1. Servlet规范介绍

  处理请求和发送响应的过程是由Servlet完成的,在Servlet规范中,指定http服务器调用动态资源文件规则;指定http服务器管理动态资源文件示例对象规则。

 

2. tomcat和Servlet的关系

  Tomcat是Web应用服务器,是一个Servlet/JSP容器。Tomcat作为Servlet容器,负责处理客户请求,把请求传送给Servlet,并将Servlet的响应传回给客户。Servlet是Web应用程序中的一个组件,扩展了Java Web服务器功能。

  在浏览器请求时,由tomcat将http请求文本接收并解析,然后封装成HttpServletRequest类型的request对象,所有Http请求头数据可以通过request对象调用对应的方法查询到。

  在对浏览器响应时,会把响应信息封装到HttpServletRespons类型的respon对象,通过设置response属性就可以控制要输出到浏览器的内容,然后将response交给tomcat,tomcat就会将其变成响应文本的格式发送给浏览器。

 

3. 一个简单的Servlet

  HttpServletResponse(响应对象)应用

  分别创建4个servlet,配置web.xml文件,在浏览器中访问对应url

  OneServlet

 

   TwoServlet

 

   ThreeServlet

 

   FourServlet

    综上HttpServletRespson对象的作用: 

   (1)通过响应对象获取标准输出流,把执行结果以二进制形式写入响应体中(write()和print()区别);

   (2)通过响应对象设置content-type,控制浏览器使用对应编译器编译响应体的二进制数据;

   (3)设置location,控制浏览器向指定服务器发送请求;

 

  HttpServletRequest(请求对象)应用

  OneServlet

 

   在TwoServlet前,先写一个html,使用超链接访问TwoServlet,这样可以使用TwoServlet来获取参数信息

  two.html

   TwoServlet

 

  在ThreeServlet前同样先写一个three.html,在three.html中分别使用get和post方法访问ThreeServlet,在ThreeServlet中分别使用doGet和doPost来获取参数信息。

   ThreeServlet

   在使用request获取请求参数时,当请求信息是英文信息时使用get和post都可以正常获取,但是当请求信息是中文信息时get也可以正常获取,post获取的请求参数信息就是乱码了。

  这是因为当浏览器以get方式发送请求时,请求参数保存在请求头,在http请求协议包到达http服务器后由tomcat解码,tomcat默认使用utf-8解码,可以解码中文;当浏览器以post方式发送请求时,请求参数保存在请求体,请求体二进制由request解码,request默认使用ISO-8859-1解码,不能解码中文

  综上HttpServletRequest对象的作用:

  (1)获取http请求协议包中的请求行信息;

  (2)获取http请求协议包中的请求参数信息;

 

4. Servlet接口实现类和生命周期

  接口实现类

 

  查看自定义OneServlet类的继承关系,可以看出自定义Servlet继承抽象类HttpServlet,HttpServlet继承抽象类GenericServlet,GenericServlet实现了Servlet接口,通过两个抽象类简化了Servlet的编写。

  而处理请求和响应其实是在HttpServlet中的Service()方法中,先判断请求方式,然后调用对应的方法执行,所以我们在编写Servlet时,可以直接重写doGet和doPost方法就可以了,不用在重写service方法了。

 

  Servlet实例创建

  (1)默认情况下,tomcat在初次发送请求后会创建servlet对象

 

   (2)如果使用<load-on-startup>1</load-on-startup>,load-on-startup大于0(默认为0,可以不写这个标签)的情况下,则会在tomcat启动时就会自动创建servlet对象

 

  Servlet的生命周期

  (1)服务器启动发送请求后,tomcat负责初始化一个Servlet对象,也就是会调用初始化方法init()方法;

  (2)创建封装Http请求的HttpServletRequest对象和Http响应的HttpServletResponse对象,然后调用Servlet的service()方法处理请求;

  (3)当服务器关闭后,销毁servlet对象,调用destroy()方法;

 

5. 欢迎资源文件

  Tomcat的欢迎资源文件规则

  (1)规则位置:tomcat安装位置/conf/web.xml

  (2)规则命令:表示顺序查找标签中的文件

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

  

  设置当前网站的默认欢迎资源文件规则

  (1)规则位置:/web/WEB-INF/web.xml

  (2)规则命令:同tomcat的欢迎资源文件配置

  当网站设置自定义默认文件定位规则后,tomcat自带定位规则将失效

 

6. 状态码

  302:浏览器获取状态码302后,不会在读取响应体内容,自动根据响应头中的location地址发起二次请求;

  405:Servlet不能对请求方式处理(请求方式是get,但是servlet中可能只定义了post方法);

  500:可以请求资源文件,也可以处理请求方式,但是请求过程中发生了异常;

  400:无法请求到资源文件;

 

7. 多个Servlet之间调用规则

  由于来自于浏览器发送的请求往往需要多个Servlet协同处理,但是浏览器一次只能访问一个Servlet,导致用户需要手动通过浏览器多次发送请求才能得到服务,增加用户访问难度,于是可以通过多个Servlet之间调度来解决这个问题,多个Servlet之间调度有两种方案。

  (1)重定向  response.sendRedirect("请求地址");

  在对OneServlet发送请求后,会把TwoServlet地址/myWeb/two写入到响应头的location属性中,tomcat会写入状态码302到状态行中,浏览器根据状态码信息会对响应头的location属性地址发送二次请求。

  使用这种方式会在浏览器和服务器之间多次往返,大量的时间消耗在往返次数上,增加等待服务时间。

 

  (2)请求转发  request.getRequestDispatcher("/资源文件名").forward(request,response);

   在OneServlet中通过当前请求对象代替浏览器向tomcat申请资源TwoServlet,使用这种方式减少了浏览器与服务器之间的往返次数。

 

8. 多个Servlet之间数据共享

  OneServlet工作完毕后,将产生的数据交给TwoServlet来使用

  Servlet规范中提供了四种数据共享方案:

  (1)ServletContext:Http服务器启动时会自动创建全局作用域对象,其他Servlet都可以从这个全局作用域对象中读取数据;

  在OneServlet中我们创建全局作用域对象,并向全局作用域对象中写入数据

 

  在TwoServlet中我们获取全局作用域对象中的数据

   ServletContext全局作用域对象可以在多个Servlet之间相互共享数据。

  在Http服务启动过程中,自动为当前网站在内存中创建一个全局作用域对象,并且在运行期间只有一个全局作用域对象,在http服务器关闭时,全局作用域对象会被销毁。

 

  (2)Cookie:当用户通过浏览器初次向网站发送请求申请OneServlet,OneServlet会在运行期间创建一个Cookie存储与当前用户相关的数据,OneServlet运行完毕后,会将Cookie信息写入到响应头交给浏览器;浏览器收到响应包后,将Cookie存储在浏览器的缓存中,一段时间后用户通过同一浏览器再次向同一网站发送申请TwoServlet时,浏览器会把之前推送的cookie信息写入到请求头发送,这样TwoServlet在运行时就可以通过读取请求头中的cookie信息与OneServlet共享数据。

  先写一个简单的页面

<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"></td>
                </tr>
            </table>
        </form>

    </center>
</body>
index.html

  用OneServlet来处理这个页面提交的请求,在Servlet中获取请求头的用户和金额参数信息,保存在用户coookie中写入响应头中,请求重新转发到下一个页面;

public class OneServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 调用请求对象获取请求头参数信息
        String userName = request.getParameter("userName");
        String money = request.getParameter("money");
        //2. 创建cookie信息
        Cookie card1 = new Cookie("userName",userName);
        Cookie card2 = new Cookie("money",money);
        //3. 设置cookie的生命周期
        card2.setMaxAge(60);  //60ms
        //4. 将cookie信息写入到响应体中
        response.addCookie(card1);
        response.addCookie(card2);
        //5. 请求转发到点餐页面
        request.getRequestDispatcher("/index_2.html").forward(request,response);
    }
}
<body>
    <center>
        <font style="color: red; font-size: 40px">点餐页面</font>
        <form action="/myWeb/two">
            食物类型:<input type="radio" name="food" value="jiaozi">饺子(30元)
            <input type="radio" name="food" value="miantiao">面条(20元)
            <input type="radio" name="food" value="gaifan">盖饭(15元)<br/>
            <input type="submit" value="消费">
        </form>

    </center>
</body>
index_2.html

  用TwoServlet来处理index_2页面发送的请求信息,在Servlet中先从请求头中获取参数信息,然后从请求头中获取缓存的cookie信息,进行处理;

public class TwoServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        int jiaozi_money = 30;
        int gaifan_money = 15;
        int miaotiao_money = 20;
        int money = 0,xiaofei = 0,balance = 0;
        String userName = null;
        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw = response.getWriter();
        Cookie newCard = null;
        //1. 获取请求头信息
        String food = request.getParameter("food");
        //2. 获取cookie信息
        Cookie[] cookies = request.getCookies();
        //3. 根据食物消费
        for(Cookie cookie : cookies){
            String key = cookie.getName();
            String value = cookie.getValue();
            if("userName".equals(key)){
                userName = value;
            }else if ("money".equals(key)){
                money = Integer.valueOf(value);
                if("jiaozi".equals(food)){
                    if(jiaozi_money > money){
                        pw.print("用户" + userName + "余额不足,请充值");
                    }else{
                        newCard = new Cookie("money",(money-jiaozi_money) + "");
                        xiaofei = jiaozi_money;
                        balance = money - jiaozi_money;
                    }
                }else if("miaotiao".equals(food)){
                    if(miaotiao_money > money){
                        pw.print("用户" + userName + "余额不足,请充值");
                    }else{
                        newCard = new Cookie("money",(money-miaotiao_money) + "");
                        xiaofei = miaotiao_money;
                        balance = money - miaotiao_money;
                    }
                }else if("gaifan".equals(food)){
                    if(gaifan_money > money){
                        pw.print("用户" + userName + "余额不足,请充值");
                    }else{
                        newCard = new Cookie("money",(money-gaifan_money) + "");
                        xiaofei = gaifan_money;
                        balance = money - gaifan_money;
                    }
                }
            }
        }
        //4. cookie信息返回用户
        response.addCookie(newCard);
        //5. 返回消费记录
        pw.print("用户" + userName + "本次消费" + xiaofei + ",余额 : " + balance);
    }
}

  a. 在index页面向OneServlet发送请求后,可以看到浏览器响应头cookie中已经保存了用户和金额的信息

 

  b. 在页面2中可以发送请求后可以直接从请求头中获取浏览器缓存的cookie信息,进行数据共享

 

 

   默认情况下cookies信息只保存在浏览器中,因此只要浏览器关闭cookies信息就会销毁,也可以手动设置cookies在硬盘上的存活时间,使用cookie.setMaxAge(时间)。

 

  (3)HttpSession:如果两个Servlet来自于同一个网站,并且为同一用户/浏览器服务,可以使用HttpSession对象进行数据共享;

  先写一个简单的html页面

<body>
    <table border="2" align="center">
        <tr>
            <td>商品名称</td>
            <td>商品单价</td>
            <td>供货商</td>
            <td>加入购物车</td>
        </tr>
        <tr>
            <td>华为笔记本</td>
            <td>7000</td>
            <td>华为</td>
            <td><a href="/myWeb/one?goodsName=华为笔记本">加入购物车</a></td>
        </tr>
        <tr>
            <td>苹果</td>
            <td>10</td>
            <td>西安</td>
            <td><a href="/myWeb/one?goodsName=苹果">加入购物车</a></td>
        </tr>
        <tr>
            <td>衣服</td>
            <td>1000</td>
            <td>上海</td>
            <td><a href="/myWeb/one?goodsName=衣服">加入购物车</a></td>
        </tr>
        <tr align="center">
            <td colspan="4"><a href="/myWeb/two">查看购物车</a></td>
        </tr>
    </table>
</body>
View Code

  用OneServlet来处理每次加入购物车的请求,在Servlet中先获取session,然后将数据保存在session中

public class OneServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 用请求参数获取参数信息
        String goodsName = request.getParameter("goodsName");
        //2. 用请求对象获取session
        HttpSession session = request.getSession();
        //3. 加入session
        Integer goodsNum = (Integer) session.getAttribute(goodsName);  //先获取商品的数量
        if(goodsNum == null){
            session.setAttribute(goodsName,1);
        }else {
            session.setAttribute(goodsName,goodsNum + 1);
        }
    }
}

  在TwoServlet中可以从session中获取数据

public class TwoServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1. 通过请求对象获取session
        HttpSession session = request.getSession();
        //2. 读取session中的key
        Enumeration goodsNames = session.getAttributeNames();    //返回一个枚举类型
        while (goodsNames.hasMoreElements()){
            String goodsName = (String)goodsNames.nextElement();
            int num = (int)session.getAttribute(goodsName);
            System.out.println("商品名:" + goodsName + " 商品数量:" + num);
        }
    }
}

  HttpSession销毁时机:

  由于用户与HttpSession关联使用的cookie只能保存在浏览器缓存中,因此浏览器关闭时,用户与他的session也会切断;由于tomcat无法检查浏览器的关闭,因此不会导致tomcat对HttpSession的销毁,为了解决这一问题,Tomcat为HttpSession设置了空闲时间,默认30分钟,就会销毁到HttpSession。

  也可以手动设置这个空闲时间:

  在当前网站下/web/WEB-INF/web.xml

    <!--设置session的空闲时间-->
    <session-config>
        <session-timeout>5</session-timeout>  <!--设置session的空闲时间5分钟-->
    </session-config>

 

  (4)HttpServletRequest:两个Servlet之间通过请求转发方式调用,因为彼此共享请求协议包,而一个请求协议包对应一个请求对象,因此两个Servlet之间可以通过请求对象实现数据共享

  在OneServlet中设置请求对象的值,请求转发到TwoServlet

public class OneServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 把数据添加到请求对象中,作为共享数据
        req.setAttribute("key1","2021/09/14");
        //2. 请求转发到下一个Servlet
        req.getRequestDispatcher("/two").forward(req,resp);
    }
}

  在TwoServlet中可以获取到请求对象共享的值

public class TwoServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //从同一个请求作用域对象中得到共享数据
        String value = (String)req.getAttribute("key1");
        System.out.println("TwoServlet runing get value " +  value);
    }
}

 

posted on 2021-11-15 21:31  homle  阅读(47)  评论(0编辑  收藏  举报