`
javatar
  • 浏览: 1700304 次
  • 性别: Icon_minigender_1
  • 来自: 杭州699号
社区版块
存档分类
最新评论

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

阅读更多
字符串过滤,是比较常用的功能,我的当前项目也有用到。
如过滤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!
分享到:
评论
3 楼 wwicked 2017-07-14  
  
2 楼 CheungCharles 2016-01-05  
1 楼 leisure 2006-12-30  
Jive论坛中的过滤功能是采用的也是装饰器(Decorator)模式.可以参考

相关推荐

    Android开发之EditText字符串过滤器InputFilter

    总之,Android的EditText字符串过滤器InputFilter是一个强大的工具,它允许开发者定制输入行为,提高应用的数据验证和用户体验。理解并熟练掌握InputFilter的使用,对于Android开发者来说是非常重要的技能之一。

    jsp中的过滤器(含例子)

    总的来说,`JSP`中的过滤器是一个强大的工具,它能够帮助我们处理请求和响应,实现跨页面的通用功能,提升应用程序的安全性和用户体验。在实际开发中,熟练掌握过滤器的使用,将大大提升我们的开发效率和代码质量。

    基于vb6开发的网站过滤器源代码

    在本项目中,可能会有一个Filter类,用于处理过滤逻辑。 三、网站过滤关键技术 1. 关键词匹配:VB6可以使用字符串函数(如InStr、Like等)进行关键词匹配。在过滤器中,需要遍历网页内容,对比预设的过滤关键字...

    yatr:用替换符替换字符串中的任何字符。这可以带有区分大小写检查的标志

    `yatr` 是一个工具,用于在字符串中替换特定字符,具有区分大小写的选项。这个工具的名称可能是 "Yet Another Text Replacer" 的缩写,它提供了与传统文本替换功能不同的可能性,尤其是在处理大量文本或者需要更精细...

    软件工程答辩常见问题总结.doc

    * 使用过滤器来解决乱码问题,可以编写一个过滤器类,例如 `SetCharacterEncodingFilter`。 六、过滤器应用 * 使用过滤器来解决乱码问题,可以编写一个过滤器类,例如 `SetCharacterEncodingFilter`。 * 过滤器...

    为了大三实习,四月份开始复习Java,这是复习完Java web所写的一个简单商城项目.zip

    8. **过滤器和监听器**:在Java Web中,过滤器(Filter)用于拦截请求和响应,实现预处理和后处理功能,如登录验证、字符编码转换等。监听器(Listener)则监听Web应用中特定事件,如session的创建、销毁等。 9. **...

    tomcat跨域cors相关jar包 java-property-utils-1.9.jar,cors-filter-1.7.jar,java-util-1.9

    这是一个包含通用Java工具类的库,可能包含字符串处理、集合操作等实用方法。在处理CORS时,可能用于辅助处理请求或响应,比如构建响应头、解析请求头等。 在Tomcat中实现跨域CORS,通常涉及以下几个步骤: 1. **...

    testIO项目

    Java通过一系列类和接口构建了一个完整的I/O流模型,分为字节流和字符流两大类。字节流处理的数据单位是字节,而字符流处理的是Unicode字符。在字节流中,InputStream和OutputStream是所有输入输出流的基类,分别...

    毕业设计: 心理咨询预约管理系统(javaEE)

    utils.filter过滤器,登录过滤,字符过滤等等 utils.jdbc数据库工具类,配置和得到连接池的连接 utils.mail是邮件模块 utils下的ConfigProperties是读入配置文件,ResultDate和UploadResult分别是请求响应结果和...

    Javaweb网上购物商城自己写的课设,一个简单的网上购物商城,通过这次的简单的项目来加深对Java的理解.zip

    在本项目中,我们探索的是一个基于JavaWeb技术构建的简单网上购物商城。这个课程设计旨在帮助学习者深入理解Java编程语言以及其在Web开发中的应用。以下将详细阐述涉及的知识点: 1. **Servlet与JSP**:作为JavaWeb...

    cors-filter-1.7.jar java-util-1.9.1.jar

    2. **配置web.xml**:在你的应用的`WEB-INF/web.xml`文件中,你需要添加一个新的过滤器定义,如下所示: ```xml &lt;filter-name&gt;CORS &lt;filter-class&gt;com.thetransactioncompany.cors.CORSFilter&lt;/filter-class&gt; ...

    apache commons 开源工具列举

    Apache Commons 是一个由Apache软件基金会维护的Java库集合,它为开发人员提供了大量实用的工具类和组件,极大地简化了常见的编程任务。这个库包含了众多模块,每个模块专注于特定的功能领域,例如字符串处理、数学...

    JavaWeb 完整的新闻项目

    9. **过滤器(Filter)与监听器(Listener)**:在JavaWeb中,过滤器可以对请求和响应进行拦截处理,如字符编码转换、权限验证等;监听器则可以监听Web应用中特定事件,如session的创建、销毁等。 10. **Ajax异步...

    XSSSecurityFilter实战

    "XSSSecurityFilter实战"是一个关于如何预防XSS攻击的实践教程,它涵盖了在Java Web开发中使用自定义过滤器来增强应用的安全性。 首先,我们需要了解XSS攻击的基本原理。XSS通常分为反射型、存储型和DOM型三种类型...

    JAVA上百实例源码以及开源项目源代码

    Java编写的显示器显示模式检测程序 2个目标文件 内容索引:JAVA源码,系统相关,系统信息检测 用JAVA编写了一个小工具,用于检测当前显示器也就是显卡的显示模式,比如分辨率,色彩以及刷新频率等。 Java波浪文字制作...

    servlet+jsp实现上传下载文件用到的两个JAR包

    这个库提供了一系列实用工具类,简化了文件、流、字符集、缓冲区、读写器和过滤器等的操作。在文件上传下载中,Commons IO 提供了如文件复制、移动、重命名以及读取文件内容的功能。例如,`FileUtils....

    commons-io-1.3.2.jar

    "commons-io-1.3.2.jar" 是Apache Commons IO库的一个版本,它是一个Java类库,专注于提供各种I/O操作的工具类和实用程序。这个版本是1.3.2,发布于2007年,是为了解决早期Java API在处理输入输出流时的一些不足而...

    net.mindview jar下载

    3. **测试辅助类**:书中可能用到一些专门用于测试的工具类,比如断言工具、模拟对象或者数据生成器。 4. **类型转换工具**:可能包含一些方便的静态方法,用于在不同数据类型之间进行安全转换。 5. **线程和并发*...

    json_lib所需要的包

    1. `commons-collections-3.2.jar`: Apache Commons Collections是Java集合框架的扩展库,提供了各种实用工具类和算法,例如映射、过滤器、比较器等,这些在处理JSON数据时可能会用到。 2. `commons-lang-2.3.jar`:...

    IOS项目实战

    本“iOS项目实战”专注于一个具体的字典应用程序的开发,旨在帮助开发者通过实际操作来深化对iOS编程的理解。下面将详细介绍这个项目的相关知识点。 1. **Swift语言基础**:作为iOS开发的主要编程语言,Swift是本...

Global site tag (gtag.js) - Google Analytics