java EE开发之Servlet第三课:过滤器(Filter)

1.什么是Filter
过滤器是用于过滤Servlet的请求和响应,过滤器是在客户端和Servlet之间。当客户端请求某一个Servlet
的时候,请求会先进入Filter的doFilter(),开始处理,处理完成以后,调用chain.doFilter(request, response)
把request,response继续传递,让请求继续往下走,进入Servlet,在Servlet处理完成以后,又重回Filter的
doFilter(),执行chain.doFilter(request, response)下面的语句,完成以后,响应给客户端.

**注意:**Filter不会产生request和response对象,只是对request和response的值进行修改,起到一个过滤的
作用
原理图:
这里写图片描述
2,测试Filter和servlet的生命周期
(1)写一个MyServlet(实现Servlet接口),实现destroy() ,init(),service()和构造方法
(2)写一个MyFilter(实现Filte接口),实现destroy() ,init(),doFilter()和构造方法

public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException{
	System.out.println("过滤之前");
	//进到过滤,开始处理,处理完成以后,让请求继续往下走,进入Servlet
	chain.doFilter(request, response);
	//在Servlet完成以后,又重回过滤器响应给客户端
	System.out.println("过滤之后");
}

(3)web.xml配置

 <servlet>
  <servlet-name>MyServlet</servlet-name>
  <servlet-class>com.accp.servlet.MyServlet</servlet-class>
 </servlet>
 <servlet-mapping>
  <servlet-name>MyServlet</servlet-name>
  <url-pattern>/MyServlet</url-pattern>
 </servlet-mapping>

<filter>
  <!--过滤器的类  -->
  <filter-name>MyFilter</filter-name>
  <filter-class>com.accp.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
  <filter-name>MyFilter</filter-name>
  <!-- 表示只过滤MyServlet这一个servlet,其他Servlet不管 -->
  <servlet-name>MyServlet</servlet-name>
   <!-- 表示所有的请求都被过滤-->
  <url-pattern>/*</url-pattern>
</filter-mapping>

**注意:**filter是服务器启动就产生了,并且进行初始化,而servlet一定是有了请求才会出生和初 始化,从打印的结果可以看到请求先进入filter,回去的时候又从过滤器经过. 当服务器重启或者关闭,servlet先死,filter后死
2,Filter应用
(1).解决中文乱码问题(request和response)

 public void doFilter(ServletRequest req, ServletResponse res,
			FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest)req;
		HttpServletResponse response = (HttpServletResponse)res;
		if(request.getMethod().equalsIgnoreCase("post")){
			request.setCharacterEncoding("gb18030");
		}else{
			Enumeration enum = request.getParameterNames();
			while(enum.hasMoreElements()){
				String key = (String)enum.nextElement();
				String[] values = request.getParameterValues(key);
				for(int i=0;i<values.length;i++){	
				values[i]=newString(values[i].getBytes("iso8859-1"),"gb18030");
				}	
			}
		}
		//必须写在过滤之前,写在之后就会失效
		response.setContentType("text/html;charset=gb18030");
		chain.doFilter(request, response);
}

补充:上面的编码问题,出现有时候有效,有时候无效,终极解决方案:重写request(装饰者模式)

public class MyRequest extends HttpServletRequestWrapper {
    private HttpServletRequest request;
    private boolean hasEncode;
    public MyRequest(HttpServletRequest req) {
        super(req);
        this.request = req;
    }
    @Override
    public Map<String, String[]> getParameterMap() {
        // 先获得请求方式
        String method = request.getMethod();
        if (method.equalsIgnoreCase("post")) {
            // post请求
            try {
                // 处理post乱码
                request.setCharacterEncoding("utf-8");
                return request.getParameterMap();
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        } else if (method.equalsIgnoreCase("get")) {
            // get请求
            Map parameterMap = request.getParameterMap();
            if (!hasEncode) { // 确保get手动编码逻辑只运行一次
                Set<String> keySet = parameterMap.keySet();
                for (String parameterName : keySet) {
                    String[] values = (String[]) parameterMap.get(parameterName);
                    if (values != null) {
                        for (int i = 0; i < values.length; i++) {
                            try {
                                values[i] = new String(values[i].getBytes("ISO-8859-1"), "utf-8");
                            } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
                hasEncode = true;
            }
            return parameterMap;
        }
        return super.getParameterMap();
    }
    @Override
    public String[] getParameterValues(String name) {
        if(name==null) {
            return null;
        }
        return getParameterMap().get(name);
    }
    @Override
    public String getParameter(String name) {
        String[] values = getParameterMap().get(name);
        if(values==null) {
            return null;
        }
        return values[0];
    }

}

(2).解决权限问题

public void doFilter(ServletRequest req, ServletResponse resp,
			FilterChain chain) throws IOException, ServletException {
	HttpServletRequest request = (HttpServletRequest)req;
	HttpServletResponse response = (HttpServletResponse)resp;
	//得到session的值
       String role = (String)request.getSession().getAttribute("role");
	//拿到项目的路径,相当于"/项目名"
	System.out.println("-------------"+request.getContextPath());
	if(role==null || !role.equals("admin")){
		response.sendRedirect(request.getContextPath()+"/error.jsp");
	}
	chain.doFilter(request, response);
}

web.xml中配置过滤器

<filter>
     <filter-name>AdminFilter</filter-name>
     <filter-class>com.accp.filter.AdminFilter</filter-class>
    </filter>
    <filter-mapping>
     <filter-name>AdminFilter</filter-name>
     <!-- 注意路径-->
     <url-pattern>/admin/*</url-pattern>
</filter-mapping>

(3),过滤掉非法文字过滤掉非法文字
a.准备一个str.properties文件,把要过滤掉的字符,准备在里面
\u738b\u516b=

\u65e5\u672c=
***
\u6740\u624b=*****
注意这里要转码
\u738b\u516b–>王八
\u65e5\u672c–>日本
\u6740\u624b–>杀手

**b.**过滤器代码

Properties ps = null;
public void doFilter(ServletRequest req, ServletResponse resp,FilterChain chain) throws IOException, 	ServletException {
      HttpServletRequest request = (HttpServletRequest)req;
      HttpServletResponse response = (HttpServletResponse)resp;
      //注意中文乱码的设置
      request.setCharacterEncoding("gb18030");
      Enumeration enum =  request.getParameterNames();
      while(enum.hasMoreElements()){
	    String key = (String)enum.nextElement();
	    String[] values = request.getParameterValues(key);
	    for (int i = 0; i < values.length; i++) {		
			//根据key,从properties中拿到值,如果不为空,则证明一定有非法字符
			//然后替换掉
			 if(ps.get(values[i])!=null){
				values[i] = ps.getProperty(values[i]);
			 }
		 }	
	   }
	   chain.doFilter(request, response);
}
//初始化中读取str.properties文件
public void init(FilterConfig filterConfig) throws ServletException {
	try {
		//读取str.properties文件
	        InputStream in = filterConfig.getServletContext().getResourceAsStream("/WEB-
							        INF/str.properties");
			ps = new Properties();
			ps.load(in);//加载配置文件
			in.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

4,dispatcher的作用
2.4版本的servlet规范在部属描述符中新增加了一个元素,这个元素有四个可能的值:即REQUEST,FORWARD,INCLUDE和ERROR,可以在一个元素中加入任意数目的,使得filter将会作用于直接从客户端过来的request,通过forward过来的request,通过include过来的request和通过过来的request。如果没有指定任何< dispatcher >元素,默认值是REQUEST。可以通过下面几个例子来辅助理解。

dispacher的配置值中 :默认是:REQUEST

REQUEST:直接从浏览器过来的请求都会过滤过来
FORWARD:通过转发请求指定资源
INCLUDE:通过包含的方式的请求(静态包含不包括)
ERROR:如果请求是通过发起的 就过滤

testFilter.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
	//forward:转发:FORWARD会过滤该请求
	request.getRequestDispatcher("MyServlet").forward(request,response);
	//ERROR:如果请求是通过<error-page>发起的 就过滤
	//会跳转到web.xml中error-page的指向的页面
	System.out.println(10/0);
%>
<!-- jsp指定的转发 -->
<!-- 静态包含: -->
<%@include file="show.jsp"%>--%>
<!-- 动态包含:INCLUDE 通过包含的方式的请求(静态包含不包括) -->
<%--<jsp:include page="show.jsp"></jsp:include>--%>

web.xml中核心的配置

.....
<filter-mapping>	
  	<filter-name>MyFilter</filter-name>
  	<!-- 所有请求的都必须过滤 -->
  	<url-pattern>/*</url-pattern>
  	<!-- 指定某个请求资源才过滤 -->
  	<!--<servlet-name>MyServlet</servlet-name>-->
  	
  	<!-- 面试要用的配置:REQUEST FORWARD INCLUDE ERROR
  		默认是:REQUEST
  		REQUEST:所有请求都会过滤过来
  		FORWARD:通过转发请求指定资源
  		INCLUDE:通过包含的方式的请求(静态包含不包括)
  		ERROR:如果请求是通过<error-page>发起的 就过滤
  	 -->
  	<dispatcher>ERROR</dispatcher>
  </filter-mapping>
  .....
  <!--error-page发起的请求-->
 <error-page>
  	<error-code>500</error-code>
  	<location>/error.jsp</location>
  </error-page>
  
  <error-page>
  	<exception-type>java.lang.Exception</exception-type>
  	<location>/error.jsp</location>
  </error-page>
发布了26 篇原创文章 · 获赞 13 · 访问量 7027

猜你喜欢

转载自blog.csdn.net/womeia331416/article/details/78040985
今日推荐