Servlet

1.资源欢迎文件

概念:

访问网页默认弹出的资源叫作欢迎资源文件

默认欢迎资源文件:

位置:
Tomcat9/conf/web.xml—>文件末尾
根据下述源码可知,当未设置具体访问资源时,浏览器会默认访问
index.html,index.htm或者index.jsp
文件。

或者另外两个文件。

	<welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

自行设置欢迎资源文件:

位置:
网站/web/WEB-INF/web.xml
自行设置之后Tomcat自带的默认欢迎文件将失效。
语法规范:

<!----资源名可以是动态资源文件,也可以是静态资源文件---->
<welcome-file-list>
	<welcome-file>(资源名)(login.html)</welcome-file>
</welcome-file-list>

2.状态码

定义:
由三位数字组成的一个符号(100~599);
位置:
Http服务器推送【响应包】前,根据处理结果将状态码写入【响应包】的【状态行】上。
作用:
向浏览器通知处理结果或向浏览器解释不能提供服务的原因。
典例:
①100:通知资源文件不完整,需要继续索要缺失部分;
②200:通知本次资源文件返回完整无缺失
③302:通知本次返回的不是资源内部而是资源的地址,需浏览器根据返回的地址继续索要资源文件;
④404:通知B端S端没有定位到被访问文件
⑤405:通知B端S端定位到被访问文件但无法访问(访问方式错误)
⑥500:通知B端S端定位到被访问文件,也存在访问方法,但出现了Java语句的异常

3.多个Servlet的调用规则:

(1).重定向的解决方案:

原理:

用户第一次手动访问OneServlet,访问结束时,将TwoServlet地址写入响应头的【location】中,浏览器接收到响应包时,读取到302状态,根据【location】发起第二次请求,访问TwoServlet。

特点:

①浏览器至少发送两条请求;
②该方案的请求方式一定是【Get】;

优缺点:

优点:
该方案能调用当前网站资源或站外的其他网站资源;
缺点:
增加了用户等待时间,效率较低。

实现命令:

//根据相应对象设置location属性
response.sendRedirect("(网站名)");
//网站名格式应为/网站名/资源名

(2).请求转发解决方法:

原理:

用户第一次手动访问OneServlet,放完结束后,通过当前请求对象代替浏览器向Tomcat发送请求,申请调用TwoServlet,完成任务即可。

特点:

①浏览器仅仅发送了一次请求(推送了一个请求包)
②请求方式只取决于第一次请求方式保持不变(因为只有一个请求包)

优缺点:

优点:
无论涉及到多少Servlet,仅发出一次请求,减少浏览器与服务器的交互次数。
缺点:
只能调用当前网站下的资源,无法站外调用。

实现命令:

//通过【请求对象】拿到资源文件申请报告对象
//资源文件名格式写为"/jsp”或“/html"格式
RequestDispatcher report = request.getRequestDispatcher("(资源文件名)");
//将报告对象发送给Tomcat服务器
report.forward((当前请求对象),(当前响应对象));

4.多个Servlet的数据共享

(1).ServletContext接口(全文):

概述:

①存在于Servlet规范中,Tomcat中存在【servlet-api.jar】包下;
②如果两个Servlet来自同一个网络,则可通过网站的【ServletContext实例对象】实现数据共享。
③开发人员习惯将其称为【全局作用域对象】。

特点:

①每个网站都存在一个全局作用域对象(类似于Map采用键值对储存)
②当前网站所有Servlet都可从中获取到相关数据。

生命周期:

http服务器启动时,自动创建一个【全局作用域对象】;
http服务器运行时,仅有一个【全局作用域对象】存在且一直存活;
http服务器关闭时,自动销毁【全局作用域对象】。
核心:【全局作用域对象】周期贯穿整个服务器运行期间。

实现命令:
在OneServlet中:

//通过请求对象向Tomcat服务器索要【全局作用域对象】
ServletContext application = request.getServletContext();
//将共享数据添加到【全局作用域对象中】
application.setAttribute("key1",());

在TwoServlet中:

//通过请求对象向Tomcat服务器索要【全局作用域对象】
ServletContext application = request.getServletContext();
//从【全局作用域对象】中获取key1所对应的数据
datatype data = application.getAttribute("key1");

(2).Cookie类:

概述:

①存在于Servlet的工具类中,Tomcat中存在的【servlet-api.jar】包下;
②如果两个Servlet来自同一个网站,且为同一个浏览器提供服务,则可通过【Cookie】对象进行数据共享;
③存放私人数据,为提高服务质量。

原理:

用户通过浏览器向网站发送请求申请OneServlet,OneServlet在运行期间会创建一个【Cookie】对象存当前用户的相关数据,工作完毕后,将Cookie写入响应头交还给浏览器。收到响应包后,将Cookie存入缓存,用户通过同一浏览器再次向Two发送请求时,浏览器将Cookie推给请求头发送过去。(类比会员卡机制)

特点:

①Cookie相当于一个Map存储;
②一个Cookie只能存储一个键值对;
③键值对都只能是String类型,key不能是中文。

实现命令:
OneServlet中:

//创建一个Cookie对象,存放共享数据
Cookie cookie = new Cookie("key1","abc");
//将Cookie对象交给响应头,交给浏览器
response.addCookie(cookie);

TwoServlet中:

//调用请求对象从请求头拿到浏览器的Cookie
Cookie[] cookieArray = request.getCookies();
//遍历数据拿到每一个Key和value
for(Cookie c:cookieArray){
	String key = c.getName();
	String value = c.getValue();
	...(KeyValue做处理即可)...
}

(3).补充请求包和响应包:

请求包:

【请求行】组成规则:方法 /url HTTP/版本号 例:GET /xinwen/2018-07/17/content_5307156.htm HTTP/1.1

【请求头】包含了客户端的环境,例:(地址http://tools.jb51.net/table/http_header)

【请求体】要发送的数据(一般post方式会使用);例:userName=123&password=123&returnUrl=/

响应包:

【响应行】规则:HTTP/版本号 响应码(状态码) 例:HTTP/1.1 200 OK

【响应头】服务器端的信息

【响应体】 显示在浏览器的内容(与响应头配合,显示出来)

(4).Cookie的项目实例(点餐系统):

a.书写欢迎页面index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>订餐系统欢迎页面</title>
</head>
<body>
<center>
    <font style="color:red;font-size:40px">新会员申请开卡</font>
    <form action="/myWeb/one">
        <table border="2">
            <tr>
                <td>用户名</td>
                <td><input type="text" name="userName"/></td>
            </tr>
            <tr>
                <td>预存金额</td>
                <td><input type="text" name="money"/></td>
            </tr>
            <tr>
                <td><input type="submit" value="申请开卡" /></td>
                <td><input type="reset" value="重置"/></td>
            </tr>
        </table>
    </form>
</center>
</body>
</html>
b.创建OneServlet用来识别会员卡,创建TwoServlet用来划卡消费
c.配置web.xml文件(web.xml文件)
<servlet>
        <servlet-name>OneServlet</servlet-name>
        <servlet-class>OneServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OneServlet</servlet-name>
        <url-pattern>/one</url-pattern>
    </servlet-mapping>
    
    <servlet>
        <servlet-name>TwoServlet</servlet-name>
        <servlet-class>TwoServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>TwoServlet</servlet-name>
        <url-pattern>/two</url-pattern>
    </servlet-mapping>
d.书写点餐界面order.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<center>
    <font style="color:red;font-size:40px">点餐页面</font>
    <form action="/myWeb/two">
        食物类型:<input type="checkbox" name="food" value="dumpling"/>饺子(30RMB)
        <input type="checkbox" name="food" value="noodles"/>面条(20RMB)
        <input type="checkbox" name="food" value="rice"/>盖浇饭(15RMB)<br/>
        <input type="submit" value="划卡消费">
    </form>
</center>
</body>
</html>
e.补充完整OneServlet与TwoServlet

OneServlet:

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class OneServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //初始化变量区
        String userName,money;
        //通过【请求对象】获取到用户的参数信息
        userName = request.getParameter("userName");
        money = request.getParameter("money");
        //创建两个Cookie对象
        Cookie cookie1 = new Cookie("userName",userName);
        Cookie cookie2 = new Cookie("money",money);
        //将Cookie对象存入响应体中
        response.addCookie(cookie1);
        response.addCookie(cookie2);
        //响应体将点餐页面发送给浏览器(请求转发)
        response.sendRedirect("/myWeb/order.html");
    }
}

TwoServlet:

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class TwoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //变量初始化区
        int dumpling_money = 30;
        int noodles_money = 20;
        int rice_money = 15;
        int cost = 0;
        int money = 0;
        int balance = 0;
        String userName;
        String[] food = new String[3];
        Cookie[] cookieArray;
        PrintWriter out = null;
        Cookie newCard = null;
        //①读取请求头参数,得到用户点餐类型

        food = request.getParameterValues("food");
        for (String s:food) {
            if ("dumpling".equals(s)) {
                cost += dumpling_money;
            } else if ("noodles".equals(s)) {
                cost += noodles_money;
            } else if ("rice".equals(s)) {
                cost += rice_money;
            }
        }
        //System.out.println(cost);
        //②读取请求头中的Cookie,得到用户会员卡
        cookieArray = request.getCookies();
        //③根据食物类型进行消费处理
        for (Cookie data : cookieArray) {
            String key = data.getName();
            //拿到用户名和预存金额
            String value = data.getValue();

            if ("userName".equals(key)){
                userName = value;
            }else if ("money".equals(key)){
                money = Integer.valueOf(value);
            }
        }
        //System.out.println(money);
        response.setContentType("text/html;charset=utf-8");
        out = response.getWriter();
        if (cost > money){
            balance = money;
            out.print("<font style='color:red;font-size:40px'>对不起,您的余额不足,请充值(●'◡'●)</font>");
        }else{
            balance = money-cost;
            out.print("<font style='color:blue;font-size:40px'>消费成功(●'◡'●),您的卡上余额剩余"+balance+"元!");
        }
        //④将Cookie交还给用户,并将消费记录写入响应体
        newCard = new Cookie("balance",balance+"");
        response.addCookie(newCard);

    }
}

f.结果演示:

登录会员卡:
在这里插入图片描述
点击申请开卡弹出点餐页面:
在这里插入图片描述
将三种食物全选,点击”划卡消费“:
在这里插入图片描述
如果开始开卡钱数不够,则消费失败:
在这里插入图片描述

g.开发过程总结与反思

本次开发过程中,进行了将案例中的单选框改为复选框,认为返回的值应可以依次存储在数组里,比如,我在三种食物处都打上勾,那么会不会将三种食物以字符串形式存入字符串数组里。原代码:

//初始化字符串数组存储食物名称
int dumpling_money = 30;
int noodles_money = 20;
int rice_money = 15;
int cost = 0;
String[] food = new String[10];
for(int i = 0;i < 3;i++){
	//从输入的复选框中拿到选项参数
	food[i] = request.getParameter("food");
	//如果拿到某种食物,则让花费变量cost加上该种食物的价格
	if("dumpling".equals(food[i])){
		cost+=dumpling_money;
	}else if("noodles".equals(food[i])){
		cost+=noodles_money;
	}else if("rice".equals(food[i])){
		cost+=rice_money;
	}
}

后来发现,这种做法仅能用于单选框情况,如果如图代码会将识别到的第一种食物重复算三次。比如三种食物全选,会得到cost最后的值为饺子价格的三倍(30x3)经过查阅资料,对多选框得到了下面这种解法:

int dumpling_money = 30;
int noodles_money = 20;
int rice_money = 15;
int cost = 0;
Stirng[] food = new String[10];
//直接通过getParameterValues方法拿到整个复选框字符串数组
food = request.getParameterValues("food");
		//再去遍历这个字符串数组,即可拿到多选的每个食物
        for (String s:food) {
            if ("dumpling".equals(s)) {
                cost += dumpling_money;
            } else if ("noodles".equals(s)) {
                cost += noodles_money;
            } else if ("rice".equals(s)) {
                cost += rice_money;
            }
        }

同理,这种代码写法如果三种食物全选时,cost最后的值为三种食物的价格总和(30+20+15),结果合理。

(5).HttpSession接口(会话):

概述:

①存在于Servlet规范中,Tomcat中存在servlet-api.jar中,Tomcat提供了实现类;
②如果两个Servlet来自于同一个网站,且为同一个浏览器提供服务,则可通过HttpSession实现类对象进行数据共享;
③开发人员习惯将其成为【会话作用域对象】。

Session和Cookie的对比:

①Cookie存在于客户端计算机内存
而Session存在于服务端计算机的内存中;
② Cookie对象仅能存储String类型数据;
而Session实现类对象可以存储任意类型
③一个Cookie对象只能存一个共享数据;
而Session实现类对象用map进行储存,可存任意数量的对象;
④Cookie相当于用户服务端的【会员卡】;
而Session相当于服务端的【私人保险柜】。

命令实现:
OneServlet中:

以下两种方法的区别:
前者:如果用户存在已有的【私人保险柜】,返回对应的【私人保险柜】
如果用户不存在【私人保险柜】,tomcat会创建一个全新的【私人保险柜】。
后者:如果用户存在已有的【私人保险柜】,返回对应的【私人保险柜】
如果用户不存在【私人保险柜】,tomcat拒绝服务,直接返回null。

//调用【请求对象】向Tomcat索要Session
HttpSession session = request.getSession();
//或者
HttpSession session = request.getSession(false);

//将数据添加到【私人保险柜】Session对象中
session.setAttribute("key1",data);

TwoServlet中:

//调用【请求对象】向Tomcat索要Session
HttpSession session = request.getSession();
//从【会话作用域对象】中获取共享数据
Object data = session.getAttribute("key1");

Session的销毁时机:

①用户与Session关联时使用的Cookie仅存在于缓存中;
②浏览器关闭时,Session与用户的联系被切断;
③Tomcat无法得知浏览器是否关闭,所以浏览器关闭时Tomcat并不会销毁Session;
④为了解决③中的问题,Tomcat设置了默认的【空闲时间】30min,到时间后自动销毁Session。
⑤也可手动设置Session实现类对象的销毁时机。

手动设置Session的销毁时机:
(在web.xml下)

<!---手动设置5分种后销毁Session实现类对象--->
<session-config>
	<session-timeout>5</session-timeout>
</session-config>

(6).HttpServletRequest接口(请求):

概述:

①两个Servlet通过【请求转发】互相调用,彼此共享一个请求协议包,此时可共享数据;
②开发人员将其对象叫作【请求作用域对象】。

命令实现:
OneServlet中:

//将数据存入【请求作用域对象】中
request.setAttribute("key1",data);
//向Tomcat申请调用TwoServlet
RequestDispatcher report = request.getRequestDispatcher("/two");
report.forward();

TwoServlet中:

//从当前【请求对象】中拿出共享数据
Object data = request.getAttribute("key1");
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐