JavaWeb开发 Servlet技术详解(四)

简介: JavaWeb开发 Servlet技术详解(四)

4.28.7 HttpSession对象的特点

  • HttpSession保存在服务端
  • HttpSession使用Key与Value结构存储数据
  • HttpSession的Key是字符串类型,Value则是Object类型
  • HttpSession存储数据大小无限制

4.28.8 HttpSession对象的创建

HttpSession对象的创建是通过request.getSession()方法来创建的。客户端浏览器在请求服务端资源时,如果在请求中没有jsessionid,getSession()方法将会为这个客户端浏览器创建一个新的HttpSession对象,并为这个HttpSession对象生成一个jsessionid,在响应中通过状态Cookie写回给客户端浏览器,如果在请求中包含了jsessionid,getSession()方法则根据这个ID返回与这个客户端浏览器对应的HttpSession对象。

getSession()方法还有一个重载方法getSession(true|false)。当参数为true时与getSession()方法作用相同。当参数为false时则只去根据jsessionid查找是否有与这个客户端浏览器对应的HttpSession,如果有则返回,如果没有jsessionid则不会创建新的HttpSession对象。

HttpSession session = req.getSession();

4.28.9 HttpSession的使用

session.setAttribute("key",value)
将数据存储到HttpSession对象中
Object value = session.getAttribute("key")
根据key获取HttpSession中的数据,返回Object
Enumeration attributeNames = session.getAttributeNames()
获取HttpSession中所有的key,返回枚举类型
session.removeAttribute("key")
根据key删除HttpSession中的数据
String id = session.getId()
根据获取当前HttpSession的SessionID,返回字符串类型
package cn.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
public class SessionServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         //创建HttpSession对象
        HttpSession session = req.getSession();
        //存放数据
        session.setAttribute("key", "Java");
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}
package cn.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
public class GetSessionData extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        //获取数据
        String key = (String) session.getAttribute("key");
        PrintWriter writer = resp.getWriter();
        writer.println(key);
        writer.flush();
        writer.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

相同浏览器中的session是共享的,不同浏览器之间的session是不共享的。当关闭浏览器的时候,状态cookie会被销毁但是存放在服务端session列表中的session是不会被销毁的。但是再次使用req.getSession创建session对象的时候得到的是一个新的session对象。

4.28.10 HttpSession的销毁方式

HttpSession的销毁方式有两种:

  • 通过web.xml文件指定超时时间
  • 通过HttpSession对象中的invalidate()方法销毁当前HttpSession对象

我们可以在web.xml文件中指定HttpSession的超时时间,当到达指定的超时时间后,容器就会销该HttpSession对象,单位为分钟。该时间对整个web项目中的所有HttpSession对象有效。时间的计算方式是根据最后一次请求时间作为起始时间。只要用户继续访问,服务器就会更新HttpSession的最后访问时间,并维护该HttpSession。用户每访问服务器一次,无论是否读写HttpSession,服务器都认为该用户的HttpSession"活跃(active)"了一次,销毁时间则会重新计算。如果有哪个客户端浏览器对应的HttpSession的失效时间已到,那么与该客户端浏览器对应的HttpSession对象就会被销毁。其他客户端浏览器对应的HttpSession对象会继续保存不会被销毁。

<session-config>
        <session-timeout>2</session-timeout>
    </session-config>
session.invalidate();

4.28.11 通过HttpSession实现客户端与服务端会话的维持

package cn.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
public class SessionServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/plain;charset=UTF-8");
         //创建HttpSession对象
        HttpSession session = req.getSession();
        boolean flag = false;
        Enumeration<String> attributeNames = session.getAttributeNames();
        while (attributeNames.hasMoreElements()) {
            String name = attributeNames.nextElement();
            if ("welcome".equals(name)) {
                flag = true;
                break;
            }
        }
        PrintWriter writer = resp.getWriter();
        if (flag){
            writer.println("欢迎再次回来");
        }else {
            writer.println("欢迎第一次访问");
            session.setAttribute("welcome",123);
        }
        writer.flush();
        writer.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

4.28.12 HttpSession生命周期

在HttpSession对象生命周期中没有固定的创建时间与销毁时间。何时创建取决于我们什么时候第一次调用了getSession()或getSession(true)的方法。HttpSession对象的销毁时间取决于超时时间的到达以及调用了invalidate()方法。如果没有超时或者没有调用invalidate()方法,那么HttpSession会一直存储。默认超时时间为30分钟(Tomcat的web.xml文件配置的时间就是默认超时时间)。

4.28.13 HttpSession对象总结

HttpSession与Cookie的区别:

  • cookie数据存放在客户的浏览器或系统的文件中,而HttpSession中的数据存放在服务器中。
  • cookie不安全,而HttpSession是安全的。
  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个域名保存cookie的数量。而HttpSession没有容量以及数量的限制。

HttpSession的使用建议

HttpSession对象是保存在服务端的,所以安全性较高。我们可以在HttpSession对象中存储数据,但是由于HttpSession对象的生命周期不固定,所以不建议存放业务数据。一般情况下我们只是存放用户登录信息。

4.29自启动Servlet

自动启动Servlet表示在Tomcat启动时就会实例化这个Servlet,他的实例化过程不依赖于请求,而是依赖容器的启动。

可以通过在web.xml中的<servlet>标签中通过<load-on-startup>1</load-on-startup>配置自启动Servlet。(详见servlet生命周期)

<load-on-startup>1</load-on-startup>中值越小的优先级越高。

<servlet>
        <servlet-name>AutoStartServlet</servlet-name>
        <servlet-class>cn.it.servlet.AutoStartServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>AutoStartServlet</servlet-name>
        <url-pattern>/auto</url-pattern>
    </servlet-mapping>
package cn.it.servlet;
import javax.servlet.ServletException;
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 AutoStartServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.println("autoStart");
        writer.flush();
        writer.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    //servlet被实例化后立即调用该方法
    @Override
    public void init() throws ServletException {
        System.out.println("servlet init");
    }
}

tomcat启动后

浏览器请求后

4.29.1 通过自启动Servlet实现配置信息的读取

修改文件下载案例,通过自启动Servlet读取配置信息

文件下载的资源不一定都是在web根目录下的img目录下面。也就是说路径不能写死。

<servlet>
        <servlet-name>fileDownServlet</servlet-name>
        <servlet-class>cn.it.servlet.FileDownServlet</servlet-class>
        <init-param>
            <param-name>path</param-name>
            <param-value>img</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>fileDownServlet</servlet-name>
        <url-pattern>/down.do</url-pattern>
    </servlet-mapping>
package cn.it.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
//文件下载
public class FileDownServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取ServletContext对象
        ServletContext servletContext = this.getServletContext();
        String path = (String) servletContext.getAttribute("path");
        //路径转换 相对路径转换为绝对路径
        String realPath = servletContext.getRealPath(path+"/哈哈.jpg");
        System.out.println(realPath);
        //读取下载文件
        File file = new File(realPath);
        //文件字节输入流
        FileInputStream fis = new FileInputStream(file);
        //文件字节缓冲流
        BufferedInputStream bis = new BufferedInputStream(fis);
        //在响应中添加文件下载的信息
        resp.addHeader("Content-Disposition", "attachment; filename="+new String(file.getName() .getBytes("utf-8"),"iso-8859-1"));
        //产生响应 文件字节缓冲输出流
        BufferedOutputStream bos = new BufferedOutputStream(resp.getOutputStream());
        int temp = 0;
        while ((temp = bis.read()) != -1) {
            bos.write(temp);
        }
        bos.flush();
        bos.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    public void init() throws ServletException {
         //获取servletConfig对象读取<servlet>配置信息
         ServletConfig servletConfig = this.getServletConfig();
         String path = servletConfig.getInitParameter("path");
         //将读取的信息放到全局容器中,因为ServletConfig只能获取当前servlet的配置文件信息
         this.getServletContext().setAttribute("path",path);
    }
}

这样只需要改动配置文件再重新启动tomcat即可。文件下载功能照样可以实现。

4.30 Servlet线程安全问题

在Servlet中使用的是多线程方式来执行service()方法处理请求,所以我们在使用Servlet时需要考虑到线程安全问题,在多线程中对于对象中的成员变量是最不安全的,所以不要在Servlet中通过成员变量的方式来存放数据,如果一定要使用成员变量存储数据,在对数据进行操作时需要使用线程同步的方式来解决线程安全问题,避免出现数据张冠李戴现象。

package cn.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
//servlet线程安全
public class ThreadSafeServlet extends HttpServlet {
    private PrintWriter writer;
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户提交的数据
        String name = req.getParameter("name");
        //响应到客户端
        writer = resp.getWriter();
        //线程休眠
        try {
            Thread.sleep(5000);
            writer.write(name);
            writer.flush();
            writer.close();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
    }
}

同时使用谷歌浏览器和edge浏览器访问时,会出现后启动的浏览器会先访问到资源就是因为两个线程共享一个成员变量。谷歌浏览器的输出对象被edge浏览器的输出对象覆盖了。

 

package cn.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
//servlet线程安全
public class ThreadSafeServlet extends HttpServlet {
    private PrintWriter writer;
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取用户提交的数据
        String name = req.getParameter("name");
        synchronized (this){
            //响应到客户端
            writer = resp.getWriter();
            //线程休眠
            try {
                Thread.sleep(5000);
                writer.write(name);
                writer.flush();
                writer.close();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
       doPost(req, resp);
    }
}

this代表的当前对象,所有调用当前的servlet中的方法的请求都会由并行变为串行。但是一般情况下不建议使用成员变量而是建议使用局部变量。

4.31 Servlet的url-pattern配置

当浏览器请求url时,服务端会根据url将请求交给能处理该请求的servlet

4.31.1 URL的匹配规则

精确匹配

精确匹配是指<url-pattern>中配置的值必须与url完全精确匹配。

<servlet-mapping>
  <servlet-name>demoServlet</servlet-name>
  <url-pattern>/demo.do</url-pattern>
</servlet-mapping>

http://localhost:8888/demo/demo.do 匹配

http://localhost:8888/demo/suibian/demo.do 不匹配

扩展名匹配

在允许使用统配符作为匹配规则,“*”表示匹配任意字符。在扩展名匹配中只要扩展名相同都会被匹配和路径无关。注意,在使用扩展名匹配时在中不能使用“/”,否则容器启动就会抛出异常。

<servlet-mapping>
  <servlet-name>demoServlet</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

http://localhost:8888/demo/abc.do 匹配

http://localhost:8888/demo/suibian/haha.do 匹配

http://localhost:8888/demo/abc 不匹配

路径匹配

根据请求路径进行匹配,在请求中只要包含该路径且该路径在contextpath的后面第一个都匹配。“*”表示任意路径以及子路径。大但是不能写成*/suibian/*

<servlet-mapping>
  <servlet-name>demoServlet</servlet-name>
  <url-pattern>/suibian/*</url-pattern>
</servlet-mapping>

http://localhost:8888/demo/suibian/haha.do 匹配

http://localhost:8888/demo/suibian/hehe/haha.do 匹配

http://localhost:8888/demo/hehe/heihei.do 不匹配

http://localhost:8888/demo/hehe/suibian/heihei.do 不匹配

任意匹配

匹配“/”。匹配所有但不包含JSP页面。

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

http://localhost:8888/demo/suibian.do 匹配

http://localhost:8888/demo/addUser.html 匹配

http://localhost:8888/demo/css/view.css 匹配

http://localhost:8888/demo/addUser.jsp 不匹配

http://localhost:8888/demo/user/addUser.jsp 不匹配

匹配所有

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

http://localhost:8888/demo/suibian.do 匹配

http://localhost:8888/demo/addUser.html 匹配

http://localhost:8888/demo/suibian/suibian.do 匹配

优先顺序

当一个url与多个Servlet的匹配规则可以匹配时,则按照 “ 精确路径 > 最长路径 > 扩展名”这样的优先级匹配到对应的Servlet。

考考你

Servlet1 映射到 /abc/*

Servlet2 映射到 /*

Servlet3 映射到 /abc

Servlet4 映射到 *.do

当请求URL为“/abc/a.html”,“/abc/* ”和“/* ”都匹配,Servlet引擎将调用Servlet1。

当请求URL为“/abc”时,“/abc/* ”和“/abc”都匹配,Servlet引擎将调用Servlet3。

当请求URL为“/abc/a.do”时,“/abc/* ”和“ *.do”都匹配,Servlet引擎将调用Servlet1。

当请求URL为“/a.do”时,“/* ”和“*.do”都匹配,Servlet引擎将调用Servlet2。

当请求URL为“/xxx/yyy/a.do”时,“/* ”和“*.do”都匹配,Servlet引擎将调用Servlet2。

4.31.2 Servlet的多URL映射方式

在web.xml文件中支持将多个URL映射到一个Servlet中,但是相同的URL不能同时映射到两个Servlet中。

方式一

<servlet-mapping>
  <servlet-name>demoServlet</servlet-name>
  <url-pattern>/suibian/*</url-pattern>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

方式二

<servlet-mapping>
  <servlet-name>demoServlet</servlet-name>
  <url-pattern>/suibian/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
  <servlet-name>demoServlet</servlet-name>
  <url-pattern>*.do</url-pattern>
</servlet-mapping>

4.32 基于注解式开发Servlet

在Servlet3.0以及之后的版本中支持注解式开发Servlet。对于Servlet的配置不在依赖于web.xml配置文件,而是使用@WebServlet注解完成Servlet的配置。

4.32.1 @WebServlet

属性名 类型 作用
initParams WebInitParam[] Servlet的init参数
name String Servlet的名称
urlPatterns String[] Servlet的访问URL,支持多个
value String[] Servlet的访问URL,支持多个
loadOnStartup int 自启动Servlet
description String Servlet的描述
displayName String Servlet的显示名称
asyncSupported boolean 声明Servlet是否支持异步操作模式
package cn.it.servlet;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(urlPatterns = "/ann.do")
public class AnnotationServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.println("annotation");
        writer.flush();
        writer.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
}

4.32.2 @WebInitParam

使用注解配置servlet初始化参数。

属性名 类型 作用
name String param-name
value String param-value
description String description
package cn.it.servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
//配置初始化参数
@WebServlet(urlPatterns = "/init.do",initParams={
        @WebInitParam(name = "key1",value = "WebInitParam"),
        @WebInitParam(name = "key2",value = "Java")
},loadOnStartup = 1)
public class WebInitParamServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        ServletConfig servletConfig = this.getServletConfig();
        String key1 = servletConfig.getInitParameter("key1");
        String key2 = servletConfig.getInitParameter("key2");
        PrintWriter writer = resp.getWriter();
        writer.println(key1);
        writer.println(key2);
        writer.flush();
        writer.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    public void init() throws ServletException {
        //读取注解中配置的参数
        ServletConfig servletConfig = this.getServletConfig();
        Enumeration<String> initParameterNames = servletConfig.getInitParameterNames();
        while (initParameterNames.hasMoreElements()) {
            String name = initParameterNames.nextElement();
            String initParameter = servletConfig.getInitParameter(name);
            System.out.println(name + "=" + initParameter);
        }
    }
}

4.33 文件上传

在Servlet3.0之前的版本中如果实现文件上传需要依赖apache的Fileupload组件,在Servlet3.0以及之后的版本中提供了Part对象处理文件上传,所以不在需要额外的添加Fileupload组件。

在Servlet3.0以及之后的版本中实现文件上传时必须要在Servlet中开启多参数配置:

基于web.xml配置文件的配置

<multipart-config>
  <file-size-threshold></file-size-threshold>
  <location></location>
  <max-file-size></max-file-size>
  <max-request-size></max-request-size>
</multipart-config>

 

基于@MultipartConfig注解的配置

属性名 类型 描述
fileSizeThreshold int 当数据量大于该值时,内容将被写入临时文件。
location String 存放生临时成的文件地址
maxFileSize long 允许上传的文件最大值(byte)。默认值为 -1,表示没有限制
maxRequestSize long 一个 multipart/form-data请求能携带的最大字节数(byte),默认值为 -1,表示没有限制。

Part对象中常用的方法

上传文件的大小

long getSize()

上传文件的原始文件名

String getSubmittedFileName()

获取<input name="upload" ...>标签中name属性值

String getName()

获取上传文件的输入流

InputStream getInputStream()

保存文件至服务器

void write(String path)
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>上传文件</title>
</head>
<body>
<!--    上传文件只能post,因为get是字符提交。post既可以是字符提交(默认)也可以是字节提交-->
   <form action="up.do" method="post" enctype="multipart/form-data">
    文件描述   <input type="text" name="desc"/> <br> <!--文件描述是字符型数据-->
    上传文件   <input type="file" name="file"    /><br>  <!--文件是字节型数据。表单提交要么是字节提交,要么是字符提交-->
               <input type="submit" value="提交">
   </form>
</body>
</html>
package cn.it.servlet;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.UUID;
//文件上传
@WebServlet(urlPatterns = "/up.do")
@MultipartConfig //开启文件上传
public class FileUploadServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.setCharacterEncoding("UTF-8");
        //获取表单的描述信息
        String desc = req.getParameter("desc");
        //获取上传的文件
        Part part = req.getPart("file");
        //将上传文件重命名,防止文件覆盖,但是文件的扩展名要保留。
        String kz = part.getSubmittedFileName().substring(part.getSubmittedFileName().lastIndexOf("."));
        String newName = UUID.randomUUID().toString()+kz;
        //将上传的文件写到项目(路径转换)
        ServletContext servletContext = this.getServletContext();
        String realPath = servletContext.getRealPath("img/" + newName);
        System.out.println(realPath);
        //文件保存
        part.write(realPath);
        //将文件上传的描述返回到浏览器
        resp.setContentType("text/plain;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
        writer.println(desc);
        writer.println("文件上传的位置是:"+realPath);
        writer.flush();
        writer.close();
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}

需要注意的是只有将项目的位置放在tomcat中时文件才会存放在tomcat中。workspace中是没有上传的文件的。

4.34 Filter过滤器

Filter过滤器是Servlet2.3中所提供的一个过滤请求与响应的对象。

Filter过滤器既可以对客户端向服务器端发送的请求进行过滤,也可以对服务器端向客户端产生的响应进行过滤处理。

Filter对象的创建

创建一个Class实现Filter接口,并实现接口中三个抽象方法。

init()方法:初始化方法,在创建Filter后立即调用。可用于完成初始化动作。

doFilter()方法:拦截请求与响应方法,可用于对请求和响应实现预处理。

destroy()方法:销毁方法,在销毁Filter之前自动调用。可用于完成资源释放等动作。

<filter>
        <filter-name>FilterServlet</filter-name>
        <filter-class>cn.it.filter.FilterServlet</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>FilterServlet</filter-name>
        <url-pattern>/filter.do</url-pattern>  <!--只有请求filter.do时,该请求才会被管理器拦截-->
    </filter-mapping>
package cn.it.filter;
import javax.servlet.*;
import java.io.IOException;
public class FilterServlet implements Filter {
    /*Filter对象在容器启动的时候会被实例化,被实例化后立即调用init方法完成初始化*/
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init filter");
    }
    /*过滤请求与响应,当客户端请求的URL与Filter定义的URL-pattern匹配,那么该请求会进入到该方法*/
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //对请求处理
        System.out.println("请求被过滤");
        //放行请求
        filterChain.doFilter(servletRequest,servletResponse);
        //对响应处理
        System.out.println("响应过滤");
    }
    /*当Filter对象在销毁之前会调用一次destroy*/
    @Override
    public void destroy() {
    }
}

4.34.2在Filter中设置请求编码

<filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>cn.it.filter.EncodingFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>  <!--所有请求都能进入过滤器-->
    </filter-mapping>
package cn.it.filter;
import javax.servlet.*;
import java.io.IOException;
public class EncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("UTF-8");
        servletResponse.setCharacterEncoding("UTF-8");//不建议设置响应编码,要视需求而定。
        filterChain.doFilter(servletRequest, servletResponse);
    }
    @Override
    public void destroy() {
    }
}

由于HttpServletResponse对象是在Servlet的doGet或doPost等方法中创建的,因此设置响应编码的代码也通常放在这些方法中。这样可以确保在Servlet的业务逻辑处理后再设置响应编码,以免影响处理单元的逻辑和性能。

相关文章
|
2月前
|
Java 容器
【学习笔记】Jsp与Servlet技术
【学习笔记】Jsp与Servlet技术
83 0
|
3月前
|
Java 应用服务中间件 Maven
JavaWeb基础5——HTTP,Tomcat&Servlet
JavaWeb技术栈、HTTP、get和post区别、响应状态码、请求响应格数据式、IDEA使用Tomcat、报错解决、Servlet的体系结构、IDEA使用模板创建Servlet
JavaWeb基础5——HTTP,Tomcat&Servlet
|
4月前
|
缓存 安全 Java
Java服务器端技术:Servlet与JSP的集成与扩展
Java服务器端技术:Servlet与JSP的集成与扩展
42 3
|
4月前
|
前端开发 Java 开发工具
servlet技术--使用注解模拟用户登录实现页面跳转
该文章介绍了Servlet技术的使用,通过注解方式开发Servlet来模拟用户登录功能,并在登录成功后实现页面跳转,展示用户的用户名和密码。
servlet技术--使用注解模拟用户登录实现页面跳转
|
4月前
|
前端开发 安全 Java
在Java服务器端开发的浩瀚宇宙中,Servlet与JSP犹如两颗璀璨的明星,它们联袂登场,共同编织出动态网站的绚丽篇章。
在Java服务器端开发的浩瀚宇宙中,Servlet与JSP犹如两颗璀璨的明星,它们联袂登场,共同编织出动态网站的绚丽篇章。
31 0
|
6月前
|
缓存 安全 Java
Java服务器端技术:Servlet与JSP的集成与扩展
【6月更文挑战第23天】Java Web开发中,Servlet和JSP是构建动态Web应用的基础。Servlet处理逻辑,JSP专注展示。示例展示了Servlet如何通过`request.setAttribute`传递数据给JSP渲染。JSP自定义标签提升页面功能,如创建`WelcomeTag`显示欢迎消息。Servlet过滤器,如`CacheControlFilter`,用于预处理数据或调整响应头。这些集成和扩展技术增强了应用效率、安全性和可维护性,是Java服务器端开发的关键。
75 7
|
6月前
|
前端开发 安全 Java
Java服务器端开发实战:利用Servlet和JSP构建动态网站
【6月更文挑战第23天】**Servlet和JSP在Java Web开发中扮演关键角色。Servlet处理业务逻辑,管理会话,JSP则结合HTML生成动态页面。两者协同工作,形成动态网站的核心。通过Servlet的doGet()方法响应请求,JSP利用嵌入式Java代码创建动态内容。实战中,Servlet处理数据后转发给JSP展示,共同构建高效、稳定的网站。虽然新技术涌现,Servlet与JSP仍为Java Web开发的基石,提供灵活且成熟的解决方案。**
89 8
|
6月前
|
存储 设计模式 搜索推荐
早期javeweb技术 JSP JDBC JSTJ Servlet BooStrap(下)
早期javeweb技术 JSP JDBC JSTJ Servlet BooStrap(下)
41 1
|
5月前
|
Java 应用服务中间件 API
如何安装与使用Java EE 8、Servlet 3.0及Apache Maven进行高效开发
【7月更文第1天】搭建高效Java EE 8开发环境,包括安装JDK、选择WildFly或Payara Server作为应用服务器,以及安装Apache Maven。使用Maven创建Servlet 3.0 Web项目,编写 HelloWorldServlet,打包部署到服务器,通过访问特定URL测试应用。这一流程助力开发者实现快速原型和大型项目开发。
122 0
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术
序-Servlet和SpringMVC的联系和区别-配置路径先想好使用的使用的方法,然后匹配的需要的技术