Hello Servlet

Servlet入门

学习笔记

HelloWorld

首先在maven中加入servlet-api依赖

<dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>4.0.1</version>
    </dependency>

创建一个servlet,用来处理请求

package controller;

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

public class HelloController extends HttpServlet{
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       	// 通过输入流向响应体中写入数据
        response.getWriter().println("helloworld");
    }
}

配置web.xml文件,将路径请求转向servlet类进行处理

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>HelloController</servlet-name>
    <servlet-class>controller.HelloController</servlet-class>
  </servlet>

    <!-- 当接收到/hello请求时,转向HelloController类 -->
  <servlet-mapping>
    <servlet-name>HelloController</servlet-name>
    <url-pattern>/hello</url-pattern>
  </servlet-mapping>

</web-app>

入门

Servlet生命周期

1、网站中所有servlet接口实现类的对象,只能由Http服务器负责创建

2、默认情况,Http服务器接收到对于某个servlet接口实现类请求时,才自动创建这个servlet的对象

​ 手动情况下,可以要求Http服务器在启动时,创建某个servlet实现类的对象

<servlet>
  <servlet-name>HelloController</servlet-name>
  <servlet-class>controller.HelloController</servlet-class>
  <load-on-startup>1</load-on-startup>  <!-- 在tomcat启动时,就创建对象 -->
</servlet>
...

3、在Http服务器运行期间,一个servlet实现类只能创建一个对象

4、Http服务器关闭时,servlet所有的实现类被销毁


HttpServletResponse接口

来自于servlet规范,由Http服务器提供实现类

主要功能:

1、将结果以二进制形式写入到【响应体】

2、设置相应头中【content-type】属性值,从而控制浏览器使用

3、设置相应头中【location】属性,将一个请求地址赋值给location,从而控制浏览器向指定服务器发送请求

通过getWriter()可以获取到标准输入流,可以通过这个输入流将结果写入到响应体中

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
    PrintWriter out = response.getWriter();
}

将结果写入到响应体由两个主要的方法:

out.writer():将结果以ascii的写入响应体

out.print():将原始结果写入到相应体

PrintWriter out = response.getWriter();
out.print(97);  // 97
out.write(97);  // a

content-type

浏览器接收到响应包之后,根据响应头中的content-type属性,来采用对于编译器对响应体中的二进制内容进行编译处理

默认情况下content-type="text",即接收到的二进制内容会被当做普通文本处理

使用setContentType()方法,设置浏览器解析二进制文件的方式

PrintWriter out = response.getWriter();
response.setContentType("text/html");
String result = "<p style='color:red'>hello world</p>";
out.print(result);

在解析数据时,浏览器会默认使用ISO-8859-1解析解析,使用,当传输中文字符串时,会出现乱码

当需要解析中文时,需要将字符集设置为utf-8

response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String result = "<p style='color:red'>你好,世界</p>";
out.print(result);

或者使用简写的方式,在setContentType时就指定解析的字符集

response.setContentType("text/html;charset=utf-8");

重定向

返回的不是简单的字符串,而是一个字符串链接

可以通过设置响应头的方式来进行网页的跳转

使用sendRedirect()将字符串链接写入到像响应头的location属性中

String result = "https://www.bilibili.com";
response.sendRedirect(result);

浏览器接收到请求【/hello】之后,会自动跳转到result指向的地址


HttpServletRequest接口

HttpServletRequest是servlet规范中的接口,由HTTP服务器提供实现类

HttpServletRequest接口负责在doGet / doPost方法运行时读取Http请求协议包中的信息

主要作用:

1、可以读取Http请求协议包中【请求行】的信息

2、可以读取保存在Http请求协议包中【请求头】或【请求体】中的请求参数

3、可以代替浏览器向Http服务器申请资源文件调用

获取url和uri

uri:资源精准定位地址,【/项目名/资源名】

// http://localhost:8080/hello
String requestUrl = request.getRequestURL().toString();
// /hello
String requestURI = request.getRequestURI();

获取请求参数

1、获取请求头中的参数

一个测试用的html

<html>
    <head>
        <meta charset="UTF-8">
    </head>
    <body>
        <!-- 直接写uri -->
        <a href="/hello?name=Wsd&age=21">测试</a>
    </body>
</html>

通过request获取到请求参数

通过指定的参数名称获取请求参数值

// 通过指定的参数名获取参数的值
String name = request.getParameter("name");
String age = request.getParameter("age");

获取全部的请求参数

// 获取全部请求参数,以map形式返回
Map parameterMap = request.getParameterMap();
parameterMap.forEach((key, value)-> System.out.println(key + " " + value));

2、获取请求体中的参数

<%@ page language="java" contentType="text/html;charset=utf-8" %>
<html>
    <body>
        <!-- POST方式:参数写在请求体中 -->
        <form action="/hello" method="post">
            <input type="text" name="name" value="Wsd" >
            <input type="text" name="age" value="21" >
            <input type="submit" value="提交post请求">
        </form>
    </body>
</html>

post请求参数的获取方式和get请求参数获取方法相同

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    response.setContentType("text/html;charset=utf-8");
    String name = request.getParameter("name");
    String age = request.getParameter("age");
    response.getWriter().println(name + ", " + age);
}

参数乱码问题

post请求携带的请求参数乱码

以get方式发送请求,请求参数保存在【请求头】中,在Http请求协议包到达Http服务器之后,首先进行解码【由tomcat进行解码】,tomcat9.x默认使用UTF-8字符集进行解码

以post方式发送请求,请求参数保存在【请求体】中,在Http请求协议包到达Http服务器之后,由请求对象request对二进制内容进行解码,request对象默认使用ISO-8859-1进行解码

解决方法:

doPost()中首先设置request对象解码的字符集

request.setCharacterEncoding("utf-8");

request和response生命周期

1、在Http服务器接收到浏览器发送的【请求协议包】之后,自动为当前【请求协议包】生成一个【请求对象】和【相应对象】

2、在Http服务器调用doGet() / doPost()方法时,负责将【请求对象】和【相应对象】作为实参传递到方法

3、在Http服务器推送【相应协议包】之前,负责将【请求对象】和【相应对象】进行销毁

【请求对象】和【相应对象】生命周期贯穿一次请求的处理过程中

【请求对象】和【相应对象】xinag

欢迎资源文件

默认的欢迎文件:在tomcat配置文件web.xml中

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

如果不存在欢迎文件,则返回404状态码

在网站中可以对欢迎文件进行设置

在网站的web.xml文件中

...
<welcome-file-list>
  <welcome-file>login.xml</welcome-file>
</welcome-file-list>

欢迎文件也可以是servlet

...
<welcome-file-list>
  <welcome-file>/user/add</welcome-file>  <!-- 最前面不需要添加/ -->
</welcome-file-list>

Http状态码

Http服务器推送响应包之前,根据请求处理情况,将Http状态码写入到响应包的状态行上

状态码由 100 - 599:组成

状态码 描述
100 通知浏览器,本次返回的资源文件不是一个完整的资源文件,需要在浏览器接收到响应包后,继续向Http服务器索要依赖的其他资源文件(百度请求)
200 通知浏览器,本次返回的是一个完整的资源文件
302 通知浏览器,本次返回的不是一个资源文件,而是一个资源文件的地址,需要浏览器根据这个地址自动发起请求索要资源文件(response.sendRedirect()location
404 通知浏览器,在服务端没有定位到被访问的资源文件
405 通知浏览器,在服务端已经定位到被访问的资源文件,但是servlet无法处理请求
500 通知浏览器,在服务端已经到资源文件,这个servlet可以进行处理,但是在处理期间,由于java异常导致处理失败

多Servlet调度规则

完成一项任务,往往需要服务端的的多个servlet参与,但是浏览器一次只能访问一个servlet,导致用户需要发送多个请求才能得到服务。

无论请求设计多少个servlet,用户只需要手动通过浏览器发送一个请求即可

多个servlet之间调度规则

1、重定向

2、请求转发


重定向

一个servlet工作完成后,将下一个servlet地址写入到响应头location中,交给浏览器

浏览器读接收到响应包之后,会读取到302状态码,会自动根据响应头中location中的地址发送第二次请求

OneServlet

...
System.out.println("第一个servlet");
response.sendRedirect("/tow");  // 下一次请求的url

TwoServlet

...
System.out.println("第二个servlet");

注意:可以向当前网站中的资源进行跳转,也可以向其他网站的资源进行跳转,重定向通过get方式发送请求

1、向当前网站资源进行跳转

sendRedirect("/网站名/资源文件名");

2、向其他网站资源文件

sendRedirect("http://ip地址:端口号/网站名/资源名");

缺点:重定向需要在浏览器于服务器之间进行多次往返,时间大量浪费在往返次数上,增加了等待时间


请求转发

一个servlet工作完成后,通过当前的请求对象代替浏览器向tomcat发送请求,申请调用下一个servlet,tomcat接收到请求后,自动调用下一个servlet完成任务

OneServlet

...
// 通过当前请求对象生成RequestDispatcher对象
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/tow");
// 将RequestDispatcher对象发送给tomcat
requestDispatcher.forward(request, response);

TwoServlet

...
System.out.println("第二个servlet");

特点:

1、请求转发过程中,只发送一次请求

2、请求转发过程中,请求发送方式和浏览器发送方式相同

3、servlet共享一个servlet

Servlet数据共享

一个servlet工作完成后,将产生的数据交给下一个servlet使用

servlet规范提供四种数据共享方案:

1、ServletContext

2、Cookie

3、HttpSession

4、HttpServletRequest

ServletContext[^全局作用域对象]

由tomcat负责提供接口实现类

每个网站都存在一个全局作用域对象,如果两个ServletContext来自于同一个网站,那么它们之间可以通过ServletContext实例实现数据共享


生命周期

1、在Http服务器启动时,自动为当前网站创建一个全局作用域对象

2、在Http服务器运行期间,全局作用域对象一直处于存活状态

3、在Http服务器准备关闭时,负责将全局作用域对象销毁

【全局作用域对象贯穿于网站的整个运行期间】

OneServlet

...
// 获取全局作用域对象
ServletContext servletContext = request.getServletContext();
// 将数据写入到全局作用域
servletContext.setAttribute("key", "oneServlet写入的内容");
response.getWriter().println("写入成功");

TwoServlet

...
// 获取全局作用域对象
ServletContext servletContext = request.getServletContext();
// 根据key获取value
String key = (String)servletContext.getAttribute("key");
response.getWriter().println(key);

cookie是servlet规范中的一个规范类,存在于tomcat提供的servlet-api中

如果两个servlet来自于同一个网站,并且为同一个浏览器 / 用户提供服务,此时可以借助cookie对象进行数据共享

用户通过浏览器第一次向网站发送请求时,由相应的servlet在运行期间创建一个cookie,存储于当前用户相关的数据,servlet工作完成后,将cookie写入到响应头交换给当前浏览器。浏览器接收到响应包之后,将cookie存储在浏览器缓存中

一段时间后,用户通过同一浏览器再次向网站发送请求时,浏览器将前面接收到的cookie写入到请求头中,发送到servlet,这样,其他的servlet就可以读取请求头中的cookie信息完成和其他servlet进行数据共享

例子:

模拟办卡消费

餐馆持卡消费,订餐时需持卡,没有卡信息时,会自动跳转到会员卡办理界面,有卡时,则进行消费

订餐界面

<form action="/buy" method="get">
    饺子<input type="checkbox" name="food" value="30"> <br>
    汤圆<input type="checkbox" name="food" value="20"> <br>
    炒饭<input type="checkbox" name="food" value="15"> <br>
    <input type="submit" value="购买" />
</form>

办卡界面

<form action="/register" method="get">
    持卡人姓名:<input type="text" name="customerName"> <br>
    冲卡金额  :<input type="text" name="customerMoney"> <br>
    <input type="submit" value="确认办卡">
</form>

订餐servlet

...
public class BuyServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        Cookie[] cookies = request.getCookies();
        String customerName = null, customerMoney = null;
        Boolean isOk = false;
        
		/* 获取到所有的cookie的名称,判断用户是否含有用户信息 */
        for (Cookie cookie : cookies) {
            if ("customerName".equals(cookie.getName())) {
                customerName = cookie.getValue();
                isOk = true;
            }
            if ("customerMoney".equals(cookie.getName())) {
                customerMoney = cookie.getValue();
            }
        }

        /* 查到用户信息 */
        if(isOk) {
            Integer money = Integer.parseInt(customerMoney);
            Integer costMoney = 0;
            String[] costs = request.getParameterValues("food");
            for (String cost : costs) {
                costMoney += Integer.parseInt(cost);
            }

            response.setContentType("text/html;charset=utf-8");
            StringBuilder sb = new StringBuilder();
            sb.append(customerName);
            sb.append("花费了");
            sb.append(costMoney);
            sb.append("元,还剩下");
            sb.append(money - costMoney);
            sb.append("元");

            response.setContentType("text/html;charset=utf-8");
            response.getWriter().print(sb.toString());
        } else {  // 用户为办卡
            response.sendRedirect("/register.jsp");
        }
    }
}

办卡servlet

...
public class RegisterServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // 获取到名称和充值金格
        String customerName = request.getParameter("customerName");
        String customerMoney = request.getParameter("customerMoney");

        // 创建Cookie并将cookie添加到相应包中
        Cookie name = new Cookie("customerName", "Wsd");
        Cookie money = new Cookie("customerMoney", "1000");

        response.addCookie(name);
        response.addCookie(money);

        StringBuilder sb = new StringBuilder();
        sb.append("办卡成功");
        sb.append("<br><br>");
        sb.append("持卡人:");
        sb.append(name);
        sb.append("<br>余额:");
        sb.append(money);

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(sb.toString());
    }
}

生命周期

默认情况下,cookie对象保存在浏览器缓存中,当浏览器关闭时,cookie对象就被销毁

可以手动设置cookie保存到硬盘中,同时需要指定cookie存活的时间,当服务器和浏览器关闭时,也不会销毁cookie对象,只有当达到存活时间时,才会销毁cookie

Cookie cookie = new Cookie("username", "Wsd");
cookie.setMaxAge(60)  // 设置cookie存活时间,单位s

HttpSession[^会话作用域]

来自servlet中的一个接口,相关实现类由Http服务器进行提供

如果两个servlet来自于同一个网站,并且为同一个浏览器 / 用户提供服务,此时可以借助cookie对象进行数据共享

HttpSession和Cookie的区别

区别 说明
存储位置 Cookie存放在客户端缓存中,HttpSession存放在服务端内存中
数据类型 Cookie存储数据类型只能是String,HttpSession存储数据类型是Object
数据数量 Cookie对象只能存储一个键值对,HttpSession可以存储任意数量共享数据

OneServlet

HttpSession session = request.getSession();
session.setAttribute("key", "value");

TwoServlet

HttpSession session = request.getSession();
session.getAttribute("key");

例子

商品购物车

购物界面

查看购物车

1、购物界面

<table border="2px" style="margin:auto;text-align:center">
    <tr>
        <th>商品名称</th>
        <th>商品单价</th>
        <th>加入购物车</th>
    </tr>
    <tr>
        <th>香蕉</th>
        <th>20</th>
        <th><a href="/one?food=香蕉&cost=20">加入购物车</a></th>
    </tr>
    <tr>
        <th>苹果</th>
        <th>18</th>
        <th><a href="/one?food=苹果&cost=18">加入购物车</a></th>
    </tr>
    <tr>
        <th>栗子</th>
        <th>37</th>
        <th><a href="/one?food=栗子&cost=37">加入购物车</a></th>
    </tr>
    <tr>
        <td colspan="3"><a href="/two">查看购物车</a></td>
    </tr>
</table>

2、将商品加入到session的servlet

...
public class AddServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        HttpSession session = request.getSession();

        String food = request.getParameter("food");
        String cost = request.getParameter("cost");

        session.setAttribute(food, cost);

        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println("<p style='text-align:center;color:red'>加入成功!</p>");

    }
}

购物车展示servlet

public class ShowServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        HttpSession session = request.getSession();
        StringBuilder sb = new StringBuilder();
        Integer sum = 0;

        Enumeration<String> attributeNames = session.getAttributeNames();

        sb.append("<div style='color:red;text-align:center'>");
        while (attributeNames.hasMoreElements()) {
            String food = attributeNames.nextElement();
            sb.append(food);

            sb.append("&nbsp;");
            sb.append("&nbsp;");
            sb.append("&nbsp;");
            sb.append("&nbsp;");

            String cost = (String)session.getAttribute(food);
            sb.append(cost);
            sum += Integer.parseInt(cost);

            sb.append("<br>");
        }

        sb.append("共" + sum + "元");
        sb.append("</div>");

        response.setContentType("text/html;charset=utf-8");

        response.getWriter().println(sb.toString());
    }
}

HttpSession如何区别不同的用户?

浏览器创建Session对象时,会生成一个JSESSIONID,并将其放入cookie对象中,通过相应包推送到浏览器,当再次通过这个浏览器发送请求时,Http服务器通过解析请求头中的JSESSIONID确认用户是否已经有了Session对象,以及该Session对象属于哪一个用户


getSession()getSession(false)

1、getSession():如果当前用户在服务端已经拥有了Session对象,则返回该对象

如果没有Session对象,则新建一个Session对象进行返回

2、getSession(false):如果当前用户在服务端已经拥有了Session对象,则返回该对象

如果没有Session对象,则返回null

HttpSession生命周期

1、用户与HttpSession关联时使用的Cookie只能存放在浏览器缓存中

2、在浏览器关闭时,Cookie对象被销毁,HttpSession对象与用户联系被切断,由于Http服务器无法检测浏览器是否被关闭,所以HttpSession并不会在浏览器关闭时销毁

3、tomcat会为每一个HttpSession对象设置一个空闲时间,默认为30分钟,当时间达到时,tomcat才会销毁HttpSession

为了保存节省资源,可以手动设置tomcat销毁HttpSession的时间

<session-config>
  <session-timeout>5</session-timeout>   <!-- 单位分钟 -->
</session-config>

HttpServletRequest

在同一个网站中,如果两个servlet之间通过请求转发方式进行调用,彼此之间共享同一个请求相应包。而同一个请求响应包只对应一个请求对象,因此,servlet之间共享同一个请求对象,此时,可以利用请求对象实现servlet之间的数据共享

OneServlet

request.setAttribute("username", "Wsd");
request.getRequestDispatcher("/two").forward(request, response);

TwoServlet

String username = (String)request.getParameter("username");
System.out.println("hello " + username);

监听器

servlet规范下的接口,需要由开发人员提供实现类

监听器用于监控作用域对象生命周期变化以及作用域对象共享数据变化

作用域对象:在服务端内存中,可以在某些条件下为两个servlet之间提供数据共享的对象

对象 说明
ServletContext 全局作用域对象
HttpSession 会话作用域对象
HttpServletRequest 请求作用域对象

监听器开发规范:

1、根据需求,选择对应的监听器接口

2、从写监听器接口声明监听事件处理方法

3、在web.xml中注册监听器接口实现类

例子:

ServletContextListener

public class OneListener implements ServletContextListener {
    @Override
    /* 全局作用域对象初始化时调用 */
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("网站启动时,全局作用域对象创建");
    }

    @Override
    /* 全局作用域对象被销毁时调用 */
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("网站关闭,全局作用域对象销毁");
    }
}
<listener>
  <listener-class>listener.OneListener</listener-class>
</listener>

ServletContextAttributeListener

public class TwoServlet implements ServletContextAttributeListener {
    @Override
    /* 全局作用域对象增加数据时调用 */
    public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println(servletContextAttributeEvent.getName() + "成功加入到全局作用域");
    }

    @Override
    /* 全局作用域对象删除数据时调用 */
    public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println(servletContextAttributeEvent.getName() + "数据被删除了");
    }

    @Override
    /* 全局作用域对象更新数据时调用 */
    public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
        System.out.println(servletContextAttributeEvent.getName() + "数据被覆盖了");
    }
}
<listener>
  <listener-class>listener.TwoListener</listener-class>
</listener>

数据库操作大部分时间都用在Connection的创建的销毁

可以通过监听器,在tomcat启动时创建一批Connection以供使用,在tomcat关闭时,在将其释放

...

public class OneListener implements ServletContextListener {
    @Override
    /* 全局作用域对象初始化时调用 */
    /* 在tomcat启动时,预先创建10个Connection,在添加时 */
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        Map map = new HashMap();
        for (int i = 0; i < 20; i++) {
            Connection conn = null;  // 创建Connection
            // 说明Connection对象是否可用
            map.put(conn, true);
        }
        // 将map对象放入到全局作用域对象中
        servletContextEvent.getServletContext().setAttribute("connections", map);
    }
    @Override
    /* 全局作用域对象被销毁时调用 */
    /* tomcat关闭时,将Connection对象进行销毁 */
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        Map map = (HashMap) servletContextEvent.getServletContext().getAttribute("connections");
        Iterator iterator = map.keySet().iterator();
        // 依次关闭Connection
        while (iterator.hasNext()) {
            Connection conn = (Connection) iterator.next();
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

使用重载的getConnection()方法获取预先创建的Connection

public Connection getConnection (HttpServletRequest request) {
    Connection conn = null;
    boolean flag = false;
    
    // 从全局作用域对象中获取到map
	ServletContext application = request.getServletContext();
    Map map = (Map)application.getAttribute("connections");
    
    // 遍历
    Iterator iterator = map.keySet().iterator();
    while (iterator.hasNext()) {
        conn = (Connection)iterator.next();
        flag = (boolean)map.get(conn);
        if (flag) {
            map.put(conn, false);
            break;
        }
    }
    return flag;
}

拦截器

servlet规范接口,由开发人员提供实现类

具体作用:拦截Http服务器

1、检测当前请求合法性

2、对当前请求做增强操作

监听器开发规范

1、创建java类实现Filter接口

2、从写doFilter方法

3、通过web.xml将拦截器注册到tomcat

<url-pattern>拦截地址</url-pattern>

拦截地址书写方式

1、调用某一个资源文件之前,使用拦截器进行拦截

<url-pattern>/html/login.html</url-pattern>

2、调用某文件下所有的资源文件前,使用拦截器进行拦截

<url-pattern>/文件夹/*</url-pattern>

3、调用任意文件夹下的某种类型的文件之前,使用拦截器进行拦截

<url-pattern>*.jpeg</url-pattern>

4、调用网站中任意文件时,使用拦截器进行拦截

<url-pattern>/*</url-pattern>

例子

使用拦截器,限制网站使用者的年龄

html

<form action="/one" style="text-align: center;margin: auto;color: red">
    输入您的年龄:<input type="text" name="age"> <br>
    <input type="submit" value="点击看片">
</form>

拦截器

...
public class OneFilter implements Filter {
    @Override
    /* 访问着的年龄必须大于18 */
    public void doFilter(ServletRequest servletRequest, 
                         ServletResponse servletResponse, 
                         FilterChain filterChain) throws IOException, ServletException {
        Integer age = Integer.parseInt(servletRequest.getParameter("age"));
        if (age > 18) {
            // 合法的请求,使用将请求对象和相应对象交还给tomcat
            filterChain.doFilter(servletRequest, servletResponse);
        } else {
            // 不合法请求
            servletResponse.setContentType("text/html;charset=utf-8");
            servletResponse.getWriter().println("未满18岁禁止进入");
        }
    }
}

使用过滤器处理中文乱码问题

使用post方式发送请求,请求参数在请求体中,由请求参数对其进行解码,请求参数默认采用ISO-8859-1编码

使用拦截器拦截所有的请求,将解码字符集设置为utf-8

public class OneFilter implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletResponse.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest, servletResponse);
    }
}
<filter-mapping>
    <filter-name>OneFilter</filter-name>
    <url-pattern>/*</url-pattern>  <!-- 拦截所有的请求 -->
</filter-mapping>

使用拦截器防止恶意登录(直接通过地址栏访问资源文件)

令牌方式,每一个合法的用户都有一个令牌(Session),在注册界面,使用getSession()方式给合法的用户分配一个Session对象,在访问网站的其他资源时,都检查该用户是否持有Session个体Session(false),有Session对象则为合法用户,没有则为非法用户

public class OneFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpSession session = request.getSession(false);

        if (session == null) {
            // 用户非法
            request.getRequestDispatcher("/login_error.jsp").forward(servletRequest, servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
}
posted @ 2021-02-10 08:03  INEEDSSD  阅读(129)  评论(0编辑  收藏  举报