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

原文地址:http://javatar.iteye.com/blog/40188

字符串过滤,是比较常用的功能,我的当前项目也有用到。 
如过滤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>

 

posted @ 2016-05-24 16:36  SuperGigi  阅读(142)  评论(0编辑  收藏  举报