目录
1.2.4 元素:指定过滤器所拦截的资源被Servlet容器调用的方式
1.3 HttpServletRequestWrapper(了解)
2.4 优化2.3例3 使用HttpFilter(没有直接继承HttpFilter)
2.5 优化2.3例3 使用HttpFilter(直接继承HttpFilter类)
servet Filter过滤在以后开发中,使用的频率还有有点高的,尤其在安全方面,如spring security,所以有必要学习一下。
一、知识点
1.1 简介
- Filter 的基本功能是对 Servlet 容器调用 Servlet 的过程进行拦截,从而在 Servlet 进行响应处理的前后实现一些特殊的功能。
- 在 Servlet API 中定义了三个接口类来开供开发人员编写 Filter 程序:Filter, FilterChain, FilterConfig
- Filter 程序是一个实现了 Filter 接口的 Java 类,与 Servlet 程序相似,它由 Servlet 容器进行调用和执行
- Filter 程序需要在 web.xml 文件中进行注册和设置它所能拦截的资源:Filter 程序可以拦截 Jsp, Servlet, 静态图片文件和静态 html 文件
Filter 的过滤过程
Filter 的基本工作原理
- 当在 web.xml 中注册了一个 Filter 来对某个 Servlet 程序进行拦截处理时,这个 Filter 就成了 Servlet 容器与该 Servlet 程序的通信线路上的一道关卡,该 Filter 可以对 Servlet 容器发送给 Servlet 程序的请求和 Servlet 程序回送给 Servlet 容器的相应进行拦截,可以决定是否将请求继续传递给 Servlet 程序,以及对请求和相应信息是否进行修改
- 在一个 web 应用程序中可以注册多个 Filter 程序,每个 Filter 程序都可以对一个或一组 Servlet 程序进行拦截。
- 若有多个 Filter 程序对某个 Servlet 程序的访问过程进行拦截,当针对该 Servlet 的访问请求到达时,web 容器将把这多个 Filter 程序组合成一个 Filter 链(过滤器链)。Filter 链中各个 Filter 的拦截顺序与它们在应用程序的 web.xml 中映射的顺序一致
Filter 接口
- init(FilterConfig filterConfig)throws ServletException:在 web 应用程序启动时,web 服务器将根据 web.xml 文件中的配置信息来创建每个注册的 Filter 实例对象,并将其保存在服务器的内存中。Web容器创建 Filter 对象实例后,将立即调用该 Filter 对象的 init 方法。Init 方法在 Filter 生命周期中仅执行一次,web 容器在调用 init 方法时,会传递一个包含 Filter 的配置和运行环境的 FilterConfig 对象(FilterConfig的用法和ServletConfig类似)。利用FilterConfig对象可以得到ServletContext对象,以及部署描述符中配置的过滤器的初始化参数。在这个方法中,可以抛出ServletException异常,通知容器该过滤器不能正常工作。
- destroy():在Web容器卸载 Filter 对象之前被调用。该方法在Filter的生命周期中仅执行一次。在这个方法中,可以释放过滤器使用的资源
- 与开发Servlet不同的是,Filter接口并没有相应的实现类可供继承,要开发过滤器,只能直接实现Filter接口。
- doFilter(ServletRequest request,ServletResponse response,
FilterChain chain)throws java.io.IOException,ServletException:
doFilter()方法类似于Servlet接口的service()方法。当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的doFilter()方法。其中参数 request, response 为 web 容器或 Filter 链的上一个 Filter 传递过来的请求和相应对象;参数 chain 为代表当前 Filter 链的对象,在特定的操作完成后,可以在当前 Filter 对象的 doFilter 方法内部需要调用 FilterChain 对象的 chain.doFilter(request,response)方法才能把请求交付给 Filter 链中的下一个 Filter 或者目标 Servlet 程序去处理,也可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及HttpServletResponse的sendRedirect()方法将请求转向到其他资源。这个方法的请求和响应参数的类型是ServletRequest和ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
FilterChain接口
- FilterChain接口:代表当前 Filter 链的对象。由容器实现,容器将其实例作为参数传入过滤器对象的doFilter()方法中。过滤器对象使用FilterChain对象调用过滤器链中的下一个过滤器,如果该过滤器是链中最后一个过滤器,那么将调用目标资源。
- doFilter(ServletRequest request,ServletResponse response)throws java.io.IOException:调用该方法将使过滤器链中的下一个过滤器被调用。如果是最后一个过滤器,会调用目标资源。
- javax.servlet.FilterConfig接口:该接口类似于ServletConfig接口,由容器实现。Servlet规范将代表 ServletContext 对象和 Filter 的配置参数信息都封装在该对象中。Servlet 容器将其作为参数传入过滤器对象的init()方法中。
- String getFilterName():得到描述符中指定的过滤器的名字。
- String getInitParameter(String name): 返回在部署描述中指定的名字为name的初始化参数的值。如果不存在返回null.
- Enumeration getInitParameterNames():返回过滤器的所有初始化参数的名字的枚举集合。
- public ServletContext getServletContext():返回Servlet上下文对象的引用。
映射 Filter
- <filter-mapping>元素用于设置一个 Filter 所负责拦截的资源。一个Filter拦截的资源可通过两种方式来指定:Servlet 名称和资源访问的请求路径( url样式)
- <filter-name>子元素用于设置filter的注册名称。该值必须是在<filter>元素中声明过的过滤器的名字
- <url-pattern>设置 filter 所拦截的请求路径(过滤器关联的URL样式)
- <servlet-name>指定过滤器所拦截的Servlet名称。
- <dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST. 可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截
- <dispatcher> 子元素可以设置的值及其意义:
- REQUEST:当用户直接访问页面时,Web容器将会调用过滤器。如果目标资源是通过RequestDispatcher的include()或forward()方法访问时,那么该过滤器就不会被调用。
- INCLUDE:如果目标资源是通过RequestDispatcher的include()方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。
- FORWARD:如果目标资源是通过RequestDispatcher的forward()方法访问时,那么该过滤器将被调用,除此之外,该过滤器不会被调用。
- ERROR:如果目标资源是通过声明式异常处理机制调用时,那么该过滤器将被调用。除此之外,过滤器不会被调用。
- 在同一个 web.xml 文件中可以为同一个 Filter 设置多个映射。若一个 Filter 链中多次出现了同一个 Filter 程序,这个 Filter 程序的拦截处理过程将被多次执行
1.2 小结
1.2.1 Filter 是什么?
1.JavaWEB的一个重要组件, 可以对发送到Servlet的请求进行拦截,并对响应也进行拦截。
2.Filter是实现了Filter接口的Java 类。
3.Filter需要在web. xml文件中进行配置和映射。
1.2.2 如何创建一一个Filter,并把他跑起来
1.创建一个Filter类:实现Filter接口: public class HelloFilter implements Filter
2.在web.xml文件中配置并映射读Filter.其中url-pattern指定该Filter可以拦截可些资源,即可以通过哪些url访问到该Filter<!--注册Filter --> <filter> <filter-name>helloFilter</filter-nane> <filter-class>com.hualinux.javaweb.HelloF11ter</fllter-class> </filter> <!--映射Filter --> <filter-mapping> <filter-name>helloFilter</fi1ter-name> <ur1-pattern>/test.jsp</url-pattern> </filter-mapping>
1.2.3 Filter 相关的API
Filter 相关的API:
1.Filter接口:
public void init(FilterConfig fllterConfig): 类似于Servlet 的init方法。在创建Fllter 对象(Filter 对象
立即被调用,且只被调用-次。该方法用于对当前的Filter进行初始化操作。Filter 实例是单例的。.
* FilterConfig类似于ServletConfig
* 可以在web.xml文件中配置当前Filter的初始化参数。配置方式也和Servlet类似。
<filter>
<filter-name>helloF ilter</filter- name>
<filter-class>com.hualinux.javaweb.HelloFilter</fi1ter-class>
<init-param>
<param- name>name</param- name>
<param-value> root</param-value>
</init-param>
</filter>public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain): 真正Filter的逻辑代码需要编写在该方法中。每次拦截都会谓用该方法。
*FilterChain: Filter 链。多个Filter可以构成- 个Filter链
-doFilter(Serv1etRequest request, ServletResponse response):把请求传给Filter错的下一个Filte若当前Filter是Filter错的最后一个Filter,将把请求给到目标Serlvet(或JSP)
Filter
-多个Fi1ter 拦截的顺序和<filter- mapping> 配置的顺序有关,靠树的先被调用。public void destroy(): 释放当前Filter所占用的资源的方法。在Fi1ter被销毁之前被调用,且只被调用一次。
1.2.4 <dispatcher> 元素:指定过滤器所拦截的资源被Servlet容器调用的方式
可以是REQUEST, INCLUDE , FORWARD和ERROR之-.默认REQUEST.
可以设置多个<dispatcher>子元用来指定Filter对资源的多种调用方式进行拦截
1. REQUEST. 当用户直接访问页面时,Web容器将公调用过滤器。如果目标资源是通过RequestDispatcher的include( )或forward( )方法访间,通过GET或POST请求直接访问。
2.FORHARD. 如果目标资源是通过RequestDispatcher的forward( )方法访问时,那么该过滤器将被调用。除此之外,该过滤器不会被调用。或<jsp:forward page-"/.." />或通过page指令的errorPage转发页面. <X@ page errorPage="test.jsp" %>
3. INCLUDE. 如果目标资源是通过RequestDispatcher的include( )方法访问时。那么資过滤器将被调用。除此之外。该过滤器不会被调用。或<jsp:include file="/..." />
4. ERROR. 如果目标资源是通过声明式异常处理机制调用时。那么该过滤器将被调用。除此之外。过滤器不会被调用。
在web. xml文件中通过error-page节点进行声明:
<error-page> <exception-type>java.lang.ArithmeticException</ exception-type> <location>/test.jsp</location> </error-page> </filter-mapping> <filter-name>secondFilter</filter- name> <url-pattern>/test .jsp</url-pattern> <dispatcher>REQUEST</dispatcher> <dispatcher> FORWARD</dispatcher> <dispatcher> INCLUDE</dispatcher> <dispatcher> ERROR</ dispatcher> </fi1ter-mapping>
1.3 HttpServletRequestWrapper(了解)
1.. why:
需要改变从Servlet容器(可能是任何的Serlvet 容器)中传入的HttpServletReuqest对象的某个行为,该怎么办?
1).继承HttpServletReuqest接口的Servlet容器的实现类,但就和具体的容器相耦合了
2).提供HttpServletRequest接口的实现类,很麻烦,而且也需要和具体的容器相耦合
3).使用装饰器设计模式:
>提供-一个类,该类实现HttpServletRequest接口
>传入具体的一一个容器实现的HttpServletRequest接口的实现类作为上述类的一个成员变量
>使用HttpServletRequest成员变量来实现HttpServletRequest接口的所有方法public class ServletRequestWrapper implements ServletRequest { //被包装的那个ServletRequest 对象 private ServletRequest request; //构造器传入ServletRequest实现类对象 public ServletRequestWrapper(ServletRequest request) { if (request == nul) { throw new llegalArgumentException("Request cannot be null'); } this.request = request; //具体实现ServletRequest的方法:调用被包装的那个成员变量的方法实现。 public Object getAttribute(String name) { return this.request.getAttribute(name); } public Enumeration getAttributeNames0 { return this.requst.gettributeNames0; } //...
>再提供上述类的实现类,重写具体的方法即可。
public class MyHttpServletRequest extends HttpServletRequestWrapper{ public MyHttpServletRequstHttpServletRequest request) { super(request); } @Override public String getParameter(String name) { String val = super.getParameter(name); if(val != null && val.contains(" fuck ")){ val = val.replace("fuck", *****); } return val; } }
二、例子
2.1 例1 原生Filter接口实现简单的hello
2.1.1 所需文件
2.1.2 相关代码
1.在web下建立index.html内容为:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<a href="test.jsp">To Test Page</a>
</body>
</html>
2. 在web下建立test.jsp内容为:
<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %>
<html>
<head>
<title>test</title>
<meta charset="UTF-8">
</head>
<body>
<%
out.println("this is Test");
%>
</body>
</html>
3. 在src--> com.hualinux.filter1--> HelloFilter.java
ackage com.hualinux.filter1;
import javax.servlet.*;
import java.io.IOException;
public class HelloFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("init...");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("doFilter...");
}
@Override
public void destroy() {
System.out.println("destroy...");
}
}
4. web-->WEB-INF-->web.xml代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- 注册Filter -->
<filter>
<filter-name>helloFilter</filter-name>
<filter-class>com.hualinux.filter1.HelloFilter</filter-class>
</filter>
<!-- 映射Filter -->
<filter-mapping>
<filter-name>helloFilter</filter-name>
<!-- 配置要拦截的目标,可以结合*号指定后缀文件,如*.jsp、/* -->
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
</web-app>
2.1.3 运行效果
注:我这里使用的是360浏览器,我把tomcat也修改了一下根目录直接为locahost:8080/
发现网页空白
上图中之所以空白是被配置的Fitler给拦截了,所以test.jsp没有出内容,刷新几次上页面
发现每刷新1次,Filter的doFilter就会被调用1次,init只执行一次,这和前面serlvet很像.
按停止,则destroy方法才会被调用
如果要让test.jsp显示内容怎么办,可以使用FilterChain放行
doFilter(ServletRequest request,ServletResponse response)throws java.io.lOException :调用该方法将使
过滤器链中的下一个过滤器被调用。如果是最后一个过滤器,会调用目标资源。
在src--> com.hualinux.filter1--> HelloFilter.java中的doFilter()方法添加
filterChain.doFilter(servletRequest, servletResponse);
如下图:
再次运行,效果:
从上图来看test.jsp中的内容被显示出来了。
2.2 例2 FilterConfig接口
FilterConfig和servletConfig很像,这里就不再写了,要学会“举一反三”,思想迁移
只学会了技术,当来了新技术之后一点思路都没有,那是挻失败的事。
2.3 例3 映射Filter
2.3.1 需求
2.3.2 所需文件
所需要的文件如下:红色方框
2.3.3 文件对应的代码
1. WEB-->login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登录</title>
</head>
<body>
<span style="color: red">${msg}</span>
<br><br>
<form action="hello.jsp" method="post">
username:<input type="text" name="username" />
password:<input type="password" name="pwd" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
2. WEB-->hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>hello</title>
</head>
<body>
Hello:${param.username}
</body>
</html>
3. src--> com.hualinux.filter1--> UserNameFilter.java
package com.hualinux.filter1;
import javax.servlet.*;
import java.io.IOException;
public class UserNameFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String initUser = filterConfig.getInitParameter("username");
String username = servletRequest.getParameter("username");
if(!initUser.equals(username)){
servletRequest.setAttribute("msg","用户名不正确");
servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
return;
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
4. src--> com.hualinux.filter1--> PasswordFilter.java
package com.hualinux.filter1;
import javax.servlet.*;
import java.io.IOException;
public class PasswordFilter implements Filter {
private FilterConfig filterConfig;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig = filterConfig;
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { ;
String initPassword = filterConfig.getServletContext().getInitParameter("pwd");
System.out.println("web.xml的pwd是:"+initPassword);
String password = servletRequest.getParameter("pwd");
if(!initPassword.equals(password)){
servletRequest.setAttribute("msg","密码不正确");
servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest,servletResponse);
return;
}
filterChain.doFilter(servletRequest,servletResponse);
}
@Override
public void destroy() {
}
}
5. web-->WEB-INF-->web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>pwd</param-name>
<param-value>1234</param-value>
</context-param>
<!-- 注册Filter -->
<filter>
<display-name>UserNameFitler</display-name>
<filter-name>UserNameFitler</filter-name>
<filter-class>com.hualinux.filter1.UserNameFilter</filter-class>
<init-param>
<param-name>username</param-name>
<param-value>Tom</param-value>
</init-param>
</filter>
<!-- 映射Filter -->
<filter-mapping>
<filter-name>UserNameFitler</filter-name>
<url-pattern>/hello.jsp</url-pattern>
</filter-mapping>
<filter>
<display-name>PasswordFitler</display-name>
<filter-name>PasswordFitler</filter-name>
<filter-class>com.hualinux.filter1.PasswordFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>PasswordFitler</filter-name>
<url-pattern>/hello.jsp</url-pattern>
</filter-mapping>
</web-app>
2.3.4 效果
运行,打开浏览器输入:http://localhost:8080/hello.jsp
输入正确密码的提示:
2.4 优化2.3例3 使用HttpFilter(没有直接继承HttpFilter)
和Servlet一样,当我们使用到http的时候,每次也要强转一下,
当需要使用到Http相关操作的时候,经常会用到GET或POST,每次都得把HttpServletRequest或HttpServletResponse方法进行强转
如下面代码:
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
太麻烦了,用到http方面的,可以直接使用Filter 接口子类HttpFilter
建立src--> com.hualinux.filter1-->HttpFilter.java,代码如下:
package com.hualinux.filter1;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public abstract class HttpFilter implements Filter {
private FilterConfig filterConfig;
/*
* 不建议子类直接覆盖。 若直接覆盖,将可能会导致 filterConfig 成员变量初始化失败
* */
@Override
public void init(FilterConfig filterConfig) throws ServletException {
this.filterConfig=filterConfig;
init();
}
/*
* 供子类继承的初始化方法。 可以通过 getFilterConfig() 获取 filterConfig 对象.
* */
protected void init(){}
/*
* 原生的 doFilter 方法,在方法内部把 ServletRequest 和 ServletResponse 转为了 HttpServletRequest 和 HttpServletResponse
* 并调用了doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
*
* 若编写 Filter 的过滤方法不建立直接继承该方法。而是建议继承
* doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 方法
* */
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
doFilter(request, response, filterChain);
}
/*
* 抽象方法,为 Http 请求定制,必须实现方法。
* @param request
* @param response
* @param filterChain
* @throws IOException
* @throws ServletException
* */
public abstract void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException;
/*
* 直接返回init(ServetConfig) 的 FilterConfig 对象
* */
public FilterConfig getFilterConfig(){
return filterConfig;
}
@Override
public void destroy() {
}
}
2.5 优化2.3例3 使用HttpFilter(直接继承HttpFilter类)
上面的2.4 优化还需要自己写,其实有现成的HttpFilter,直接使用即可。只有2个方法
具体代码修改在这里我不写了,以为和serlvet的相似
2.6 例4 映射 Filter dispatcher
此例子是 “2.1 例1”的基础上稍微修改一下的,其中web.xml、HelloFilter、test.jsp不变
在index.hml和test.jsp中添加一个文件转而已,修改前后图如下:
2.6.1 所需要文件
2.6.2 相关代码
1.index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test</title>
</head>
<body>
<a href="dispatcher.jsp">To Test Page</a>
</body>
</html>
2. dispatcher.jsp代码
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>dispatcher</title>
</head>
<body>
<jsp:forward page="/test.jsp"></jsp:forward>
</body>
</html>
3. web.xml代码不变
<!-- 注册Filter -->
<filter>
<filter-name>helloFilter</filter-name>
<filter-class>com.hualinux.filter1.HelloFilter</filter-class>
</filter>
<!-- 映射Filter -->
<filter-mapping>
<filter-name>helloFilter</filter-name>
<!-- 配置要拦截的目标,可以结合*号指定后缀文件,如*.jsp、/* -->
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
2.6.3 效果
没点下面之前清空ide最下方的信息
发现最下方Filter没有被调用,没有doFilter
分析原因:
<dispatcher>指定过滤器所拦截的资源被 Servlet 容器调用的方式,可以是REQUEST,INCLUDE,FORWARD和ERROR之一,默认REQUEST. 可以设置多个<dispatcher> 子元素用来指定 Filter 对资源的多种调用方式进行拦截
因为我们用的是forward方式,并不是REQUEST,所以需要在web.xml配置一个<dispatcher>子元素用来指定 Filter
打开web.xml,修改如下:
<!-- 映射Filter -->
<filter-mapping>
<filter-name>helloFilter</filter-name>
<!-- 配置要拦截的目标,可以结合*号指定后缀文件,如*.jsp、/* -->
<url-pattern>/test.jsp</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
添加一个<dispatcher>子节点就行了,重启tomcat,清空ide最下方信息,再次测试一下
发现有“doFilter...”了,如下图:
同理如果用到其它方式相继添加<dispatcher>子节点就行了
三、 Filter经典案例
3.1 经典应用1使浏览器不缓存页面的过滤器
- 使浏览器不缓存页面的过滤器:
- 有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
- response.setDateHeader("Expires",-1);
- response.setHeader("Cache-Control","no-cache");
- response.setHeader("Pragma","no-cache");
- 并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头
- 有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
具体代码我这里不写了,可以看相关视频截图,这个应用得少。
3.2 经典应用2 字符编码的过滤器
3.2.1 所需文件
所需要的文件很简单,就是在web目录下建立一个encoding目录,再建立a.jsp和b.jsp文件
3.2.2 实现代码
web-->encoding-->a.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>a</title>
<meta charset="UTF-8">
</head>
<body>
<form action="b.jsp" method="post">
name:<input type="text" name="name" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
web-->encoding-->b.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>b</title>
<meta charset="UTF-8">
</head>
<body>
Hello:${param.name}
</body>
</html>
3.2.3 运行效果
打开浏览器,输入:http://localhost:8080/encoding/a.jsp
输入abc提交,效果如下:
但是输入中文,如“广州”,会产生乱码,如下图:
解决方法一:
在请求中指定编码,我这里使用的是UTF-8,b.jsp修改如下:
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>b</title>
<meta charset="UTF-8">
</head>
<body>
<%
request.setCharacterEncoding("UTF-8");
%>
Hello:${param.name}
</body>
</html>
重启tomcat再次测试,显示正常
这里有一个问题,如果我的页面是几百上千万个,我每个页都添加这段代码,会累死的!
而且还不好维护...所以使用过滤器统一过滤这样比较好
思路:
为了方便统一修改编码,我样可以放在一个配置文件中,这里可以放以web.xml中
然后通过filter统一过渡
实现:
1. 把b.jsp添加的请求编码去掉:
<%
request.setCharacterEncoding("UTF-8");
%>
恢复到起始的状态
2. web.xml添加编码,如下:
<context-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</context-param>
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.hualinux.filter1.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/encoding/*</url-pattern>
</filter-mapping>
3. src-->com.hualinux.filter1-->EncodingFilter.java
这里用到前面的手工写的HttpFilter类
ackage com.hualinux.filter1;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class EncodingFilter extends HttpFilter{
private String encoding;
@Override
protected void init() {
encoding= getFilterConfig().getServletContext().getInitParameter("encoding");
}
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
request.setCharacterEncoding(encoding);
filterChain.doFilter(request,response);
}
}
4. 运行一下试下效果和之前的一样不
3.3 经典应用3 检测用户是否登录的过滤器
检测用户是否登陆的过滤器:
-情景:系统中的某些页面只有在正常登陆后才可以使用,用户请求
这些页面时要检查session中有无该用户信息,但在所有必要的页
面加上session的判断相当麻烦的事情-解决方案:编写一个用于检测用户是否登陆的过滤器,如果用户未
登录,则重定向到指的登录页面-要求:需检查的在Session中保存的关键字;如果用户未登录,需
重定向到指定的页面(URL不包括ContextPath);不做检查的URL列
表(以分号分开,并且URL中不包括ContextPath)都要采取可配置
的方式
3.3.1 相关文件
其中HttpFilter代码上面有,不再写
3.3.2 实现代码
1. web-->login-->a.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>a</title>
</head>
<body>
<h3>AAA PAGE</h3>
<a href="list.jsp">Return...</a>
</body>
</html>
其中b.jsp、c.jsp、d.jsp、e.jsp的
<a href="list.jsp">Return...</a>
是不变的,还有把a.jsp相应地做出修改
<h3>AAA PAGE</h3>
把它分别修改成
<h3>BBB PAGE</h3>
<h3>CCC PAGE</h3>
<h3>DDD PAGE</h3>
<h3>EEE PAGE</h3>
2. web-->login-->list.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>list</title>
</head>
<body>
<a href="a.jsp">AAA</a>
<br><br>
<a href="b.jsp">BBB</a>
<br><br>
<a href="c.jsp">CCC</a>
<br><br>
<a href="d.jsp">DDD</a>
<br><br>
<a href="e.jsp">EEE</a>
<br><br>
</body>
</html>
3. web-->login-->login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
</head>
<body>
<form action="doLogin.jsp" method="post">
username:<input type="text" name="username" />
<input type="submit" value="Submit" />
</form>
</body>
</html>
4. web-->WEB-INF-->web.xml
<!-- 用户信息放入到 sesskon中的键的名字-->
<context-param>
<param-name>userSessionKey</param-name>
<param-value>USERSESSIONKEY</param-value>
</context-param>
<!-- 右未登录,需重写向页面-->
<context-param>
<param-name>rediretPage</param-name>
<param-value>/login/login.jsp</param-value>
</context-param>
<!-- 不需要拦截(或检查)的 URL 列表 -->
<context-param>
<param-name>uncheckedUrls</param-name>
<param-value>/login/a.jsp,/login/list.jsp,/login/login.jsp,/login/doLogin.jsp</param-value>
</context-param>
<filter>
<filter-name>lgoinFitler</filter-name>
<filter-class>com.hualinux.filter1.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>lgoinFitler</filter-name>
<url-pattern>/login/*</url-pattern>
</filter-mapping>
5. web-->login-->doLogin.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>登陆</title>
</head>
<body>
<%
//1. 获取用户的登陆信息
String username = request.getParameter("username");
//2. 若登陆信息完整,则把登陆信息放到 HttpSession
if (username != null && !username.trim().equals("")){
session.setAttribute(application.getInitParameter("userSessionKey"),username);
//3. 重定向到list.jsp
response.sendRedirect("list.jsp");
}else {
response.sendRedirect("login.jsp");
}
%>
</body>
</html>
6. src--> com.hualinux.filter1-->LoginFilter.java
package com.hualinux.filter1;
import javax.servlet.FilterChain;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
public class LoginFilter extends HttpFilter {
// 1. 从web.xml 文件中获取 sessionKey,redirectUrl, uncheckedUrls
private String sessionKey;
private String redirectUrl;
private String uncheckedUrls;
@Override
protected void init() {
ServletContext servletContext = getFilterConfig().getServletContext();
sessionKey = servletContext.getInitParameter("userSessionKey");
redirectUrl = servletContext.getInitParameter("rediretPage");
uncheckedUrls = servletContext.getInitParameter("uncheckedUrls");
}
@Override
public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
//1. 获取请求的URL
// String requestURL = request.getRequestURL().toString();
// String requestURI = request.getRequestURI();
// /login/b.jsp
String servletPath = request.getServletPath();
//2. 检查1获取的 servletPath 是否为不需要检查的 URL 中的一个,若是,则直接放行,方法结束
List<String> urls = Arrays.asList(uncheckedUrls.split(","));
if(urls.contains(servletPath)){
filterChain.doFilter(request,response);
return;
}
//3.从 session 中获取 sessionKey 对应的值,若值不存在,则重定向到 redirectUrl
Object user = request.getSession().getAttribute(sessionKey);
if(user == null){
response.sendRedirect(request.getContextPath()+redirectUrl);
return;
}
//4. 右存在,则放行,充许访问
filterChain.doFilter(request,response);
}
}
3.3.3 效果
运行,打开浏览器输入http://localhost:8080/login/list.jsp
点BBB效果
因为上图没有编写登出代码,需要清空cookie才行