浏览 5451 次
锁定老帖子 主题:项目中用到的一个小工具类(字符过滤器)
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2006-12-22
如过滤User输入的Html,Js代码等, 由于过滤需求是可能变动的, 如客户又要你过滤一些脏词或者为内容中的url自动加上超链接等。 考虑“开-闭”(OCP)原则, 我决定使用装饰器(Decorator)模式。 首先定义Decorator接口: package com.sanook.hompy.util.filter; public interface StringFilter { public void setNextStringFilter(StringFilter stringFilter); //关联下一装饰器 public String filter(String source); //处理过滤 } 然后用模板方法(Template Method)模式实现一个抽象的过滤器: 这样可以将相同的实现部分抽象出来。 package com.sanook.hompy.util.filter; public abstract class AbstractStringFilter implements StringFilter { private StringFilter stringFilter; public void setNextStringFilter(StringFilter stringFilter) { this.stringFilter = stringFilter; } public String filter(String source) { String target = doFilter(source); if (stringFilter == null) { return target; } return stringFilter.filter(target); } // 模板抽象方法,传入要处理的string,返回处理完的string // 遵循模板方法doXXX命名方式 public abstract String doFilter(String source); } 空的实现: package com.sanook.hompy.util.filter; public class EmptyFilter extends AbstractStringFilter { public String doFilter(String source) { return source; } } 下面实现该接口的Html过滤: package com.sanook.hompy.util.filter; import org.apache.commons.lang.StringUtils; public class HtmlFilter extends AbstractStringFilter { public String doFilter(String source) { source = StringUtils.replace(source, "<", "& lt;"); source = StringUtils.replace(source, ">", "& gt;"); source = StringUtils.replace(source, "&", "& amp;"); source = StringUtils.replace(source, " ", "& nbsp;"); source = StringUtils.replace(source, "\"", "& #0034;"); source = StringUtils.replace(source, "\'", "& #0039;"); return source; } } 由于Decorator是嵌套结构(注:这里只用了前(before)装饰,所以看起来有点像链结构,如有必要,也可以加上后(after)装饰), 它的调用关系需要组装,所以应该用建造者(Builder)模式或简单工厂模式。 这里使用简单工厂模式,工厂的获取用单例(Singleton)模式返回 package com.sanook.hompy.util.filter; import java.util.HashMap; import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.sanook.hompy.util.manager.ConfigureManager; public class StringFilterFactory { private static final Log log = LogFactory.getLog(StringFilterFactory.class); private static final StringFilterFactory stringFilterFactory = new StringFilterFactory(); private Map filterMap = new HashMap(); private StringFilterFactory() { //ConfigureManager是Hompy项目统一读取配置的类,以多例(Multi-Singleton)模式实现 filterMap = ConfigureManager.getInstance("filter").getMap(); } public static StringFilterFactory getInstance() { return stringFilterFactory; } //通过一个以逗号分割的过滤器引用名串,获取过滤器 public StringFilter getStringFilterChain(String chain) { if (chain == null || chain.length() == 0) { return new EmptyFilter(); } if ("all".equalsIgnoreCase(chain)) { return getAllStringFilterChain(); } String[] filters = chain.split("\\,"); return getStringFilterChain(filters); } public StringFilter getAllStringFilterChain() { String[] filters = (String[]) filterMap.values().toArray(); return getStringFilterChain(filters); } public StringFilter getStringFilterChain(String[] filters) { if (filters == null || filters.length == 0) { return new EmptyFilter(); } StringFilter[] stringFilters = new StringFilter[filters.length]; for (int i = filters.length - 1; i >= 0; i--) { stringFilters[i] = getStringFilter(filters[i]); if (i != filters.length - 1) { stringFilters[i].setNextStringFilter(stringFilters[i + 1]); } else { stringFilters[i].setNextStringFilter(null); } } return stringFilters[0]; } public StringFilter getStringFilter(String key) { if (key != null) { try { //通过类名反射得到过滤器的实例 Class clazz = Class.forName((String) filterMap.get(key)); StringFilter stringFilter = (StringFilter) clazz.newInstance(); return stringFilter; } catch (ClassNotFoundException e) { e.printStackTrace(); log.warn(e); } catch (InstantiationException e) { e.printStackTrace(); log.warn(e); } catch (IllegalAccessException e) { e.printStackTrace(); log.warn(e); } } return new EmptyFilter(); } } 配置文件filter.properties如下: html=com.sanook.hompy.util.filter.HtmlFilter url=com.sanook.hompy.util.filter.UrlFilter js=com.sanook.hompy.util.filter.JavaScriptFilter dirty=com.sanook.hompy.util.filter.DirtyWordFilter quote=com.sanook.hompy.util.filter.QuotationMarkFilter line=com.sanook.hompy.util.filter.NewLineFilter lower=com.sanook.hompy.util.filter.LowerFilter 这些配置将通过ConfigureManager读到filterMap中, 其中key作为chain的引用名,value为过滤器对象名。 调用方式: String chain = "html,js,dirty"; StringFilter stringFilter = StringFilterFactory.getInstance().getStringFilterChain(chain); String source = "<b>aaaa</b>"; String result = stringFilter.filter(source); 现在如果你要扩展一个过滤器,只要继承AbstractStringFilter,实现doFilter(String source)方法, 在filter.properties加入其引用名即可。上面的配置示例中就是Hompy项目用到的一些过滤器。 Hompy项目以JSP作为View层,而StringFiler是属于展示逻辑,应由View层控制,所以,我使用了自定义标签。 package com.sanook.hompy.servlet.tag; import com.sanook.hompy.util.filter.StringFilter; import com.sanook.hompy.util.filter.StringFilterFactory; public class FilterTag extends BodyOutTag { private static final long serialVersionUID = 1L; private String chain; public void setChain(String chain) { this.chain = chain; } public String doBody(String body) { StringFilter stringFilter = StringFilterFactory.getInstance() .getStringFilterChain(chain); return stringFilter.filter(body); } } 其父类BodyOutTag是一个抽象类 package com.sanook.hompy.presentation.tag; import javax.servlet.jsp.JspException; import javax.servlet.jsp.JspTagException; import javax.servlet.jsp.tagext.BodyTagSupport; public abstract class BodyOutTag extends BodyTagSupport { private String body; public BodyOutTag() { super(); init(); } private void init() { body = null; } public void setBody(String body) { this.body = body; } public int doStartTag() throws JspException { return EVAL_BODY_BUFFERED; } public int doEndTag() throws JspException { if (body == null) { if (bodyContent != null && bodyContent.getString() != null) { body = bodyContent.getString().trim(); } else { body = ""; } } /*如果继承SimpleTagSupport,则用: if (body == null) { body = ""; JspFragment body = getJspBody(); if (body != null) { StringWriter writer = new StringWriter(); body.invoke(writer); body = writer.toString(); } }*/ body = doBody(body); try { pageContext.getOut().print(body == null ? "" : body); } catch (java.io.IOException ex) { throw new JspTagException(ex.getMessage()); } body = null; return EVAL_PAGE; } public void release() { super.release(); init(); } public abstract String doBody(String body); } 配置/WEB-INF/tld/hompy-string.tld, (我将其归纳在string处理namespace内) <?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <description>hompy string tag library</description> <display-name>string</display-name> <tlib-version>1.0</tlib-version> <short-name>s</short-name> <uri>http://hompy.sanook.com/tag/string</uri> <tag> <description></description> <name>filter</name> <tag-class>com.sanook.hompy.servlet.tag.FilterTag</tag-class> <body-content>JSP</body-content> <attribute> <description>body</description> <name>body</name> <required>false</required> <rtexprvalue>true</rtexprvalue> <type>java.lang.String</type> </attribute> <attribute> <description>filter chain key, separator is ,</description> <name>chain</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag> </taglib> 在web.xml的适当位置加入: <taglib> <taglib-uri>hompy-string</taglib-uri> <taglib-location>/WEB-INF/tld/hompy-string.tld</taglib-location> </taglib> 在jsp页面中使用如下: <%@ page language="java" contentType="text/html" pageEncoding="UTF-8" isELIgnored="false"%> <%@ taglib uri="hompy-string" prefix="s"%> <html> <body> Test Filter: <s:filter chain="html,js,dirty">${picture.title}</s:filter> </body> </html> 希望各位 帮忙重构。 Like Refactor! 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2006-12-30
Jive论坛中的过滤功能是采用的也是装饰器(Decorator)模式.可以参考
|
|
返回顶楼 | |