java配置多个过滤器优先级以及几个常用过滤器操作
目录
- 过滤器配置:
- 常用过滤器之一:
- 常用过滤器之二:
- 敏感词过滤工具类
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 * @date2018年10月25日 * @versionV1.0 * Description: 过滤器配置 */@SuppressWarnings("all")@Configurationpublic 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; } }
【java配置多个过滤器优先级以及几个常用过滤器操作】
常用过滤器之一: 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 = https://www.it610.com/article/cookies[i].getValue(); if ("user_accesstoken".equals(name)) { // 用户tokenreq.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 * @date2018年8月16日 * @versionV1.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 * @date2018年8月16日 * @versionV1.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; } @Overridepublic 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() {@Overridepublic boolean isFinished() {return true; } @Overridepublic boolean isReady() {return true; } @Overridepublic void setReadListener(ReadListener readListener) { } @Overridepublic int read() throws IOException {return bis.read(); }}; } @Overridepublic String getParameter(String name) {String value = https://www.it610.com/article/super.getParameter(xssEncode(name)); if (StringUtils.isNotBlank(value)) {value = xssEncode(value); }return value; } @Overridepublic 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; } @Overridepublic Map getParameterMap() {Map map = new LinkedHashMap<>(); Map 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; } @Overridepublic String getHeader(String name) {String value = https://www.it610.com/article/super.getHeader(xssEncode(name)); if (StringUtils.isNotBlank(value)) {value = xssEncode(value); }return value; }//富文本内容放行private String xssEncode(String input) {if(!input.startsWith("")) {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 * @date2018年8月16日 * @versionV1.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("([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 P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap(); private static final ConcurrentMap P_REMOVE_SELF_BLANKS = new ConcurrentHashMap(); /** set of allowed html elements, along with allowed attributes for each element **/private final Map> vAllowed; /** counts of open tags for each (allowable) html element **/private final Map vTagCounts = new HashMap(); /** html elements which must always be self-closing (e.g. "") **/private final String[] vSelfClosingTags; /** html elements which must always have separate opening and closing tags (e.g. "") **/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. "" or "") **/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. "" becomes " text ").If set to false,* unbalanced angle brackets will be html escaped.*/private final boolean alwaysMakeTags; /** Default constructor.**/public HtmlFilter() {vAllowed = new HashMap<>(); final ArrayList aAtts = new ArrayList(); aAtts.add("href"); aAtts.add("target"); vAllowed.put("a", aAtts); final ArrayList imgAtts = new ArrayList(); imgAtts.add("src"); imgAtts.add("width"); imgAtts.add("height"); imgAtts.add("alt"); vAllowed.put("img", imgAtts); final ArrayList noAtts = new ArrayList(); 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 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>) 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, "& ", result); result = regexReplace(P_QUOTE, "" ", result); result = regexReplace(P_LEFT_ARROW, "< ", result); result = regexReplace(P_RIGHT_ARROW, "> ", 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("")); }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, "< $1", s); s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2> <", 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 tagsMatcher 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 tagsm = 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 paramNames = new ArrayList(); final List paramValues = new ArrayList(); 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 = https://www.it610.com/article/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 ""; }}// commentsm = 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 insteads = "#" + 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 stringMatcher 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, "" ", 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: "& " + 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 * @date2018年12月12日 * @versionV1.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 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(); // 缓冲区读取流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 newWorMap; // 迭代sensitiveWordSetIterator 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; // 匹配标识数默认为0int matchFlag = 0; char word; Map nowMap = sensitiveWordMap; for (int i = beginIndex; i < txt.length(); i++) {word = txt.charAt(i); // 获取指定keynowMap = (Map) nowMap.get(word); if (nowMap != null) {// 存在,则判断是否为最后一个// 找到相应key,匹配标识+1matchFlag++; // 如果为最后一个匹配规则,结束循环,返回匹配标识数if ("1".equals(nowMap.get("isEnd"))) {// 结束标志位为trueflag = 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存在,返回trueflag = true; }}return flag; } /*** @author gaodeqiang* @Description 获取文字中的敏感词* @date 2018年12月13日上午9:36:00*/ public Set getSensitiveWord(String txt, int matchType) {Set 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 set = getSensitiveWord(txt, matchType); Iterator 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; }}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- vue-cli|vue-cli 3.x vue.config.js 配置
- 事件代理
- Java|Java OpenCV图像处理之SIFT角点检测详解
- java中如何实现重建二叉树
- 数组常用方法一
- 【Hadoop踩雷】Mac下安装Hadoop3以及Java版本问题
- 从战略性的角度可以配置股票
- Java|Java基础——数组
- RxJava|RxJava 在Android项目中的使用(一)