filter在开发中的常见应用:
* 1.filter可以目标资源执行之前,进行权限检查,检查用户有无权限,如有权限则放行,如没有,则拒绝访问
* 2.filter可以放行之前,对request和response进行预处理,从而实现一些全局性的设置。
* 3.filter在放行之后,可以捕获到目标资源的输出,从而对输出作出类似于压缩这样的设置
一、解决全网站的乱码:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; request.setCharacterEncoding("UTF-8"); //这个编码只能解决Post提交,不能解决get方式的提交,所以需要对request中getParameter //方法增强 response.setCharacterEncoding("UTF-8"); response.setContentType("text/html;charset=UTF-8"); chain.doFilter(new MyRequest(request), response); //request.getparameter("password"); } /* 1.写一个类,实现与被增强对象相同的接口 2.定义一个变量,记住被增强对象 3.定义一个构造方法,接收被增强对象 4.覆盖想增强的方法 5.对于不想增强的方法,直接调用被增强对象(目标对象)的方法 */ class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } @Override public String getParameter(String name) { String value = this.request.getParameter(name); if(!request.getMethod().equalsIgnoreCase("get")){ return value; } if(value==null){ return null; } try { return value = new String(value.getBytes("iso8859-1"),request.getCharacterEncoding()); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } }
二,实现自动登录
实现用户自动登陆的过滤器
在用户登陆成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和md5加密后的密码。编写一个AutoLoginFilter,这个filter检查用户是否带有名称为user的cookie来,如果有,则调用dao查询cookie的用户名和密码是否和数据库匹配,匹配则向session中存入user对象(即用户登陆标记),以实现程序完成自动登陆。
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //1.先检查用户是否已登陆,没登陆才自动登陆 User user = (User) request.getSession().getAttribute("user"); if(user!=null){ chain.doFilter(request, response); return; } //2.没登陆,再执行自动登陆逻辑 //看用户有没有带自动登陆的cookie Cookie autoLoginCookie = null; Cookie cookies[] = request.getCookies(); for(int i=0;cookies!=null && i<cookies.length;i++){ if(cookies[i].getName().equals("autologin")){ autoLoginCookie = cookies[i]; } } if(autoLoginCookie==null){ chain.doFilter(request, response); return; } //用户带了自动登陆的cookie,则先检查cookie的有效期 String values[] = autoLoginCookie.getValue().split("\\:"); if(values.length!=3){ chain.doFilter(request, response); return; } long expirestime = Long.parseLong(values[1]); if(System.currentTimeMillis()>expirestime){ chain.doFilter(request, response); return; } //代表cookie时间有效,再检查cookie的有效性 String username = values[0]; String client_md5 = values[2]; BusinessService service = new BusinessService(); user = service.findUser(username); if(user==null){ chain.doFilter(request, response); return; } ////autologin=username:expirestime:md5(password:expirestime:username) String server_md5 = md5(user.getUsername(),user.getPassword(),expirestime); if(!server_md5.equals(client_md5)){ chain.doFilter(request, response); return; } //执行登陆 request.getSession().setAttribute("user", user); chain.doFilter(request, response); } private String md5(String username,String password,long expirestime){ try{ String value = password + ":" + expirestime + ":" + username; MessageDigest md = MessageDigest.getInstance("md5"); byte md5[] = md.digest(value.getBytes()); BASE64Encoder encode = new BASE64Encoder(); return encode.encode(md5); }catch (Exception e) { throw new RuntimeException(e); } }
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); BusinessService service = new BusinessService(); User user = service.login(username, password); if(user==null){ request.setAttribute("message", "用户名或密码错误!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } request.getSession().setAttribute("user", user); int expirestime = Integer.parseInt(request.getParameter("time")); //给客户机发送自动登陆的 cookie //autologin=username:expirestime:md5(password:expirestime:username) Cookie cookie = makeCookie(user, expirestime); response.addCookie(cookie); response.sendRedirect("/login/index.jsp"); } public Cookie makeCookie(User user,int expirestime){ long currenttime = System.currentTimeMillis(); String cookieValue = user.getUsername() + ":" + (currenttime+expirestime*1000) + ":" + md5(user.getUsername(), user.getPassword(), (currenttime+expirestime*1000)); Cookie cookie = new Cookie("autologin",cookieValue); cookie.setMaxAge(expirestime); cookie.setPath("/login"); return cookie; } private String md5(String username,String password,long expirestime){ try{ String value = password + ":" + expirestime + ":" + username; MessageDigest md = MessageDigest.getInstance("md5"); byte md5[] = md.digest(value.getBytes()); BASE64Encoder encode = new BASE64Encoder(); return encode.encode(md5); }catch (Exception e) { throw new RuntimeException(e); } }
三,禁止浏览器缓存所有动态页面的过滤器:
有 3 个 HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:
response.setDateHeader("Expires",-1);
response.setHeader("Cache-Control","no-cache");
response.setHeader("Pragma","no-cache");
并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。
Expires数据头:值为GMT时间值,为-1指浏览器不要缓存页面
Cache-Control响应头有两个常用值:
no-cache指浏览器不要缓存当前页面。
max-age:xxx指浏览器缓存页面xxx秒。
四,控制浏览器缓存页面中的静态资源的过滤器:
有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件经常是不变化的,所以为减轻服务器的压力,可以使用filter控制浏览器缓存这些文件,以提升服务器的性能。
private Map<String,byte[]> map = new HashMap(); public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //1.得到用户想访问的资源(uri) String uri = request.getRequestURI(); //2.看map集合中是否保存了该资源的数据 byte b[] = map.get(uri); //3.如果保存了,则直接取数据打给浏览器 if(b!=null){ response.getOutputStream().write(b); return; } //4.如果没有保存数据,则放行让目标资源执行,这时还需写一个response的包装类,捕获目标资源的输出 MyResponse my = new MyResponse(response); chain.doFilter(request, my); byte data[] = my.getBuffer(); //5.以资源uri为关键字,打资源的数据保存map集合中,以备于下次访问 map.put(uri, data); //6.输出数据给浏览器 response.getOutputStream().write(data); } class MyResponse extends HttpServletResponseWrapper{ private ByteArrayOutputStream bout = new ByteArrayOutputStream(); private PrintWriter pw; private HttpServletResponse response; public MyResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(bout); //myresponse.getOutputStream().write("hahah"); } @Override public PrintWriter getWriter() throws IOException { pw = new PrintWriter(new OutputStreamWriter(bout,response.getCharacterEncoding())); return pw; } public byte[] getBuffer(){ if(pw!=null){ pw.close(); } return bout.toByteArray(); } } 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); } }
五、使用Decorator模式包装request对象,实现html标签转义功能(Tomcat服务器中提供了转义html标签的工具类)
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; chain.doFilter(new MyRequest(request), response); //request.getParameter("resume"); //<script> } class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } @Override public String getParameter(String name) { String value = this.request.getParameter(name); if(value==null){ return null; } return filter(value); } public String filter(String message) { if (message == null) return (null); char content[] = new char[message.length()]; message.getChars(0, message.length(), content, 0); StringBuffer result = new StringBuffer(content.length + 50); for (int i = 0; i < content.length; i++) { switch (content[i]) { case '<': result.append("<"); break; case '>': result.append(">"); break; case '&': result.append("&"); break; case '"': result.append("""); break; default: result.append(content[i]); } } return (result.toString()); } }
六、压缩响应信息
服务器发给浏览器的数据时,先进行压缩,然后在发出,(注意filter要拦截的对象,都会压缩,所以要在web.xml中配置好想要拦截的对象)。
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; MyResponse myresponse = new MyResponse(response); chain.doFilter(request, myresponse); //response.getwriter response.getOutputStream //取出缓冲的数据压缩后输出 byte out[] = myresponse.getBuffer(); //得到目标资源的输出 byte gzipout[] = gzip(out); response.setHeader("content-encoding", "gzip"); response.setHeader("content-length", gzipout.length + ""); response.getOutputStream().write(gzipout); } public byte[] gzip(byte b[]) throws IOException{ ByteArrayOutputStream bout = new ByteArrayOutputStream(); GZIPOutputStream gout = new GZIPOutputStream(bout); gout.write(b); gout.close(); return bout.toByteArray(); } class MyResponse extends HttpServletResponseWrapper{ private ByteArrayOutputStream bout = new ByteArrayOutputStream(); private PrintWriter pw; private HttpServletResponse response; public MyResponse(HttpServletResponse response) { super(response); this.response = response; } @Override public ServletOutputStream getOutputStream() throws IOException { return new MyServletOutputStream(bout); //myresponse.getOutputStream().write("hahah"); } @Override public PrintWriter getWriter() throws IOException { pw = new PrintWriter(new OutputStreamWriter(bout,response.getCharacterEncoding())); return pw; } public byte[] getBuffer(){ if(pw!=null){ pw.close(); } return bout.toByteArray(); } } 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); } }
七、敏感词过滤(z注意词库中词语的格式:例如:傻逼|1 后面的1表示识别词库中的等级 ,禁用词为1,审查词为2,替换词为3)
private List<String> banWords = new ArrayList();//禁用词,例如:傻逼|1 private List<String> auditWords = new ArrayList();//审查词 例如: 中共|2 private List<String> replaceWords = new ArrayList();//替换词 例如: 色情|3 public void init(FilterConfig filterConfig) throws ServletException { try{ String path = WordsFilter.class.getClassLoader().getResource("cn/xxx/xxx").getPath();//地址表词库存放在那个包下面 File files[] = new File(path).listFiles(); for(File file : files){ if(!file.getName().endsWith(".txt")){//表示词库的后缀名文件 continue; } BufferedReader br = new BufferedReader(new FileReader(file)); String line = null; while((line=br.readLine())!=null){ String s[] = line.split("\\|"); if(s.length!=2){ continue; } if(s[1].trim().equals("1")){ banWords.add(s[0].trim()); } if(s[1].trim().equals("2")){ auditWords.add(s[0].trim()); } if(s[1].trim().equals("3")){ replaceWords.add(s[0].trim()); } } } System.out.println("haha"); }catch (Exception e) { throw new RuntimeException(e); } } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //检查提交数据是否包含禁用词 Enumeration e = request.getParameterNames(); while(e.hasMoreElements()){ String name = (String) e.nextElement(); String data = request.getParameter(name); for(String regex : banWords){ Pattern pattern = Pattern.compile(regex); Matcher m = pattern.matcher(data); if(m.find()){ request.setAttribute("message", "文章中包括非法词汇,请检查后再提交!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } } } //检查审核词 //检查替换词 chain.doFilter(new MyRequest(request), response); } class MyRequest extends HttpServletRequestWrapper{ private HttpServletRequest request; public MyRequest(HttpServletRequest request) { super(request); this.request = request; } @Override public String getParameter(String name) { String data = this.request.getParameter(name); if(data==null){ return null; } for(String regex : auditWords){//检查审核词 Pattern p = Pattern.compile(regex); Matcher m = p.matcher(data); if(m.find()){ String value = m.group(); //找出客户机提交的数据中和正则表达式相匹配的数据 data = data.replaceAll(regex, "<font color='red'>" + value + "</font>"); } } for(String regex : replaceWords){//检查替换词 Pattern p = Pattern.compile(regex); Matcher m = p.matcher(data); if(m.find()){ data = data.replaceAll(regex, "*******"); } } return data; } }