分享

项目中用到的一个小工具类(字符过滤器)

 WindySky 2007-02-02
关键字: 设计模式   字符过滤器,Decorator模式    

字符串过滤,是比较常用的功能,我的当前项目也有用到。
如过滤User输入的Html,Js代码等,
由于过滤需求是可能变动的,
如客户又要你过滤一些脏词或者为内容中的url自动加上超链接等。
考虑“开-闭”(OCP)原则,
我决定使用装饰器(Decorator)模式。
首先定义Decorator接口:

java 代码
  1. package com.sanook.hompy.util.filter;   
  2.   
  3. public interface StringFilter {   
  4.   
  5.     public void setNextStringFilter(StringFilter stringFilter); //关联下一装饰器   
  6.   
  7.     public String filter(String source); //处理过滤   
  8. }   

 

然后用模板方法(Template Method)模式实现一个抽象的过滤器:
这样可以将相同的实现部分抽象出来。

java 代码
  1. package com.sanook.hompy.util.filter;   
  2.   
  3. public abstract class AbstractStringFilter implements StringFilter {   
  4.   
  5.     private StringFilter stringFilter;   
  6.   
  7.     public void setNextStringFilter(StringFilter stringFilter) {   
  8.         this.stringFilter = stringFilter;   
  9.     }   
  10.   
  11.     public String filter(String source) {   
  12.         String target = doFilter(source);   
  13.         if (stringFilter == null) {   
  14.             return target;   
  15.         }   
  16.         return stringFilter.filter(target);   
  17.     }   
  18.   
  19.     // 模板抽象方法,传入要处理的string,返回处理完的string   
  20.     // 遵循模板方法doXXX命名方式   
  21.     public abstract String doFilter(String source);    
  22.   
  23. }   

 

空的实现:

java 代码
  1. package com.sanook.hompy.util.filter;   
  2.   
  3. public class EmptyFilter extends AbstractStringFilter {   
  4.   
  5.     public String doFilter(String source) {   
  6.         return source;   
  7.     }   
  8.   
  9. }   

 

下面实现该接口的Html过滤:

java 代码
  1. package com.sanook.hompy.util.filter;   
  2.   
  3. import org.apache.commons.lang.StringUtils;   
  4.   
  5. public class HtmlFilter extends AbstractStringFilter {   
  6.   
  7.     public String doFilter(String source) {   
  8.         source = StringUtils.replace(source, "<""& lt;");   
  9.         source = StringUtils.replace(source, ">""& gt;");   
  10.         source = StringUtils.replace(source, "&""& amp;");   
  11.         source = StringUtils.replace(source, " ""& nbsp;");   
  12.         source = StringUtils.replace(source, "\"""& #0034;");   
  13.         source = StringUtils.replace(source, "\‘""& #0039;");   
  14.         return source;   
  15.     }   
  16.   
  17. }   

 

由于Decorator是嵌套结构(注:这里只用了前(before)装饰,所以看起来有点像链结构,如有必要,也可以加上后(after)装饰),
它的调用关系需要组装,所以应该用建造者(Builder)模式或简单工厂模式。
这里使用简单工厂模式,工厂的获取用单例(Singleton)模式返回

java 代码
  1. package com.sanook.hompy.util.filter;   
  2.   
  3. import java.util.HashMap;   
  4. import java.util.Map;   
  5.   
  6. import org.apache.commons.logging.Log;   
  7. import org.apache.commons.logging.LogFactory;   
  8.   
  9. import com.sanook.hompy.util.manager.ConfigureManager;   
  10.   
  11. public class StringFilterFactory {   
  12.   
  13.     private static final Log log = LogFactory.getLog(StringFilterFactory.class);   
  14.   
  15.     private static final StringFilterFactory stringFilterFactory = new StringFilterFactory();   
  16.   
  17.     private Map filterMap = new HashMap();   
  18.   
  19.     private StringFilterFactory() {   
  20.         //ConfigureManager是Hompy项目统一读取配置的类,以多例(Multi-Singleton)模式实现   
  21.         filterMap = ConfigureManager.getInstance("filter").getMap();   
  22.     }   
  23.   
  24.     public static StringFilterFactory getInstance() {   
  25.         return stringFilterFactory;   
  26.     }   
  27.   
  28.     //通过一个以逗号分割的过滤器引用名串,获取过滤器   
  29.     public StringFilter getStringFilterChain(String chain) {   
  30.         if (chain == null || chain.length() == 0) {   
  31.             return new EmptyFilter();   
  32.         }   
  33.   
  34.         if ("all".equalsIgnoreCase(chain)) {   
  35.             return getAllStringFilterChain();   
  36.         }   
  37.   
  38.         String[] filters = chain.split("\\,");   
  39.         return getStringFilterChain(filters);   
  40.     }   
  41.   
  42.     public StringFilter getAllStringFilterChain() {   
  43.         String[] filters = (String[]) filterMap.values().toArray();   
  44.         return getStringFilterChain(filters);   
  45.     }   
  46.   
  47.     public StringFilter getStringFilterChain(String[] filters) {   
  48.         if (filters == null || filters.length == 0) {   
  49.             return new EmptyFilter();   
  50.         }   
  51.   
  52.         StringFilter[] stringFilters = new StringFilter[filters.length];   
  53.         for (int i = filters.length - 1; i >= 0; i--) {   
  54.             stringFilters[i] = getStringFilter(filters[i]);   
  55.             if (i != filters.length - 1) {   
  56.                 stringFilters[i].setNextStringFilter(stringFilters[i + 1]);   
  57.             } else {   
  58.                 stringFilters[i].setNextStringFilter(null);   
  59.             }   
  60.         }   
  61.         return stringFilters[0];   
  62.     }   
  63.   
  64.     public StringFilter getStringFilter(String key) {   
  65.         if (key != null) {   
  66.             try {   
  67.                 //通过类名反射得到过滤器的实例   
  68.                 Class clazz = Class.forName((String) filterMap.get(key));   
  69.                 StringFilter stringFilter = (StringFilter) clazz.newInstance();   
  70.                 return stringFilter;   
  71.             } catch (ClassNotFoundException e) {   
  72.                 e.printStackTrace();   
  73.                 log.warn(e);   
  74.             } catch (InstantiationException e) {   
  75.                 e.printStackTrace();   
  76.                 log.warn(e);   
  77.             } catch (IllegalAccessException e) {   
  78.                 e.printStackTrace();   
  79.                 log.warn(e);   
  80.             }   
  81.         }   
  82.         return new EmptyFilter();   
  83.     }   
  84. }   

 

配置文件filter.properties如下:

java 代码
  1. html=com.sanook.hompy.util.filter.HtmlFilter   
  2. url=com.sanook.hompy.util.filter.UrlFilter   
  3. js=com.sanook.hompy.util.filter.JavaScriptFilter   
  4. dirty=com.sanook.hompy.util.filter.DirtyWordFilter   
  5. quote=com.sanook.hompy.util.filter.QuotationMarkFilter   
  6. line=com.sanook.hompy.util.filter.NewLineFilter   
  7. lower=com.sanook.hompy.util.filter.LowerFilter   

这些配置将通过ConfigureManager读到filterMap中,
其中key作为chain的引用名,value为过滤器对象名。

 

调用方式:

java 代码
  1. String chain = "html,js,dirty";   
  2. StringFilter stringFilter = StringFilterFactory.getInstance().getStringFilterChain(chain);   
  3. String source = "<b>aaaa</b>";   
  4. String result = stringFilter.filter(source);   

 

现在如果你要扩展一个过滤器,只要继承AbstractStringFilter,实现doFilter(String source)方法,
在filter.properties加入其引用名即可。上面的配置示例中就是Hompy项目用到的一些过滤器。

Hompy项目以JSP作为View层,而StringFiler是属于展示逻辑,应由View层控制,所以,我使用了自定义标签。

java 代码
  1. package com.sanook.hompy.servlet.tag;   
  2.   
  3. import com.sanook.hompy.util.filter.StringFilter;   
  4. import com.sanook.hompy.util.filter.StringFilterFactory;   
  5.   
  6. public class FilterTag extends BodyOutTag {   
  7.   
  8.     private static final long serialVersionUID = 1L;   
  9.   
  10.     private String chain;   
  11.        
  12.     public void setChain(String chain) {   
  13.         this.chain = chain;   
  14.     }   
  15.   
  16.     public String doBody(String body) {   
  17.         StringFilter stringFilter = StringFilterFactory.getInstance()   
  18.                 .getStringFilterChain(chain);   
  19.         return stringFilter.filter(body);   
  20.     }   
  21.   
  22. }   

 

其父类BodyOutTag是一个抽象类

java 代码
  1. package com.sanook.hompy.presentation.tag;   
  2.   
  3. import javax.servlet.jsp.JspException;   
  4. import javax.servlet.jsp.JspTagException;   
  5. import javax.servlet.jsp.tagext.BodyTagSupport;   
  6.   
  7. public abstract class BodyOutTag extends BodyTagSupport {   
  8.        
  9.     private String body;   
  10.        
  11.     public BodyOutTag() {   
  12.         super();   
  13.         init();   
  14.     }   
  15.        
  16.     private void init() {   
  17.         body = null;   
  18.     }   
  19.        
  20.     public void setBody(String body) {   
  21.         this.body = body;   
  22.     }   
  23.        
  24.     public int doStartTag() throws JspException {   
  25.         return EVAL_BODY_BUFFERED;   
  26.     }   
  27.        
  28.     public int doEndTag() throws JspException {   
  29.         if (body == null) {   
  30.             if (bodyContent != null && bodyContent.getString() != null) {   
  31.                 body = bodyContent.getString().trim();   
  32.             } else {   
  33.                 body = "";   
  34.             }   
  35.         }   
  36.            
  37.         /*如果继承SimpleTagSupport,则用:  
  38.         if (body == null) {  
  39.             body = "";  
  40.             JspFragment body = getJspBody();  
  41.             if (body != null) {  
  42.                 StringWriter writer = new StringWriter();  
  43.                 body.invoke(writer);  
  44.                 body = writer.toString();  
  45.             }  
  46.         }*/  
  47.            
  48.         body = doBody(body);   
  49.            
  50.         try {   
  51.             pageContext.getOut().print(body == null ? "" : body);   
  52.         } catch (java.io.IOException ex) {   
  53.             throw new JspTagException(ex.getMessage());   
  54.         }   
  55.         body = null;   
  56.         return EVAL_PAGE;   
  57.     }   
  58.        
  59.     public void release() {   
  60.         super.release();   
  61.         init();   
  62.     }   
  63.        
  64.     public abstract String doBody(String body);   
  65.   
  66. }   

 

配置/WEB-INF/tld/hompy-string.tld,
(我将其归纳在string处理namespace内)

xml 代码
  1. <?xml version="1.0" encoding="UTF-8" ?>  
  2.   
  3. <taglib xmlns="http://java./xml/ns/j2ee" xmlns:xsi="http://www./2001/XMLSchema-instance" xsi:schemaLocation="http://java./xml/ns/j2ee http://java./xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">  
  4.     <description>hompy string tag library</description>  
  5.     <display-name>string</display-name>  
  6.     <tlib-version>1.0</tlib-version>  
  7.     <short-name>s</short-name>  
  8.     <uri>http://hompy./tag/string</uri>  
  9.     <tag>  
  10.         <description></description>  
  11.         <name>filter</name>  
  12.         <tag-class>com.sanook.hompy.servlet.tag.FilterTag</tag-class>  
  13.         <body-content>JSP</body-content>  
  14.         <attribute>  
  15.             <description>body</description>  
  16.             <name>body</name>  
  17.             <required>false</required>  
  18.             <rtexprvalue>true</rtexprvalue>  
  19.             <type>java.lang.String</type>  
  20.         </attribute>  
  21.         <attribute>  
  22.             <description>filter chain key, separator is ,</description>  
  23.             <name>chain</name>  
  24.             <required>true</required>  
  25.             <rtexprvalue>true</rtexprvalue>  
  26.         </attribute>  
  27.     </tag>  
  28. </taglib>  

 

在web.xml的适当位置加入:

xml 代码
  1. <taglib>  
  2.     <taglib-uri>hompy-string</taglib-uri>  
  3.     <taglib-location>/WEB-INF/tld/hompy-string.tld</taglib-location>  
  4. </taglib>  

 

在jsp页面中使用如下:

xml 代码
  1. <%@ page language="java" contentType="text/html" pageEncoding="UTF-8" isELIgnored="false"%>  
  2. <%@ taglib uri="hompy-string" prefix="s"%>  
  3. <html>  
  4.     <body>  
  5.         Test Filter: <s:filter chain="html,js,dirty">${picture.title}</s:filter>  
  6.     </body>  
  7. </html>  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多