java配置多个过滤器优先级以及几个常用过滤器操作

 更新时间:2021年7月4日 10:00  点击:1643

一个项目中不出意外的话会有两个以上的过滤器,但是直接不配置的话他会按照你的过滤器名字排序执行,这样的话可能会导致一些性能上或者逻辑上的问题。那么,控制一下执行顺序是我们所必须要做的。

java封装了一个FilterRegistrationBean对象,可以把他比作一个容器,将过滤器套入这个对象中,可以对这个对象进行优先级设置、过滤规则设置等属性,下面是几个常用的过滤器以及过滤器配置。

过滤器配置:

package cn.ask.filter;
import javax.servlet.DispatcherType; 
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;
 
/**
 * Title:      FilterConfig
 * @date       2018年10月25日
 * @version    V1.0
 * Description: 过滤器配置
 */
@SuppressWarnings("all")
@Configuration
public class FilterConfig {
	/**
	 * @Description 防xss攻击过滤器
	 * @date 2018年8月16日下午4:55:44
	 */
	@Bean
	public FilterRegistrationBean xssFilterRegistration() {
		FilterRegistrationBean registration = new FilterRegistrationBean();
		registration.setDispatcherTypes(DispatcherType.REQUEST);
		registration.setFilter(new XssFilter());
		registration.addUrlPatterns("/*");
		registration.setName("xssFilter");
        //order数字越小越先执行
		registration.setOrder(1);
		return registration;
	}
	
	/**  
	* @Description 获取登录信息 
	* @date 2018年10月25日上午9:14:48
	*/
	@Bean
	public FilterRegistrationBean cookieRegistration() {
		FilterRegistrationBean registration = new FilterRegistrationBean();
		registration.setDispatcherTypes(DispatcherType.REQUEST);
		registration.setFilter(new CookieFilter());
		registration.addUrlPatterns("/*");
		registration.setName("firstFilter");
		registration.setOrder(2);
		return registration;
	}	
}

常用过滤器之一:

sso单点登录(使用cookie记录跨站数据)

package cn.ask.filter; 
import java.io.IOException;
import java.net.URLDecoder; 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; 
import org.apache.commons.lang3.StringUtils;
 
/**
 * Servlet Filter implementation class FirstFilter
 */
public class CookieFilter implements Filter {
 
    /**
     * Default constructor. 
     */
    public CookieFilter() {
        // TODO Auto-generated constructor stub
    }
 
	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}
 
	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) request;
		String tokenHeader = req.getHeader("token");
		if(StringUtils.isBlank(tokenHeader)) {
			Cookie[] cookies = req.getCookies();
			if (cookies != null && cookies.length > 0) {
				for (int i = 0; i < cookies.length; i++) {
					String name = cookies[i].getName();
					String value = cookies[i].getValue();
					if ("user_accesstoken".equals(name)) { // 用户token
						req.setAttribute("token", URLDecoder.decode(value, "utf-8"));
					}
					if ("user_avatar".equals(name)) { // 头像
						req.setAttribute("avatar", URLDecoder.decode(value, "utf-8"));
					}
					if ("user_nickname".equals(name)) { // 昵称
						req.setAttribute("nickname", URLDecoder.decode(value, "utf-8"));
					}
					String token = (String) req.getAttribute("token");
					if (StringUtils.isBlank(token)) {
						req.setAttribute("isLogin", "no");
					} else {
						req.setAttribute("isLogin", "yes");
					}
				}
			}else {
				req.removeAttribute("token");
				req.removeAttribute("avatar");
				req.removeAttribute("nickname");
				req.setAttribute("isLogin", "no");
			}
		} else {
			req.setAttribute("token", tokenHeader);
		}
		
		chain.doFilter(request, response);
	}
 
	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException {
		// TODO Auto-generated method stub
	} 
}

常用过滤器之二:

xss过滤以及防html注入过滤(包括过滤敏感词)

package cn.ask.filter; 
import java.io.IOException; 
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;  
/**
 * Title:      XssFilter
 * @date       2018年8月16日
 * @version    V1.0
 * Description: xss过滤
 */
public class XssFilter implements Filter {
 
	@Override
	public void init(FilterConfig config) throws ServletException {
	}
 
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
		XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
		chain.doFilter(xssRequest, response);
	}
 
	@Override
	public void destroy() {
	} 
}

package cn.ask.filter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper; 
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; 
 
/**
 * Title:      XssHttpServletRequestWrapper
 * @date       2018年8月16日
 * @version    V1.0
 * Description:  XSS过滤处理
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
    /**没被包装过的HttpServletRequest(特殊场景,需要自己过滤*/
    HttpServletRequest orgRequest;
    /**html过滤*/
    private final static HtmlFilter HTMLFILTER = new HtmlFilter();
 
    public XssHttpServletRequestWrapper(HttpServletRequest request) {
        super(request);
        orgRequest = request;
    }
 
    @Override
    public ServletInputStream getInputStream() throws IOException {
        //非json类型,直接返回
        if(!super.getHeader(HttpHeaders.CONTENT_TYPE).equalsIgnoreCase(MediaType.APPLICATION_JSON_VALUE)){
            return super.getInputStream();
        }
 
        //为空,直接返回
        String json = IOUtils.toString(super.getInputStream(), "utf-8");
        if (StringUtils.isBlank(json)) {
            return super.getInputStream();
        }
 
        //xss过滤
        json = xssEncode(json);
        final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes());
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return true;
            }
 
            @Override
            public boolean isReady() {
                return true;
            }
 
            @Override
            public void setReadListener(ReadListener readListener) {
 
            }
 
            @Override
            public int read() throws IOException {
                return bis.read();
            }
        };
    } 
    @Override
    public String getParameter(String name) {
        String value = super.getParameter(xssEncode(name));
        if (StringUtils.isNotBlank(value)) {
            value = xssEncode(value);
        }
        return value;
    } 
    @Override
    public String[] getParameterValues(String name) {
        String[] parameters = super.getParameterValues(name);
        if (parameters == null || parameters.length == 0) {
            return null;
        }
 
        for (int i = 0; i < parameters.length; i++) {
            parameters[i] = xssEncode(parameters[i]);
        }
        return parameters;
    } 
    @Override
    public Map<String,String[]> getParameterMap() {
        Map<String,String[]> map = new LinkedHashMap<>();
        Map<String,String[]> parameters = super.getParameterMap();
        for (String key : parameters.keySet()) {
            String[] values = parameters.get(key);
            for (int i = 0; i < values.length; i++) {
                values[i] = xssEncode(values[i]);
            }
            map.put(key, values);
        }
        return map;
    } 
    @Override
    public String getHeader(String name) {
        String value = super.getHeader(xssEncode(name));
        if (StringUtils.isNotBlank(value)) {
            value = xssEncode(value);
        }
        return value;
    }
    //富文本内容放行
    private String xssEncode(String input) {
    	if(!input.startsWith("<p")&&!input.startsWith("<ol")&&!input.startsWith("<ul")&&!input.startsWith("<hr/>")) {
    		input=HTMLFILTER.filter(input);
    	}
        //敏感词过滤
        input=SensitiveWordUtils.getSensitiveWordUtils().replaceSensitiveWord(input, '*', 2);
        return input;        
    } 
    /**
     * 获取最原始的request
     */
    public HttpServletRequest getOrgRequest() {
        return orgRequest;
    } 
    /**
     * 获取最原始的request
     */
    public static HttpServletRequest getOrgRequest(HttpServletRequest request) {
        if (request instanceof XssHttpServletRequestWrapper) {
            return ((XssHttpServletRequestWrapper) request).getOrgRequest();
        } 
        return request;
    } 
}

package cn.ask.filter; 
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern; 
/**
 * Title:      HTMLFilter
 * @date       2018年8月16日
 * @version    V1.0
 * Description: 防html注入
 */
public final class HtmlFilter { 
    /** regex flag union representing /si modifiers in php **/
    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
    private static final Pattern P_END_ARROW = Pattern.compile("^>");
    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
    private static final Pattern P_AMP = Pattern.compile("&");
    private static final Pattern P_QUOTE = Pattern.compile("<");
    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
    private static final String SS="#//";
 
    /** @xxx could grow large... maybe use sesat's ReferenceMap */
    private static final ConcurrentMap<String,Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<String, Pattern>();
    private static final ConcurrentMap<String,Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<String, Pattern>();
 
    /** set of allowed html elements, along with allowed attributes for each element **/
    private final Map<String, List<String>> vAllowed;
    /** counts of open tags for each (allowable) html element **/
    private final Map<String, Integer> vTagCounts = new HashMap<String, Integer>();
 
    /** html elements which must always be self-closing (e.g. "<img />") **/
    private final String[] vSelfClosingTags;
    /** html elements which must always have separate opening and closing tags (e.g. "<b></b>") **/
    private final String[] vNeedClosingTags;
    /** set of disallowed html elements **/
    private final String[] vDisallowed;
    /** attributes which should be checked for valid protocols **/
    private final String[] vProtocolAtts;
    /** allowed protocols **/
    private final String[] vAllowedProtocols;
    /** tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />") **/
    private final String[] vRemoveBlanks;
    /** entities allowed within html markup **/
    private final String[] vAllowedEntities;
    /** flag determining whether comments are allowed in input String. */
    private final boolean stripComment;
    private final boolean encodeQuotes;
    private boolean vDebug = false;
    /**
     * flag determining whether to try to make tags when presented with "unbalanced"
     * angle brackets (e.g. "<b text </b>" becomes "<b> text </b>").  If set to false,
     * unbalanced angle brackets will be html escaped.
     */
    private final boolean alwaysMakeTags;
 
    /** Default constructor.
     *
     */
    public HtmlFilter() {
        vAllowed = new HashMap<>();
 
        final ArrayList<String> aAtts = new ArrayList<String>();
        aAtts.add("href");
        aAtts.add("target");
        vAllowed.put("a", aAtts);
 
        final ArrayList<String> imgAtts = new ArrayList<String>();
        imgAtts.add("src");
        imgAtts.add("width");
        imgAtts.add("height");
        imgAtts.add("alt");
        vAllowed.put("img", imgAtts);
 
        final ArrayList<String> noAtts = new ArrayList<String>();
        vAllowed.put("b", noAtts);
        vAllowed.put("strong", noAtts);
        vAllowed.put("i", noAtts);
        vAllowed.put("em", noAtts);
 
        vSelfClosingTags = new String[]{"img"};
        vNeedClosingTags = new String[]{"a", "b", "strong", "i", "em"};
        vDisallowed = new String[]{};
        /**no ftp*/
        vAllowedProtocols = new String[]{"http", "mailto", "https"};
        vProtocolAtts = new String[]{"src", "href"};
        vRemoveBlanks = new String[]{"a", "b", "strong", "i", "em"};
        vAllowedEntities = new String[]{"amp", "gt", "lt", "quot"};
        stripComment = true;
        encodeQuotes = true;
        alwaysMakeTags = true;
    } 
    /** Set debug flag to true. Otherwise use default settings. See the default constructor.
     *
     * @param debug turn debug on with a true argument
     */
    public HtmlFilter(final boolean debug) {
        this();
        vDebug = debug; 
    } 
    /** Map-parameter configurable constructor.
     *
     * @param conf map containing configuration. keys match field names.
     */
    @SuppressWarnings("unchecked")
	public HtmlFilter(final Map<String,Object> conf) {
 
        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
 
        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
        vDisallowed = (String[]) conf.get("vDisallowed");
        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
        stripComment =  conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
    } 
    private void reset() {
        vTagCounts.clear();
    } 
    private void debug(final String msg) {
        if (vDebug) {
            Logger.getAnonymousLogger().info(msg);
        }
    } 
    //---------------------------------------------------------------
    /**my versions of some PHP library functions*/
    public static String chr(final int decimal) {
        return String.valueOf((char) decimal);
    }
 
    public static String htmlSpecialChars(final String s) {
        String result = s;
        result = regexReplace(P_AMP, "&amp;", result);
        result = regexReplace(P_QUOTE, "&quot;", result);
        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
        return result;
    } 
    //---------------------------------------------------------------
    /**
     * given a user submitted input String, filter out any invalid or restricted
     * html.
     *
     * @param input text (i.e. submitted by a user) than may contain html
     * @return "clean" version of input, with only valid, whitelisted html elements allowed
     */
    public String filter(final String input) {
        reset();
        String s = input;
 
        debug("************************************************");
        debug("              INPUT: " + input);
 
        s = escapeComments(s);
        debug("     escapeComments: " + s);
 
        s = balanceHTML(s);
        debug("        balanceHTML: " + s);
 
        s = checkTags(s);
        debug("          checkTags: " + s);
 
        s = processRemoveBlanks(s);
        debug("processRemoveBlanks: " + s);
 
        s = validateEntities(s);
        debug("    validateEntites: " + s);
 
        debug("************************************************\n\n");
        return s;
    } 
    public boolean isAlwaysMakeTags(){
        return alwaysMakeTags;
    } 
    public boolean isStripComments(){
        return stripComment;
    } 
    private String escapeComments(final String s) {
        final Matcher m = P_COMMENTS.matcher(s);
        final StringBuffer buf = new StringBuffer();
        if (m.find()) {
        	/**(.*?)*/
            final String match = m.group(1); 
            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
        }
        m.appendTail(buf); 
        return buf.toString();
    } 
    private String balanceHTML(String s) {
        if (alwaysMakeTags) {
            //
            // try and form html
            //
            s = regexReplace(P_END_ARROW, "", s);
            s = regexReplace(P_BODY_TO_END, "<$1>", s);
            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
 
        } else {
            //
            // escape stray brackets
            //
            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
 
            //
            // the last regexp causes '<>' entities to appear
            // (we need to do a lookahead assertion so that the last bracket can
            // be used in the next pass of the regexp)
            //
            s = regexReplace(P_BOTH_ARROWS, "", s);
        } 
        return s;
    } 
    private String checkTags(String s) {
        Matcher m = P_TAGS.matcher(s);
 
        final StringBuffer buf = new StringBuffer();
        while (m.find()) {
            String replaceStr = m.group(1);
            replaceStr = processTag(replaceStr);
            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
        }
        m.appendTail(buf); 
        s = buf.toString(); 
        // these get tallied in processTag
        // (remember to reset before subsequent calls to filter method)
        for (String key : vTagCounts.keySet()) {
            for (int ii = 0; ii < vTagCounts.get(key); ii++) {
                s += "</" + key + ">";
            }
        } 
        return s;
    } 
    private String processRemoveBlanks(final String s) {
        String result = s;
        for (String tag : vRemoveBlanks) {
            if(!P_REMOVE_PAIR_BLANKS.containsKey(tag)){
                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
            }
            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
            if(!P_REMOVE_SELF_BLANKS.containsKey(tag)){
                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
            }
            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
        } 
        return result;
    } 
    private static String regexReplace(final Pattern regexPattern, final String replacement, final String s) {
        Matcher m = regexPattern.matcher(s);
        return m.replaceAll(replacement);
    } 
    private String processTag(final String s) {
        // ending tags
        Matcher m = P_END_TAG.matcher(s);
        if (m.find()) {
            final String name = m.group(1).toLowerCase();
            if (allowed(name)) {
                if (!inArray(name, vSelfClosingTags)) {
                    if (vTagCounts.containsKey(name)) {
                        vTagCounts.put(name, vTagCounts.get(name) - 1);
                        return "</" + name + ">";
                    }
                }
            }
        }
        // starting tags
        m = P_START_TAG.matcher(s);
        if (m.find()) {
            final String name = m.group(1).toLowerCase();
            final String body = m.group(2);
            String ending = m.group(3);
            //debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
            if (allowed(name)) {
                String params = "";
                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
                final List<String> paramNames = new ArrayList<String>();
                final List<String> paramValues = new ArrayList<String>();
                while (m2.find()) {
                	/**([a-z0-9]+)*/
                    paramNames.add(m2.group(1)); 
                    /**(.*?)*/
                    paramValues.add(m2.group(3)); 
                }
                while (m3.find()) {
                	/**([a-z0-9]+)*/
                    paramNames.add(m3.group(1));
                    /**([^\"\\s']+)*/
                    paramValues.add(m3.group(3)); 
                }
                String paramName, paramValue;
                for (int ii = 0; ii < paramNames.size(); ii++) {
                    paramName = paramNames.get(ii).toLowerCase();
                    paramValue = paramValues.get(ii);
                    if (allowedAttribute(name, paramName)) {
                        if (inArray(paramName, vProtocolAtts)) {
                            paramValue = processParamProtocol(paramValue);
                        }
                        params += " " + paramName + "=\"" + paramValue + "\"";
                    }
                }
                if (inArray(name, vSelfClosingTags)) {
                    ending = " /";
                }
                if (inArray(name, vNeedClosingTags)) {
                    ending = "";
                }
                if (ending == null || ending.length() < 1) {
                    if (vTagCounts.containsKey(name)) {
                        vTagCounts.put(name, vTagCounts.get(name) + 1);
                    } else {
                        vTagCounts.put(name, 1);
                    }
                } else {
                    ending = " /";
                }
                return "<" + name + params + ending + ">";
            } else {
                return "";
            }
        }
        // comments
        m = P_COMMENT.matcher(s);
        if (!stripComment && m.find()) {
            return  "<" + m.group() + ">";
        }
        return "";
    } 
    private String processParamProtocol(String s) {
        s = decodeEntities(s);
        final Matcher m = P_PROTOCOL.matcher(s);
        if (m.find()) {
            final String protocol = m.group(1);
            if (!inArray(protocol, vAllowedProtocols)) {
                // bad protocol, turn into local anchor link instead
                s = "#" + s.substring(protocol.length() + 1, s.length());
                if (s.startsWith(SS)) {
                    s = "#" + s.substring(3, s.length());
                }
            }
        } 
        return s;
    } 
    private String decodeEntities(String s) {
        StringBuffer buf = new StringBuffer();
 
        Matcher m = P_ENTITY.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.decode(match).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
 
        buf = new StringBuffer();
        m = P_ENTITY_UNICODE.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.valueOf(match, 16).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
 
        buf = new StringBuffer();
        m = P_ENCODE.matcher(s);
        while (m.find()) {
            final String match = m.group(1);
            final int decimal = Integer.valueOf(match, 16).intValue();
            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
        }
        m.appendTail(buf);
        s = buf.toString();
 
        s = validateEntities(s);
        return s;
    } 
    private String validateEntities(final String s) {
        StringBuffer buf = new StringBuffer();
 
        // validate entities throughout the string
        Matcher m = P_VALID_ENTITIES.matcher(s);
        while (m.find()) {
        	/**([^&;]*)*/
            final String one = m.group(1);
            /**(?=(;|&|$))*/
            final String two = m.group(2);
            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
        }
        m.appendTail(buf); 
        return encodeQuotes(buf.toString());
    } 
    private String encodeQuotes(final String s){
        if(encodeQuotes){
            StringBuffer buf = new StringBuffer();
            Matcher m = P_VALID_QUOTES.matcher(s);
            while (m.find()) {
            	/**(>|^)*/
                final String one = m.group(1);
                /**([^<]+?)*/
                final String two = m.group(2); 
                /**(<|$)*/
                final String three = m.group(3);
                m.appendReplacement(buf, Matcher.quoteReplacement(one + regexReplace(P_QUOTE, "&quot;", two) + three));
            }
            m.appendTail(buf);
            return buf.toString();
        }else{
            return s;
        }
    } 
    private String checkEntity(final String preamble, final String term) {
 
        return ";".equals(term) && isValidEntity(preamble)
                ? '&' + preamble
                : "&amp;" + preamble;
    } 
    private boolean isValidEntity(final String entity) {
        return inArray(entity, vAllowedEntities);
    } 
    private static boolean inArray(final String s, final String[] array) {
        for (String item : array) {
            if (item != null && item.equals(s)) {
                return true;
            }
        }
        return false;
    } 
    private boolean allowed(final String name) {
        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
    } 
    private boolean allowedAttribute(final String name, final String paramName) {
        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
    }
}

敏感词过滤工具类

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.*; 
import org.springframework.core.io.ClassPathResource;
 
/**
 * Title:      SensitiveWordUtils
 * @author:    gaodeqiang
 * @date       2018年12月12日
 * @version    V1.0
 * Description: 敏感词过滤
 */
@SuppressWarnings("all")
public class SensitiveWordUtils implements Serializable { 
	private static final long serialVersionUID = 1L; 
	private SensitiveWordUtils() {
	}
 
	private static SensitiveWordUtils sensitiveWordUtils = null;
 
	public synchronized static SensitiveWordUtils getSensitiveWordUtils() {
		if (sensitiveWordUtils == null) {
			sensitiveWordUtils = new SensitiveWordUtils();
		}
		return sensitiveWordUtils;
	} 
	private static Set<String> sensitiveWordSet = null; 
	static {
		try {
			readResource("keywords.txt");
		} catch (Exception e) {
			e.printStackTrace();
		}
		// 初始化敏感词库
		initSensitiveWordMap();
	} 
	private static final int MinMatchTYpe = 1; // 最小匹配规则,如:敏感词库["中国","中国人"],语句:"我是中国人",匹配结果:我是[中国]人
	private static final int MaxMatchType = 2; // 最大匹配规则,如:敏感词库["中国","中国人"],语句:"我是中国人",匹配结果:我是[中国人] 
	private static HashMap sensitiveWordMap = new HashMap<>();
 
	/**
	 * @author gaodeqiang
	 * @Description 读取资源文件
	 * @date 2018年12月13日上午9:29:01
	 */
	private static void readResource(String name) throws Exception {
		ClassPathResource resource = new ClassPathResource(name);
		InputStream inputStream = resource.getInputStream();
		InputStreamReader read = new InputStreamReader(inputStream, "utf-8");
		// 初始化set集合
		sensitiveWordSet = new HashSet<String>();
		// 缓冲区读取流
		BufferedReader bufferedReader = new BufferedReader(read);
		// 循环读取文件中内容,每次读取一行内容
		String txt = null;
		while ((txt = bufferedReader.readLine()) != null) {
			// 读取文件,将文件内容放入到set中
			sensitiveWordSet.add(txt);
		}
		read.close();
	} 
	/**
	 * @author gaodeqiang
	 * @Description 初始化敏感词库,构建DFA算法模型
	 * @date 2018年12月13日上午9:30:08
	 */
	private static void initSensitiveWordMap() {
		// 初始化敏感词容器,减少扩容操作
		sensitiveWordMap = new HashMap(sensitiveWordSet.size());
		String key;
		Map nowMap;
		Map<String, String> newWorMap;
		// 迭代sensitiveWordSet
		Iterator<String> iterator = sensitiveWordSet.iterator();
		while (iterator.hasNext()) {
			// 关键字
			key = iterator.next();
			nowMap = sensitiveWordMap;
			for (int i = 0; i < key.length(); i++) {
				// 转换成char型
				char keyChar = key.charAt(i);
				// 库中获取关键字
				Object wordMap = nowMap.get(keyChar);
				// 如果存在该key,直接赋值,用于下一个循环获取
				if (wordMap != null) {
					nowMap = (Map) wordMap;
				} else {
					// 不存在则,则构建一个map,同时将isEnd设置为0,因为他不是最后一个
					newWorMap = new HashMap<>();
					// 不是最后一个
					newWorMap.put("isEnd", "0");
					nowMap.put(keyChar, newWorMap);
					nowMap = newWorMap;
				}
 
				if (i == key.length() - 1) {
					// 最后一个
					nowMap.put("isEnd", "1");
				}
			}
		}
	} 
	/**
	 * @author gaodeqiang
	 * @Description 检查文字中是否包含敏感字符
	 * @date 2018年12月13日上午9:38:35
	 */
	private int checkSensitiveWord(String txt, int beginIndex, int matchType) {
		// 敏感词结束标识位:用于敏感词只有1位的情况
		boolean flag = false;
		// 匹配标识数默认为0
		int matchFlag = 0;
		char word;
		Map nowMap = sensitiveWordMap;
		for (int i = beginIndex; i < txt.length(); i++) {
			word = txt.charAt(i);
			// 获取指定key
			nowMap = (Map) nowMap.get(word);
			if (nowMap != null) {// 存在,则判断是否为最后一个
				// 找到相应key,匹配标识+1
				matchFlag++;
				// 如果为最后一个匹配规则,结束循环,返回匹配标识数
				if ("1".equals(nowMap.get("isEnd"))) {
					// 结束标志位为true
					flag = true;
					// 最小规则,直接返回,最大规则还需继续查找
					if (MinMatchTYpe == matchType) {
						break;
					}
				}
			} else {// 不存在,直接返回
				break;
			}
		}
		if (matchFlag < 2 || !flag) {// 长度必须大于等于1,为词
			matchFlag = 0;
		}
		return matchFlag;
	} 
	/**
	 * @author gaodeqiang
	 * @Description 判断文字是否包含敏感字符 匹配规则 1:最小匹配规则,2:最大匹配规则
	 * @date 2018年12月13日上午9:34:23
	 */
	public boolean contains(String txt, int matchType) {
		boolean flag = false;
		for (int i = 0; i < txt.length(); i++) {
			int matchFlag = checkSensitiveWord(txt, i, matchType); // 判断是否包含敏感字符
			if (matchFlag > 0) { // 大于0存在,返回true
				flag = true;
			}
		}
		return flag;
	} 
	/**
	 * @author gaodeqiang
	 * @Description 获取文字中的敏感词
	 * @date 2018年12月13日上午9:36:00
	 */
	public Set<String> getSensitiveWord(String txt, int matchType) {
		Set<String> sensitiveWordList = new HashSet<>();
 
		for (int i = 0; i < txt.length(); i++) {
			// 判断是否包含敏感字符
			int length = checkSensitiveWord(txt, i, matchType);
			if (length > 0) {// 存在,加入list中
				sensitiveWordList.add(txt.substring(i, i + length));
				i = i + length - 1;// 减1的原因,是因为for会自增
			}
		} 
		return sensitiveWordList;
	} 
	/**
	 * @author gaodeqiang
	 * @Description 替换敏感字字符
	 * @date 2018年12月13日上午9:36:34
	 */
	public String replaceSensitiveWord(String txt, char replaceChar, int matchType) {
		String resultTxt = txt;
		// 获取所有的敏感词
		Set<String> set = getSensitiveWord(txt, matchType);
		Iterator<String> iterator = set.iterator();
		String word;
		String replaceString;
		while (iterator.hasNext()) {
			word = iterator.next();
			replaceString = getReplaceChars(replaceChar, word.length());
			resultTxt = resultTxt.replaceAll(word, replaceString);
		} 
		return resultTxt;
	}
 
	/**
	 * @author gaodeqiang
	 * @Description 获取替换字符串
	 * @date 2018年12月13日上午9:37:53
	 */
	private String getReplaceChars(char replaceChar, int length) {
		String resultReplace = String.valueOf(replaceChar);
		for (int i = 1; i < length; i++) {
			resultReplace += replaceChar;
		}
		return resultReplace;
	}
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • IntelliJ IDEA2021.1 配置大全(超详细教程)

    这篇文章主要介绍了IntelliJ IDEA2021.1 配置大全(超详细教程),需要的朋友可以参考下...2021-04-18
  • Java实现经典游戏复杂迷宫

    这篇文章主要介绍了如何利用java语言实现经典《复杂迷宫》游戏,文中采用了swing技术进行了界面化处理,感兴趣的小伙伴可以动手试一试...2022-02-01
  • Windows VPN服务器配置图文教程 超详细版

    VPN可以虚拟出一个专用网络,让远处的计算机和你相当于处在同一个局域网中,而中间的数据也可以实现加密传输,用处很大,特别是在一些大公司,分公司处在不同的区域。...2016-01-27
  • Tomcat配置及如何在Eclipse中启动

    这篇文章主要介绍了Tomcat配置及如何在Eclipse中启动,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-02-04
  • java 运行报错has been compiled by a more recent version of the Java Runtime

    java 运行报错has been compiled by a more recent version of the Java Runtime (class file version 54.0)...2021-04-01
  • Laravel4安装配置的方法

    如果我们需要安培Laravel4的话最php最低要求要在php5.3.7版本并且我们需要把mcrypt与openss这两个扩展开启才可以,具体步骤我们参考下文。 前面我们介绍我了 com...2016-11-25
  • 在java中获取List集合中最大的日期时间操作

    这篇文章主要介绍了在java中获取List集合中最大的日期时间操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
  • 教你怎么用Java获取国家法定节假日

    这篇文章主要介绍了教你怎么用Java获取国家法定节假日,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下...2021-04-23
  • Java如何发起http请求的实现(GET/POST)

    这篇文章主要介绍了Java如何发起http请求的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-31
  • 浅谈Java与C#的一些细微差别

    说起C#和Java这两门语言(语法,数据类型 等),个人以为,大概有90%以上的相似,甚至可以认为几乎一样。但是在工作中,我也发现了一些细微的差别...2020-06-25
  • 解决Java处理HTTP请求超时的问题

    这篇文章主要介绍了解决Java处理HTTP请求超时的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29
  • 详解Maven profile配置管理及激活profile的几种方式

    这篇文章主要介绍了详解Maven profile配置管理及激活profile的几种方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-01-26
  • java 判断两个时间段是否重叠的案例

    这篇文章主要介绍了java 判断两个时间段是否重叠的案例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-08-15
  • java 画pdf用itext调整表格宽度、自定义各个列宽的方法

    这篇文章主要介绍了java 画pdf用itext调整表格宽度、自定义各个列宽的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-31
  • 超简洁java实现双色球若干注随机号码生成(实例代码)

    这篇文章主要介绍了超简洁java实现双色球若干注随机号码生成(实例代码),本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-04-02
  • 配置vue全局方法的两种方式实例

    vue项目中有一些方法需要在多个页面调用,但为了避免在每个页面都import进来,可以把方法加到原型上去,这样在每个组件中都能使用了,下面这篇文章主要给大家介绍了关于配置vue全局方法的两种方式,需要的朋友可以参考下...2021-09-13
  • IDEA如何添加配置文件到classpath中

    这篇文章主要介绍了IDEA如何添加配置文件到classpath中,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-09-19
  • Java生成随机姓名、性别和年龄的实现示例

    这篇文章主要介绍了Java生成随机姓名、性别和年龄的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-10-01
  • 查找php配置文件php.ini所在路径的二种方法

    通常php.ini的位置在:复制代码 代码如下:/etc目录下或/usr/local/lib目录下。如果你还是找不到php.ini或者找到了php.ini修改后不生效(其实是没找对),请使用如下办法:1.新建php文件,写入如下代码复制代码 代码如下:<?phpe...2014-05-31
  • 部署PHP时的4个配置修改说明

    以下就是部署PHP时的4个配置修改说明,大家一个一个进行学习研究。1、short_open_tag 是什么呢? 决定是否允许使用代码开始标志的缩写形式(<&#63; &#63;> )。如果要和 XML 结合使用PHP,可以禁用此选项以便于嵌入使用<&#63;x...2015-10-21