加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

[javaweb]Java过滤器与包装设计模式的实用案例.

发布时间:2020-12-14 06:16:35 所属栏目:Java 来源:网络整理
导读:在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求。 当某个对象的方法不适应业务需求时,通常有2种方式可以对方

在filter中可以得到代表用户请求和响应的request、response对象,因此在编程中可以使用Decorator(装饰器)模式对request、response对象进行包装,再把包装对象传给目标资源,从而实现一些特殊需求。

  当某个对象的方法不适应业务需求时,通常有2种方式可以对方法进行增强:

  1. 编写子类,覆盖需增强的方法。
  2. 使用Decorator设计模式对方法进行增强。

  在阎宏博士的《JAVA与模式》一书中开头是这样描述装饰(Decorator)模式的:装饰模式又名包装(Wrapper)模式。装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

  那么在实际应用中遇到需增强对象的方法时,到底选用哪种方式比较好呢?这个没有具体的定式,只能是根据具体的需求来采用具体的方式,不过有一种情况下,必须使用Decorator设计模式:即被增强的对象,开发人员只能得到它的对象,无法得到它的class文件。比如request、response对象,开发人员之所以在servlet中能通过sun公司定义的HttpServletRequestresponse接口去操作这些对象,是因为Tomcat服务器厂商编写了request、response接口的实现类。web服务器在调用servlet时,会用这些接口的实现类创建出对象,然后传递给servlet程序。此种情况下,由于开发人员根本不知道服务器厂商编写的request、response接口的实现类是哪个?在程序中只能拿到服务器厂商提供的对象,因此就只能采用Decorator设计模式对这些对象进行增强。

  1.首先看需要被增强对象继承了什么接口或父类,编写一个类也去继承这些接口或父类。  2.在类中定义一个变量,变量类型即需增强对象的类型。  3.在类中定义一个构造函数,接收需增强的对象。  4.覆盖需增强的方法,编写增强的代码。

  Servlet API 中提供了一个request对象的Decorator设计模式的默认实现类HttpServletRequestWrapper,HttpServletRequestWrapper 类实现了request 接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 request 对象的对应方法,以避免用户在对request对象进行增强时需要实现request接口中的所有方法。

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

CharacterEncodingFilter FilterConfig filterConfig = String defaultCharset = "UTF-8" FilterChain chain) HttpServletRequest request = HttpServletResponse response = String charset = filterConfig.getInitParameter("charset" (charset== charset = response.setContentType("text/html;charset="+ MyCharacterEncodingRequest requestWrapper = init(FilterConfig filterConfig) .filterConfig = MyCharacterEncodingRequest .request = String value= (value== (!.request.getMethod().equalsIgnoreCase("get" } value = String(value.getBytes("ISO8859-1"), } }

??? 在web.xml文件中配置CharacterEncodingFilter:

CharacterEncodingFilter >me.gacl.web.filter.CharacterEncodingFilter> CharacterEncodingFilter

???? 编写jsp测试页面,如下:

<%@ page language="java" pageEncoding="UTF-8"%> <%--引入jstl标签库 --%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> 使用字符过滤器解决解决get、post请求方式下的中文乱码问题 <%--使用c:url标签构建url,构建好的url存储在servletDemo1变量中--%> <%--构建的url的附带的中文参数 ,参数名是:username,值是:孤傲苍狼--%> <%--使用get的方式访问 --%>
<%--使用post方式提交表单 --%>
用户名:

  编写处理用户请求的ServletDemo1

ServletDemo1 String username = request.getParameter("username" String method = PrintWriter out = out.write("请求的方式:"+ out.write("
" out.write("接收到的参数:"+ }

  这样,无论是get请求方式还是post请求方式,中文乱码问题都可以完美解决了。

  编写一个html转义过滤器,代码如下:

HtmlFilter FilterChain chain) HttpServletRequest request = HttpServletResponse response = MyHtmlRequest myrequest = init(FilterConfig filterConfig) MyHtmlRequest .request = String value = (value == (message == content[] = message.getChars(0,message.length(),content,0 StringBuffer result = StringBuffer(content.length + 50 ( i = 0; i < content.length; i++ '<' result.append("&lt;" '>' result.append("&gt;" '&' result.append("&amp;" '"' result.append("&quot;" }

  在web.xml文件中配置HtmlFilter

HtmlFilter >me.gacl.web.filter.HtmlFilter> HtmlFilter

  编写jsp测试页面,如下:

<%@ page language="java" ="java.util.*" pageEncoding="UTF-8"%> html过滤器测试

  编写处理用户请求的ServletDemo2

ServletDemo2 String message = request.getParameter("message" response.getWriter().write("您上次的留言是:
" + }

  这样,所有的html标签都被转义输出了。

  编写一个敏感字符过滤器,代码如下:

DirtyFilter FilterConfig config = init(FilterConfig filterConfig) .config = FilterChain chain) HttpServletRequest request = HttpServletResponse response = DirtyRequest dirtyrequest = List List dirtyWords = ArrayList String dirtyWordPath = config.getInitParameter("dirtyWord" InputStream inputStream = InputStreamReader is = is = InputStreamReader(inputStream,"UTF-8" } BufferedReader reader = ((line = reader.readLine())!= ) { } DirtyRequest List dirtyWords = .request = String value = (value== System.out.println("内容中包含敏感词:"+dirtyWord+",将会被替换成****" value = value.replace(dirtyWord,"****" }

  在web.xml文件中配置DirtyFilter

DirtyFilter >me.gacl.web.filter.DirtyFilter> dirtyWord /WEB-INF/DirtyWord.txt DirtyFilter

????? 当用户填写的内容包含一些敏感字符时,在DirtyFilter过滤器中就会将这些敏感字符替换掉。

  我们如果将上述的CharacterEncodingFilter、HtmlFilter、DirtyFilter这三个过滤器联合起来使用,那么就相当于是把request对象包装了3次,request对象的getParameter方法经过3次重写,使得getParameter方法的功能大大增强,可以同时解决中文乱码,html标签转义,敏感字符过滤这些需求。

  在实际开发中完全可以将上述的三个过滤器合并成一个,让合并后的过滤器具有解决中文乱码,html标签转义,敏感字符过滤这些功能,例如:

AdvancedFilter FilterConfig filterConfig = String defaultCharset = "UTF-8" init(FilterConfig filterConfig) .filterConfig = FilterChain chain) HttpServletRequest request = HttpServletResponse response = String charset = filterConfig.getInitParameter("charset" (charset== charset = response.setContentType("text/html;charset="+ AdvancedRequest requestWrapper = AdvancedRequest List dirtyWords = .request = String value= (value== (!.request.getMethod().equalsIgnoreCase("get" value= } value = String(value.getBytes("ISO8859-1"), value= System.out.println("内容中包含敏感词:"+dirtyWord+",将会被替换成****" value = value.replace(dirtyWord,"****" } (value == content[] = value.getChars(0,value.length(),0 StringBuffer result = StringBuffer(content.length + 50 ( i = 0; i < content.length; i++ '<' result.append("&lt;" '>' result.append("&gt;" '&' result.append("&amp;" '"' result.append("&quot;" List List dirtyWords = ArrayList String dirtyWordPath = filterConfig.getInitParameter("dirtyWord" InputStream inputStream = InputStreamReader is = is = } BufferedReader reader = ((line = reader.readLine())!= ) { } }

  在web.xml文件中配置AdvancedFilter

AdvancedFilter >me.gacl.web.filter.AdvancedFilter> charset UTF-8 dirtyWord /WEB-INF/DirtyWord.txt AdvancedFilter

  AdvancedFilter过滤器同时具有解决中文乱码,转义内容中的html标签,过滤内容中的敏感字符这些功能。

  Servlet? API 中提供了response对象的Decorator设计模式的默认实现类HttpServletResponseWrapper ,HttpServletResponseWrapper类实现了response接口中的所有方法,但这些方法的内部实现都是仅仅调用了一下所包装的的 response对象的对应方法,以避免用户在对response对象进行增强时需要实现response接口中的所有方法。

  应用HttpServletResponseWrapper对象,压缩响应正文内容。

  具体思路:通过filter向目标页面传递一个自定义的response对象。在自定义的response对象中,重写getOutputStream方法和getWriter方法,使目标资源调用此方法输出页面内容时,获得的是我们自定义的ServletOutputStream对象。在我们自定义的ServletOuputStream对象中,重写write方法,使写出的数据写出到一个buffer中。当页面完成输出后,在filter中就可得到页面写出的数据,从而我们可以调用GzipOuputStream对数据进行压缩后再写出给浏览器,以此完成响应正文件压缩功能。

  编写压缩过滤器,代码如下:

GzipFilter HttpServletRequest request = HttpServletResponse response = BufferResponse myresponse = out[] = System.out.println("原始大小:" + ByteArrayOutputStream bout = GZIPOutputStream gout = gzip[] = System.out.println("压缩后的大小:" + response.setHeader("content-encoding","gzip" init(FilterConfig filterConfig) BufferResponse ByteArrayOutputStream bout = .response = ServletOutputStream getOutputStream() PrintWriter getWriter() pw = PrintWriter( OutputStreamWriter(bout, (pw!= (bout!= } MyServletOutputStream .bout = write( b) }

  在web.xml中配置压缩过滤器:

配置压缩过滤器 GzipFilter >me.gacl.web.filter.GzipFilter> GzipFilter *.jsp FORWARD REQUEST GzipFilter *.js GzipFilter *.css GzipFilter *.html

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

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

WebResourceCachedFilter Map[]> map = HashMap[]> init(FilterConfig filterConfig) FilterChain chain) HttpServletRequest request = HttpServletResponse response = String uri = b[] = (b!= String webResourceHtmlStr = BufferResponse myresponse = out[] = BufferResponse ByteArrayOutputStream bout = ByteArrayOutputStream(); .response = ServletOutputStream getOutputStream() PrintWriter getWriter() pw = PrintWriter( OutputStreamWriter(bout, (pw!= } MyServletOutputStream MyServletOutputStream(ByteArrayOutputStream bout){ .bout = write( b) }

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

Web资源缓存过滤器 WebResourceCachedFilter >me.gacl.web.filter.WebResourceCachedFilter> WebResourceCachedFilter /login.jsp /test.jsp /test2.jsp

?3.3、禁止浏览器缓存所有动态页面

有3 个HTTP 响应头字段都可以禁止浏览器缓存当前页面,它们在 Servlet 中的示例代码如下:

1 response.setDateHeader("Expires",-1); 2 response.setHeader("Cache-Control","no-cache"); 3 response.setHeader("Pragma","no-cache");

  并不是所有的浏览器都能完全支持上面的三个响应头,因此最好是同时使用上面的三个响应头。

  • Expires数据头:值为GMT时间值,为-1指浏览器不要缓存页面
  • Cache-Control响应头有两个常用值:
  • no-cache指浏览器不要缓存当前页面。
  • max-age:xxx指浏览器缓存页面xxx秒。
    NoCacheFilter FilterChain chain) HttpServletRequest request = HttpServletResponse response = response.setDateHeader("Expires",-1 response.setHeader("Cache-Control","no-cache" response.setHeader("Pragma","no-cache" init(FilterConfig filterConfig) }

  web.xml文件中的配置如下:

NoCacheFilter >me.gacl.web.filter.NoCacheFilter> NoCacheFilter *.jsp

?3.4、控制浏览器缓存页面中的静态资源

有些动态页面中引用了一些图片或css文件以修饰页面效果,这些图片和css文件经常是不变化的,所以为减轻服务器的压力,可以使用filter控制浏览器缓存这些文件,以提升服务器的性能。

CacheFilter FilterChain chain) HttpServletRequest request = HttpServletResponse response = String uri = String ext = uri.substring(uri.lastIndexOf(".")+1 String time = (time!= t = Long.parseLong(time)*3600*1000 response.setDateHeader("expires",System.currentTimeMillis() + init(FilterConfig filterConfig) .filterConfig = }

  web.xml文件中的配置如下:

CacheFilter >me.gacl.web.filter.CacheFilter> css 4 jpg 1 js 4 png 4 CacheFilter *.jpg CacheFilter *.css CacheFilter *.js CacheFilter *.png

  思路是这样的:

  1、在用户登陆成功后,发送一个名称为user的cookie给客户端,cookie的值为用户名和md5加密后的密码。  2、编写一个AutoLoginFilter,这个filter检查用户是否带有名称为user的cookie来,如果有,则调用dao查询cookie的用户名和密码是否和数据库匹配,匹配则向session中存入user对象(即用户登陆标记),以实现程序完成自动登陆。

  核心代码如下:  处理用户登录的控制器:LoginServlet

LoginServlet String username = request.getParameter("username" String password = request.getParameter("password" UserDao dao = User user = (user== request.setAttribute("message","用户名或密码不对!!" request.getRequestDispatcher("/message.jsp" request.getSession().setAttribute("user" request.getRequestDispatcher("/index.jsp" (request.getParameter("logintime")!= logintime = Integer.parseInt(request.getParameter("logintime" Cookie cookie = Cookie("autologin",user.getUsername() + "." + }

  处理用户自动登录的过滤器:AutoLoginFilter

AutoLoginFilter HttpServletRequest request = HttpServletResponse response = (request.getSession().getAttribute("user")!= String value = Cookie cookies[] = ( i=0;cookies!= && i (cookies[i].getName().equals("autologin" value = (value!= String username = value.split(".")[0 String password = value.split(".")[1 UserDao dao = User user = String dbpassword = request.getSession().setAttribute("user" init(FilterConfig filterConfig) }

  如果想取消自动登录,那么可以在用户注销时删除自动登录cookie,核心代码如下:

CancelAutoLoginServlet request.getSession().removeAttribute("user" request.getRequestDispatcher("/login.jsp" Cookie cookie = Cookie("autologin","" cookie.setMaxAge(0 }

  以上就是过滤器的几个常见应用场景。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读