Loading

JavaWeb学习总结(十五)--过滤器的应用

  一、解决全站字符乱码(post和get中文编码问题)

乱码问题:

  •  获取请求参数中的乱码问题;
  1. POST请求:request.setCharacterEncoding(“utf-8”);
  2. GET请求:new String(request.getParameter(“xxx”).getBytes(“iso-8859-1”), “utf-8”);
  • 响应的乱码问题:
  1. response.setContextType(“text/html;charset=utf-8”)

使用Decorator模式包装request对象解决get和post请求方式下的中文乱码问题

  编写一个用于处理中文乱码的过滤器CharacterEncodingFilter,代码如下:

 1 package cn.zy.filter;
 2 
 3 import java.io.IOException;
 4 import javax.servlet.Filter;
 5 import javax.servlet.FilterChain;
 6 import javax.servlet.FilterConfig;
 7 import javax.servlet.ServletException;
 8 import javax.servlet.ServletRequest;
 9 import javax.servlet.ServletResponse;
10 import javax.servlet.http.HttpServletRequest;
11 import javax.servlet.http.HttpServletRequestWrapper;
12 import javax.servlet.http.HttpServletResponse;
13 
14 public class CharacterEncodingFilter implements Filter {
15     private FilterConfig filterConfig = null;
16     //设置默认的字符编码
17     private String defaultCharset = "UTF-8";
18 
19     public void doFilter(ServletRequest req, ServletResponse resp,
20             FilterChain chain) throws IOException, ServletException {
21         HttpServletRequest request = (HttpServletRequest)req;
22         HttpServletResponse response = (HttpServletResponse) resp;
23         //得到在web.xml中配置的字符编码
24         String charset = filterConfig.getInitParameter("charset");
25         if(charset==null){
26             charset = defaultCharset;
27         }
28         request.setCharacterEncoding(charset);
29         response.setCharacterEncoding(charset);
30         response.setContentType("text/html;charset="+charset);
31         
32         //使用得到加强的request
33         EncodingRequest requestWrapper = new EncodingRequest(request);
34          chain.doFilter(requestWrapper, response);
35     }
36 
37     public void init(FilterConfig filterConfig) throws ServletException {
38         this.filterConfig = filterConfig;
39 
40     }
41     
42     public void destroy() {
43     }
44     
45     /*
46      * 写一个装饰类增强HttpServletRequest对象
47      */
48      class EncodingRequest extends HttpServletRequestWrapper {
49         //定义一个变量记住被增强对象(request对象是需要被增强的对象)
50         private HttpServletRequest request;
51         //定义一个构造函数,接收被增强对象
52         public EncodingRequest(HttpServletRequest request) {
53             super(request);
54             this.request = request;
55         }
56         /* 覆盖需要增强的getParameter方法
57          * @see javax.servlet.ServletRequestWrapper#getParameter(java.lang.String)
58          */
59         @Override
60         public String getParameter(String name) {
61             try{
62                 //获取参数的值
63                 String value= this.request.getParameter(name);
64                 if(value==null){
65                     return null;
66                 }
67                 //如果不是以get方式提交数据的,就直接返回获取到的值
68                 if(!this.request.getMethod().equalsIgnoreCase("get")) {
69                     return value;
70                 }else{
71                     //如果是以get方式提交数据的,就对获取到的值进行转码处理
72                     value = new String(value.getBytes("ISO8859-1"),this.request.getCharacterEncoding());
73                     return value;
74                 }
75             }catch (Exception e) {
76                 throw new RuntimeException(e);
77             }
78         }
79     }
80 }

在web.xml文件中配置Filter

<filter>
      <filter-name>CharacterEncodingFilter</filter-name>
      <filter-class>cn.zy.filter.CharacterEncodingFilter</filter-class>
      <init-param>
          <param-name>name</param-name>
          <param-value>UTF-8</param-value>
      </init-param>
  </filter>
  <filter-mapping>
      <filter-name>CharacterEncodingFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>

编写一个测试的用的jsp提交表单

 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 3 <%
 4 String path = request.getContextPath();
 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 6 %>
 7 
 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 9 <html>
10   <head>
11     <base href="<%=basePath%>">
12     
13     <title>My JSP 'index.jsp' starting page</title>
14     <meta http-equiv="pragma" content="no-cache">
15     <meta http-equiv="cache-control" content="no-cache">
16     <meta http-equiv="expires" content="0">    
17     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
18     <meta http-equiv="description" content="This is my page">
19     <!--
20     <link rel="stylesheet" type="text/css" href="styles.css">
21     -->
22   </head>
23   
24   <body>
25     <form action="<c:url value='/Aservlet'/>" method="post">
26     用户名: <input type="text" name="username">
27   <input type="submit" value="提交"/>  
28    </form>
29    <a href="<c:url value='/Aservlet?username=张三'/>">点击这里</a><br/>
30   </body>
31 </html>

编写一个Servlet用于处理请求

 1 package cn.zy.filter;
 2 
 3 import java.io.IOException;
 4 import java.io.PrintWriter;
 5 
 6 import javax.servlet.ServletException;
 7 import javax.servlet.http.HttpServlet;
 8 import javax.servlet.http.HttpServletRequest;
 9 import javax.servlet.http.HttpServletResponse;
10 
11 public class Aservlet extends HttpServlet {
12 
13     /**
14      * The doGet method of the servlet. <br>
15      *
16      * This method is called when a form has its tag value method equals to get.
17      * 
18      * @param request the request send by the client to the server
19      * @param response the response send by the server to the client
20      * @throws ServletException if an error occurred
21      * @throws IOException if an error occurred
22      */
23     public void doGet(HttpServletRequest request, HttpServletResponse response)
24             throws ServletException, IOException {
25         String username = request.getParameter("username");
26          //获取请求方式
27        String method = request.getMethod();
28        response.getWriter().print("请求方式" +method+"参数:"+username);    
29     }
30 
31     
32     public void doPost(HttpServletRequest request, HttpServletResponse response)
33             throws ServletException, IOException {
34         doGet(request, response);
35     }
36 
37 }

 

二、统计每个访问次数

写一个监听器,在服务启动时创建一个map,用于保存访问IP和次数

 1 package cn.zy.listener;
 2 
 3 import java.util.LinkedHashMap;
 4 import java.util.Map;
 6 import javax.servlet.ServletContext;
 7 import javax.servlet.ServletContextEvent;
 8 import javax.servlet.ServletContextListener;
 9 
10 public class CreateMapListener implements ServletContextListener {
11 
12     public void contextInitialized(ServletContextEvent sce) {
13         /*
14          * 在服务器启动时创建map
15          */
16         Map<String,Integer> map = new LinkedHashMap<String,Integer>();
17         //得到ServletContext
18         ServletContext application = sce.getServletContext();
19         //把Map保存到ServletContext中
20         application.setAttribute("map", map);
21     }
22     
23     public void contextDestroyed(ServletContextEvent sce) {
24 
25     }
26 
27 }

创建一个Filter用于统计访问次数

package cn.zy.filter;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/*
 * 获取某个IP访问本站的次数
 */
public class AccessCountFilter implements Filter {
    private FilterConfig config;

    public void destroy() {
    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        //1. 得到appliction
        ServletContext app = config.getServletContext();
        //2.从application中获取map
        Map<String,Integer> map = (Map<String, Integer>) app.getAttribute("map");
        //3.获取客户端的地址
        String ip = request.getRemoteAddr();
        /*
         * 4.进行判断IP是否是第一次访问,如果不是则加1,如果是则设置为1
         */
        if(map.containsKey(ip)){
            int cnt = map.get(ip);
            map.put(ip, cnt+1);
        }else{
            map.put(ip, 1);
        }
        //5.把map重新放回到app中
        app.setAttribute("map", map);
        //6.放行
        chain.doFilter(request, response);
    }

    public void init(FilterConfig filterConfig) throws ServletException {
        this.config=filterConfig;

    }

}

web.xml中的配置:

<filter>
      <filter-name>AccessCountFilter</filter-name>
      <filter-class>cn.zy.filter.AccessCountFilter</filter-class>
  </filter>
  <filter-mapping>
      <filter-name>AccessCountFilter</filter-name>
      <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
 <!-- 配置Listener -->
 <listener>
    <listener-class>cn.zy.listener.CreateMapListener</listener-class>
  </listener>

创建一个jsp用于显示

 1 <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
 2 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 3 <%
 4 String path = request.getContextPath();
 5 String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 6 %>
 7 
 8 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 9 <html>
10   <head>
11     <base href="<%=basePath%>">
12     
13     <title>My JSP 'show.jsp' starting page</title>
14     
15     <meta http-equiv="pragma" content="no-cache">
16     <meta http-equiv="cache-control" content="no-cache">
17     <meta http-equiv="expires" content="0">    
18     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
19     <meta http-equiv="description" content="This is my page">
20     <!--
21     <link rel="stylesheet" type="text/css" href="styles.css">
22     -->
23 
24   </head>
25   
26   <body>
27    <h1 align="center">显示结果</h1>
28 <table align="center" width="60%" border="1">
29     <tr>
30         <th>IP</th>
31         <th>次数</th>
32     </tr>
33 <c:forEach items="${applicationScope.map }" var="entry">
34     <tr>
35         <td>${entry.key }</td>
36         <td>${entry.value }</td>
37     </tr>
38 </c:forEach>
39 </table>
40   </body>
41 </html>

结果如下图所示:

 

三、粗粒度权限控制(控制页面的访问权限)

目的:

我们给出三个页面:index.jsp、user.jsp、admin.jsp。

l  index.jsp:谁都可以访问,没有限制;

l  user.jsp:只有登录用户才能访问;

l  admin.jsp:只有管理员才能访问。

 

创建一个登陆界面,用于提交表单

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'login.jsp' starting page</title>
    
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>
  
  <body>
    <h1>登录</h1>
    ${msg }
    <form action="<c:url value='/LoginServlet' />" method="post">
    用户名:<input type="text" name="username" /><br>
   密码:<input type="password" name="password" /> <br>
   <input type="submit" value="提交">
    </form>
  </body>
</html>

2.创建一个Servlet处理表单

package cn.zy.web.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        response.setContentType("text/html;charset=utf-8");
        
        /*
         * 1.获取用户名
         * 2.如果含有admin则是管理员
         * 3.如果不包含则为普通用户
         */
        
        String username = request.getParameter("username");
        if(username.contains("admin")){
            request.getSession().setAttribute("admin", username);
        }else{
            request.getSession().setAttribute("username", username);
        }
        request.getRequestDispatcher("/index.jsp").forward(request, response);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request,response);
    }

}

2.创建一个jsp,用于链接到不同的页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">
    
    <title>My JSP 'index.jsp' starting page</title>
    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->
  </head>
  
  <body>
   <h1>你就是个游客而已</h1>
<a href="<c:url value='/index.jsp'/>">游客入口</a><br/>
<a href="<c:url value='/users/u.jsp'/>">会员入口</a><br/>
<a href="<c:url value='/admin/a.jsp'/>">管理员入口</a><br/>
  </body>
</html>

3.创建两个jsp,内容就是普通用户能访问的页面和管理员才能访问的页面

 

4.做两个过滤器,用于权限控制

AdminFilter

package cn.zy.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class AdminFilter implements Filter {

    public void destroy() {

    }

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        //得到Session
        HttpServletRequest req = (HttpServletRequest)request;
        String name = (String)req.getSession().getAttribute("admin");
        if(name != null){
            chain.doFilter(request, response);
        }else{
            req.setAttribute("msg", "您不是管理员!");
            req.getRequestDispatcher("/login.jsp").forward(request, response);
        }
    }

    public void init(FilterConfig arg0) throws ServletException {
    }
}

UserFilter

package cn.zy.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

public class UserFilter implements Filter {
    
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }
    
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        
        HttpServletRequest req = (HttpServletRequest) request;
        String name = (String)req.getSession().getAttribute("admin");
        if(name != null) {
            chain.doFilter(request, response);
            return;
        } 
        
        name = (String)req.getSession().getAttribute("username");
        if(name != null){
            chain.doFilter(request, response);
        }else{
            req.setAttribute("msg", "您不是管理员也不是会员!");
            req.getRequestDispatcher("/login.jsp").forward(request, response);
        }

    }

    public void destroy() {
    }

}

web.xml中的配置

<filter>
    <display-name>UserFilter</display-name>
    <filter-name>UserFilter</filter-name>
    <filter-class>cn.zy.filter.UserFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>UserFilter</filter-name>
    <url-pattern>/users/*</url-pattern>
  </filter-mapping>
  <filter>
    <display-name>AdminFilter</display-name>
    <filter-name>AdminFilter</filter-name>
    <filter-class>cn.zy.filter.AdminFilter</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>AdminFilter</filter-name>
    <url-pattern>/admin/*</url-pattern>
  </filter-mapping>

 

四、 response增强案例——缓存数据到内存

对于页面中很少更新的数据,例如商品分类,为避免每次都要从数据库查询分类数据,因此可把分类数据缓存在内存或文件中,以此来减轻数据库压力,提高系统响应速度。

  编写缓存数据的过滤器,代码如下:

package cn.zy.filter;


import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class WebResourceCachedFilter implements Filter {
    /**
    * @Field: map
    *          缓存Web资源的Map容器
    */ 
    private Map<String,byte[]> map = new HashMap<String,byte[]>();
    
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        response.setCharacterEncoding("utf-8"); 
        //1.得到用户请求的uri
        String uri = request.getRequestURI();
        //2.看缓存中有没有uri对应的数据
        byte b[] = map.get(uri);
        //3.如果缓存中有,直接拿缓存的数据打给浏览器,程序返回
        if(b!=null){
            //根据字节数组和指定的字符编码构建字符串
            String webResourceHtmlStr = new String(b,response.getCharacterEncoding());
            System.out.println(webResourceHtmlStr);
            response.getOutputStream().write(b);
            return;
        }
        //4.如果缓存没有,让目标资源执行,并捕获目标资源的输出
        BufferResponse myresponse = new BufferResponse(response);
        chain.doFilter(request, myresponse);
        //获取缓冲流中的内容的字节数组
        byte out[] = myresponse.getBuffer();
        //5.把资源的数据以用户请求的uri为关键字保存到缓存中
        map.put(uri, out);
        //6.把数据打给浏览器
        response.getOutputStream().write(out);
    }

    public void destroy() {

    }

    class BufferResponse extends HttpServletResponseWrapper{
        private ByteArrayOutputStream bout = new ByteArrayOutputStream();  //捕获输出的缓存
        private PrintWriter pw;
        private HttpServletResponse response;
        public BufferResponse(HttpServletResponse response) {
            super(response);
            this.response = response;
        }
        @Override
        public ServletOutputStream getOutputStream() throws IOException {
            return new MyServletOutputStream(bout);
        }
        @Override
        public PrintWriter getWriter() throws IOException {
            pw = new PrintWriter(new OutputStreamWriter(bout,this.response.getCharacterEncoding()));
            return pw;
        }
        
        public byte[] getBuffer(){
            try{
                if(pw!=null){
                    pw.close();
                }
                return bout.toByteArray();
            }catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    class MyServletOutputStream extends ServletOutputStream{
        private ByteArrayOutputStream bout;
        public MyServletOutputStream(ByteArrayOutputStream bout){  //接收数据写到哪里
            this.bout = bout;
        }
        @Override
        public void write(int b) throws IOException {
            bout.write(b);
        }
    }
}

在web.xml中配置Web资源缓存过滤器

<filter>
       <description>Web资源缓存过滤器</description>
      <filter-name>WebResourceCachedFilter</filter-name>
      <filter-class>cn.zy.filter.WebResourceCachedFilter</filter-class>
  </filter>
  
  <filter-mapping>
      <filter-name>WebResourceCachedFilter</filter-name>
      <!-- 映射需要缓存输出的JSP页面,这几个页面都只是单纯作为输入UI,不会有太多的变化,因此可以缓存输出 -->
      <url-pattern>/login.jsp</url-pattern>
      <url-pattern>/test.jsp</url-pattern>
      <url-pattern>/test2.jsp</url-pattern>
  </filter-mapping>

 

posted @ 2016-12-12 17:19  头痛不头痛  阅读(424)  评论(0编辑  收藏  举报