过滤器
1:过滤器的作用
把通用的、相同的处理代码用过滤器实现,可以共享,然后在web.xml中将过滤器配置给相关的资源使用即可

2:过滤器的开发方法
- 写一个类实现Filter接口
- 重写Filter接口的三个方法

- IDE开发工具开发过滤器的步骤:
- 在doFilter()方法写逻辑: System.out.println("MyFilter.doFilter()...");
- 创建servlet,运行servlet测试.
- 放行 执行chain.doFilter(request,response)
- 不放行 不执行chain.doFilter(request,response)
package com.tjetc.filter;
import javax.servlet.*;
import java.io.IOException;
import java.util.Enumeration;
public class HelloFilter implements Filter {
public HelloFilter() {
System.out.println("HelloFilter的构造方法");
}
/**
* 初始化, 调用一次, Tomcat启动时会调用Filter的init ?
*
* @param filterConfig
* @throws ServletException
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("HelloFilter的init方法被调用");
String filterName = filterConfig.getFilterName();
System.out.println("filterName=" + filterName);
Enumeration<String> initParameterNames = filterConfig.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {//initParameterNames.hasMoreElements())遍历过程中判断是否还有元素遍历
//获取参数名称
String parameterName = initParameterNames.nextElement();
//获取参数对应的value值
String parameterValue = filterConfig.getInitParameter(parameterName);
System.out.println(parameterName + "=" + parameterValue);
}
ServletContext servletContext = filterConfig.getServletContext();
//获取上下文对象
System.out.println("servletContext=" + servletContext);
}
/**
* 每次Filter拦截到的请求, 都会调用doFilter方法, 可调用多次
*
* @param servletRequest 请求对象
* @param servletResponse 响应对象
* @param filterChain 过滤器链对象
* @throws IOException
* @throws ServletException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("HelloFilter的doFilter方法被调用");
//例如:验证是否的登录过,没有登录,返回到登录页面或者返间json, 需要的登录
//filterChain 过滤器链, 不处理过滤器链, 那就认为链条断掉, 后续的filter和servlet都不会访问
//filterChain.doFilter(servletRequest,servletResponse);
filterChain.doFilter(servletRequest, servletResponse);//放行,执行后续的filter和servlet
}
/**
* 销毁Filter时调用, 调用一次, 使用场景:释放资源
*/
@Override
public void destroy() {
System.out.println("HelloFilter的destroy方法被调用");
}
}
web.xml配置HelloFilter
<filter>
<filter-name>HelloFilter</filter-name>
<filter-class>com.tjetc.filter.HelloFilter</filter-class>
<init-param>
<param-name>age</param-name>
<param-value>19</param-value>
</init-param>
<init-param>
<param-name>email</param-name>
<param-value>ww@163.com</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HelloFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
3、过滤器的各个方法执行顺序
- 构造方法
- init(filterConfig)初始化方法
- doFilter()方法
- destroy()方法
package com.tjetc.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;
public class HelloServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// resp.setContentType("text/html;charset=utf-8");
// resp.getWriter().write("<h1>HelloServlet欢迎您!</h1>");
//请求转发到my.jsp页面
req.getRequestDispatcher("/my.jsp").forward(req, resp);
}
}
web.xml配置HelloServlet
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.tjetc.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>my.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<base href="<%=request.getContextPath()%>/">
</head>
<body>
<img src="static/img/14.jpg" width="500px">
</body>
</html>TestServlet
package com.tjetc.servlet;
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;
@WebServlet(value = "/test", initParams = {
@WebInitParam(name = "username", value = "jack"),
@WebInitParam(name = "age", value = "20")
})
public class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = super.getInitParameter("username");
String age = super.getInitParameter("age");
System.out.println("username=" + username + ",age=" + age);
}
} 

4、FilterConfig接口的方法

5、FilterChain接口的方法

6、编码过滤器
package com.tjetc.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CharacterEncodingFilter implements Filter {
//定义编码
private String charset = "utf-8";
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//读取参数
String encoding = filterConfig.getInitParameter("charset");
if (charset != null && " ".equals(encoding)) {
charset = encoding;
}
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//转换request和response对象
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//设置编码参数
//设置请求对象的参数编码
req.setCharacterEncoding(charset);
//设置相应的参数编码
resp.setContentType("text/html;charset=" + charset);
//resp.setContentType(charset);
//过滤器链放行
filterChain.doFilter(req, resp);
}
@Override
public void destroy() {
}
}
总结
1、过滤器的作用
把相同通用的代码用过滤器实现,会让目标资源共享
2、过滤器的开发方法
- 写一个类实现Filter接口
- 重写接口的3个方法
- doFilter()写处理逻辑.
- chain.doFilter()放行
- 不调用chain.doFilter()不放行,到不了servlet或者jsp
3、过滤器的各个方法的执行顺序
- 构造方法
- 初始化方法init(FilterConfig fConfig)
- doFilter()方法
- destroy()方法 销毁方法
4、FilterConfig接口的方法
- getFilterName():返回xml配置的filter的名字
- getInitParameter(name):返回初始化的参数的值
- getInitParameterNames():返回所有的初始化参数的名字
- getServletContext():返回上下文对象
5、FilterChain接口的方法
1、doFilter()方法:
- 如果有下一个过滤器就执行下一个过滤器
- 没有就会执行目标资源(servlet或者jsp)
6、编码过滤器
- 初始化参数encoding=UTF-8
- doFilter():设置encoding
过滤器的配置
1、过滤器配置信息
1.过滤器的名称和类
2.过滤的url
3.过滤的url的访问方式
1.REQUEST:默认的访问方式
1.直接url访问
2.超级链接
3.form的提交
4.重定向
5.静态包含
2.FORWARD
请求转发
3.INCLUDE
动态包含
4.ERROR
错误页面的跳转
4.初始化参数
5.一个过滤器可以配置给多个url
6.一个url可以配置多个过滤器,多个过滤器组成过滤器链,按照配置的顺序执行
范例:
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.tjetc.filter.MyFilter</filter-class>
<init-param>
<param-name>name</param-name>
<param-value>zs</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/order/*</url-pattern>
<url-pattern>/cart/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
一个工程有多个过滤器,形成过滤器链
多个过滤器的执行顺序是什么?
根据filter-mapping的url-pattern的顺序来执行
利用过滤器实现访问控制
1、什么是访问控制
有很多资源需要登录后才能访问,称为访问控制
访问控制使用过滤器实现效果更佳.
2、登录过滤器实现访问控制
1、创建order.jsp订单页面
要访问order.jsp必须先登录才能访问,不登录不能访问
在WEB-INF下建个目录user,user下创建order.jsp,(WEB-INF下的不会被外部访问)
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<base href="<%=request.getContextPath()%>/">
</head>
<body>
<h1>order.jsp</h1>
</body>
</html>
2、创建登录过滤器,过滤/order/*请求
判断用户是否登录,如果用户登录,用户信息会放到session
到session拿用户信息:
- 如果用户信息不空代表用户已经登录,则放行
- 如果用户信息为空,代表用户未登录,则重定向到登录页面,让用户去登录
package com.tjetc.filter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//从session中获取用户名,如果存在,就请求转发到order.jsp页面,如果不存在,就响应重定向到login.jsp页面
String username = (String) req.getSession().getAttribute("username");
if (username == null) { //不存在
//响应重定向到login.jsp页面
resp.sendRedirect(req.getContextPath() + "/login.jsp");
} else { //存在
//说明已经登录过了,放行
filterChain.doFilter(req, resp);
}
}
}
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.tjetc.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<!--url中/user开头的要经过过滤器,也就是要判断登录-->
<url-pattern>/user/*</url-pattern>
</filter-mapping>3、创建login.jsp
<html>
<head>
<title>Title</title>
<base href="<%=request.getContextPath()%>/">
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username"><br>
密码:<input type="password" name="password"><br>
<input type="submit" value="登录">
<%
String msg = (String) request.getAttribute("msg");
if (msg != null) {
%>
<span style="color: #ff0032"><%=msg%></span>
<%
}
%>
</form>
</body>
</html>
4、创建LoginServlet
从请求参数取得用户名和密码
判断用户名和密码是否正确
- 如果正确,将user放到session,session.setAttribute(“user”,user),重定向到success.jsp
- 如果错误,重定向到login.jsp继续登录
package com.tjetc.servlet;
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 LoginServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//获取请求传来的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
//判断用户名和密码是否正确
if ("tom".equals(username) && "123".equals(password)) {
//登陆验证成功,要在session中存储用户信息
req.getSession().setAttribute("username", username);
//正确,跳转到订单页面, 响应重定向访问order页面url(/user/order 访问订单的servlet)
resp.sendRedirect(req.getContextPath() + "/user/order");
} else {
//错误,请求转发跳转到登录页面,把错误消息返回给页面
req.setAttribute("msg", "用户名或密码错误");
req.getRequestDispatcher("/login.jsp").forward(req, resp);
}
}
}
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.tjetc.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>5、创建OrderServlet
package com.tjetc.servlet;
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 OrderServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//请求转发到WEB-INF/user/order.jsp页面
req.getRequestDispatcher("/WEB-INF/user/order.jsp").forward(req, resp);
}
}
<servlet>
<servlet-name>OrderServlet</servlet-name>
<servlet-class>com.tjetc.servlet.OrderServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OrderServlet</servlet-name>
<url-pattern>/user/order</url-pattern>
</servlet-mapping> 
Servlet3.0新特性
1:注解
Servlet3.0注解有五种类型:
@WebServlet:对Servlet进行配置
@WebInitParam:配置Servlet初始化参数
@WebFilter:配置过滤器
@WebListener :配置监听器
@MultipartConfig:对文件上传的支持
1、@WebServlet:对Servlet进行配置
- 必选属性
1、value: 等价于 urlPatterns 属性。
2、urlPatterns:等价于web.xml配置文件中的 <url-pattern> 标签
二者的值是一样的,而且代表的含义也是一样的.其他是可选的
3、注意:
value和urlPatterns不能同时设置,只能使用其中的一个,同时设置就会报错
Caused by:java.lang.IllegalArgumentException: 类文件[com.tjetc.servlet.HelloServlet]的urlPatterns和值属性上同时设置了注解[WebServlet]
4、例子
@WebServlet(urlPatterns={"/HelloServlet","/abc"})
2、可选属性
1、name:等价于web.xml配置文件中的 <servlet-name>。
如果没有指定name, Servlet 的<servlet-name>取值为类的全限定名,比如XXX.XXX.XXX。
如果指定name,取值为指定的名字
2、loadOnStartup:
等价于web.xml配置文件中的<load-on-startup> 标签
在服务器启动的时候就加载servlet,数字,越小代表越先启动
当值小于0或者没有指定时,则表示容器在该servlet被选择时才会去加载。
正数的值越小,该servlet的优先级越高,应用启动时就越先加载。
3、initParams :
等价于web.xml配置文件中的<init-param> 标签,他的参数是@WebInitParam注解的集合
4、description:
等价于web.xml配置文件中的<description> 标签
5、displayName:
等价于web.xml配置文件中的 <display-name> 标签
2、@WebInitParam
配置Servlet初始化参数,常用属性有三个,这三个属性当中只有description为可选属性:
name:等价于web.xml配置文件中的 <param-name>
value :等价于web.xml配置文件中的<param-value>
description:等价于web.xml配置文件中的<description>

@WebServlet(value = "/test", initParams = {
@WebInitParam(name = "username", value = "jack"),
@WebInitParam(name = "age", value = "20")
})3、@WebFilter
配置过滤器此注解为声明一个过滤器,主要属性有以下几个。
1、value、urlPatterns、servletNames至少包含一个
在这些属性当中value、urlPatterns、servletNames 三个属性至少要包含其中的一个,并且 value 和 urlPatterns 属性只能有一个,如果两个同时配置,一般情况下value取值将会被忽略。
- value:该属性等价于 urlPatterns 属性
- urlPatterns:等价于web.xml配置文件中的 <url-pattern> 标签
- servletNames:指定该过滤器将应用的范围。如果是注解的话取值是 @WebServlet 中的 name 属性的取值,如果servlet在 web.xml 中配置的话,取值是 <servlet-name> 的取值
2、其他的都是可选属性
filterName:等价于web.xml配置文件中的 <filter-name>标签,过滤器的名称
dispatcherTypes:过滤器的转发模式。取值包括:
ASYNC(异步)、ERROR(错误)、FORWARD(请求转发)、INCLUDE(包含)、REQUEST(请求)。
initParams:等价于web.xml配置文件中的<init-param> 标签
description:等价于web.xml配置文件中的<description> 标签
displayName:等价于web.xml配置文件中的<display-name> 标签
@WebFilter(filterName = "HelloFilter",value = {"/*"},initParams ={
@WebInitParam(name = "age",value = "13"),
@WebInitParam(name = "email",value = "33@163.com")},
dispatcherTypes = {DispatcherType.REQUEST,DispatcherType.FORWARD}
) 
4、@WebListener:配置监听器,
此注解是用来声明监听器,它主要的属性只有一个:
value:这个属性表示的是监听器的描述信息,整个配置可以简写成@WebListener("XXX")

package com.tjetc.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("contextInitialized");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("contextDestroyed");
}
}
