过滤器如何编写?
1.写一个类实现Filter接口
2.在web.xml中进行配置
Filter接口:
public void init(FilterConfig filterConfig)
创建之后,马上执行;Filter会在服务器启动时就创建!
public void destroy():
销毁之前执行!在服务器关闭时销毁
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
每次过滤时都会执行
Filter是单例的
web.xml配置
<filter>
<filter-name>xxx</fi1ter-name>T
<filter-class>cn.itcast.web.filter.AFitler</fitler-class>
</servlet>
<fitler-mapping>
<filter-name>xxx</filter-name>
只要碰到AServlet就拦截
<url-pattern>/Aservlet</url-pattern>
</filter-mapping>
举例:
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">
<servlet>
<servlet-name>AServlet</servlet-name>
<servlet-class>cn.itcast.web.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>AServlet</filter-name>
<filter-class>cn.itcast.web.filter.AFilite</filter-class>
</filter>
<filter-mapping>
<filter-name>AServlet</filter-name>
<url-pattern>/AServlet</url-pattern>
</filter-mapping>
</web-app>
AServlet:
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("AServlet......");
}
}
AFilter:
public class AFilite implements Filter {
/**
*
* @param filterConfig
* @throws ServletException
*
* 创建之后马上执行,用来做初始化
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("过滤器初始化");
}
/**
*
* @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("拦截你");
}
/**
* 销毁之前,用来做对非内存资源进行释放
*/
@Override
public void destroy() {
System.out.println("过滤器销毁");
}
}
这个过滤器屏蔽了AServlet路径访问
多个过滤器
AServlet:
public class AServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("AServlet......");
}
}
AFilter:
public class AFilite implements Filter {
/**
*
* @param filterConfig
* @throws ServletException
*
* 创建之后马上执行,用来做初始化
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("AFilite过滤器初始化");
}
/**
*
* @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("AFilter拦截你");
filterChain.doFilter(servletRequest,servletResponse);//放行,不再拦截
System.out.println("AFilite回来了");
}
/**
* 销毁之前,用来做对非内存资源进行释放
*/
@Override
public void destroy() {
System.out.println("过滤器销毁");
}
}
BFilter:
public class BFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("BFilter拦截你");
chain.doFilter(req,resp);//放行
System.out.println("BFilter回来了");
}
public void init(FilterConfig config) throws ServletException {
System.out.println("BFilter过滤器初始化");
}
}
web.xml:
<servlet>
<servlet-name>AServlet</servlet-name>
<servlet-class>cn.itcast.web.servlet.AServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>AServlet</servlet-name>
<url-pattern>/AServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>AServlet</filter-name>
<filter-class>cn.itcast.web.filter.AFilite</filter-class>
</filter>
<filter-mapping>
<filter-name>AServlet</filter-name>
<url-pattern>/AServlet</url-pattern>
</filter-mapping>
<filter>
<filter-name>BServlet</filter-name>
<filter-class>cn.itcast.web.filter.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>BServlet</filter-name>
<url-pattern>/AServlet</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
结果:
AFilter拦截你
BFilter拦截你
AServlet......
BFilter回来了
AFilite回来了
区别
FilterConfig与ServletConfig相似:
*获取初始化参数:getInitParameter():
*获得过滤器名称:getFilterName():
*获取application:getServletContext():
FilterChain
*doFilter(ServletRequest,ServletResponse):放行!
就相当于调用了目标servlet的service()方法!
用来放行拦截器
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("拦截你");
filterChain.doFilter(servletRequest,servletResponse);//放行,不再拦截
System.out.println("回来了");
}
结果:
拦截你
AServlet......
回来了
四种拦截方式
请求 DISPATCHER
转发 FORWARD
包含 INCLUDE
错误 ERROR
在
<filter-mapping>
中进行配置
<dispatcher>REQUEST</dispatcher>默认的
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
FilterConfig接口
MyFilter03:
public class MyFilter03 implements Filter {
private String characterEncoding;
FilterConfig fc;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//输出参数信息
characterEncoding=fc.getInitParameter("encoding");
System.out.println("encoding初始化参数的值为:"+characterEncoding);
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
//获取FilterConfig对象
this.fc=config;
}
}
web.xml:
<filter>
<filter-name>MyFilter03</filter-name>
<filter-class>cn.itcast.web.filter.MyFilter03</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>GBK</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilter03</filter-name>
<url-pattern>/AServlet</url-pattern>
</filter-mapping>
结果:
AFilter拦截你
BFilter拦截你
encoding初始化参数的值为:GBK
AServlet......
BFilter回来了
AFilite回来了
过滤器的优点
• 过滤器是可插拔的。
• 一个过滤器不依赖于另一个资源。
• 维护少,比较容易维护。
• 能够过滤访问web资源的所有的请求,包括图片,样式等。(每个请求都触发一次过滤事件)
过滤器的编写原则:
a 尽量不要过滤全部 * (降低所有请求的访问效率,且容易出错)
b 在过滤器中,优先使用转发,谨慎使用重定向,因为重定向有可能再次进入过滤器,导致死循环。
过滤器的优点
要创建一个过滤器,必须要实现Filter接口。
Filter接口为过滤器提供了生命周期方法。
FilterChain接口
注解配置过滤器
注解配置时,顺序按过滤器类的类名,按字符串的排序规则。
过滤器的过滤顺序
- 如果是用web.xml配置的话,和
url-pattern有关,谁在前面谁就先过滤
- 如果使用注解配置的话,只和过滤器的类名有关,
顺序按过滤器类的类名,按字符串的排序规则。
- 如果既有web.xml和注解配置的话,web.xml配置的先过滤
案例
a 统一中文编码处理
@WebFilter("/*")
public class CFilter implements Filter {
/**
* Default constructor.
*/
public CFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
注册名检查过滤器
@WebFilter("/RegServlet")
public class RegFilter implements Filter {
/**
* Default constructor.
*/
public RegFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
private static List<String> badNames=new ArrayList<>();
static {
badNames.add("他妈的");
badNames.add("fuck");
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//1 获取请求参数
String username=((HttpServletRequest)request).getParameter("username");
if(badNames.contains(username)) {
response.getWriter().println(username+"非法,注册失败");
response.getWriter().flush();
response.getWriter().close();
return;
}
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
ip过滤器
@WebFilter("/*")
public class IPFilter implements Filter {
/**
* Default constructor.
*/
public IPFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//获取请求方ip
String ip=request.getRemoteAddr();
if(ip.startsWith("192.168")) {
response.getWriter().println("禁止192.168开头的IP访问本站");
response.getWriter().flush();
response.getWriter().close();
return;
}
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
内页访问登录校验过滤器
LoginCheckFilter:
/**
* Servlet Filter implementation class LoginCheckFilter
*/
@WebFilter("/*")
public class LoginCheckFilter implements Filter {
/**
* Default constructor.
*/
public LoginCheckFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//让两个uri白名单放行。//login.jsp,LoginServlet
HttpServletRequest req=(HttpServletRequest) request;
if(req.getRequestURI().indexOf("login.jsp")>=0
||req.getRequestURI().indexOf("LoginServlet")>=0
||!req.getSession().isNew()) {
chain.doFilter(request, response);
return;
}
request.setAttribute("msg", "请先登录");
//在过滤器中转发,不会再进入过滤器
request.getRequestDispatcher("login.jsp").forward(request, response);
// req.getSession().setAttribute("msg", "请先登录");
// ((HttpServletResponse)response).sendRedirect("login.jsp");
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}
login.jsp:
<c:if test="${not empty msg }">
${msg}<br/>
</c:if>
<!-- 让session失效 -->
<%session.invalidate(); %>
<!-- <img src="img/1.png" width="100px" height="200px"> -->
<form action="LoginServlet" method="post">
<input name="username" placeholder="username" /> <br/>
<input name="password" type="password" placeholder="password" /> <br />
<input type="submit" value="登录" />
</form>
篡改响应报文
CharResponseWrapper.java:
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
//工具类,对请求、响应流的封装,可以获取响应的报文
class CharResponseWrapper
extends HttpServletResponseWrapper
{
protected CharArrayWriter charWriter;//将响应缓存在这个写入器中
protected PrintWriter writer;
protected boolean getOutputStreamCalled;
protected boolean getWriterCalled;
public CharResponseWrapper(HttpServletResponse response)
{
super(response);
// Create the writer
charWriter = new CharArrayWriter();
}
public ServletOutputStream getOutputStream()
throws IOException
{
// Can't call getOutputStream if getWriter
// has already been called
if (getWriterCalled)
{
throw new IllegalStateException(
"getWriter already called");
}
getOutputStreamCalled = true;
return super.getOutputStream();
}
public PrintWriter getWriter()
throws IOException
{
if (writer != null)
{
return writer;
}
// Can't call getWriter if getOutputStream
// has already been called
if (getOutputStreamCalled)
{
throw new IllegalStateException(
"getOutputStream already called");
}
getWriterCalled = true;
writer = new PrintWriter(charWriter);
return writer;
}
public String toString()//将响应数据用字符串返回
{
String s = null;
// Only return a String if the writer was
// used.
if (writer != null)
{
s = charWriter.toString();
}
return s;
}
}
GetMsgServlet.java:
@WebServlet("/GetMsgServlet")
public class GetMsgServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public GetMsgServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("今天晚上警察巡逻,保护大家安全");
response.getWriter().flush();
response.getWriter().close();
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
BadResponseFilter.java:
@WebFilter("/GetMsgServlet")
public class BadResponseFilter implements Filter {
/**
* Default constructor.
*/
public BadResponseFilter() {
// TODO Auto-generated constructor stub
}
/**
* @see Filter#destroy()
*/
public void destroy() {
// TODO Auto-generated method stub
}
/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
//使用新的响应流对象,代替原来的response的对象
CharResponseWrapper crw=new CharResponseWrapper((HttpServletResponse)response);
chain.doFilter(request, crw);
String newHtml=crw.toString().replace("警察", "jc");
response.getWriter().println(newHtml);
response.getWriter().flush();
response.getWriter().close();
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
}