基于Struts2+Java7的前端波罗的海字符过滤通用方案选型咨询
针对波罗的海字符输入拦截的最优方案分析(Struts2 + Java7 + JSP-Servlet)
先直接给结论:优先选择基于HttpServlet Filter的全局请求参数遍历检查方案,它能同时适配Struts2和原生JSP-Servlet架构,实现成本低、复用性强,完全覆盖你的业务场景。下面详细对比两种思路,并补充其他可行方案:
一、两种思路的优劣对比
1. 反射遍历请求Bean对象(Struts2专属)
- 优势:贴合Struts2的MVC模型,直接处理Action中封装的业务Bean,能针对复杂嵌套对象的属性做检查。
- 劣势:
- 只能覆盖Struts2场景,完全无法处理原生JSP-Servlet的请求参数,需要单独为Servlet写一套逻辑,维护成本翻倍。
- 反射操作需要额外处理Bean的访问权限(比如私有属性的getter方法),如果系统中Bean没有统一的父类或注解标记,遍历所有属性容易误检内部业务字段。
- 性能略低于直接遍历请求参数(反射的方法调用开销)。
2. 遍历HttpServlet请求参数(全局通用)
- 优势:
- 完美适配Struts2和JSP-Servlet两种架构:不管请求是被Struts2的核心Filter处理,还是直接交给Servlet,自定义Filter都能在请求到达业务逻辑前拦截检查。
- 实现简单:直接通过
request.getParameterMap()获取所有请求参数键值对,不需要关心后端的Bean结构,只需要检查参数值本身。 - 可扩展性强:可以通过配置URL白名单(比如你提到的13个支持波罗的海字符的菜单),避免对合法请求做无效检查。
- 劣势:
- 如果存在POST提交的复杂JSON请求体(而非表单键值对),需要额外读取请求流并解析JSON后检查,但从你的场景描述看,应该以表单提交为主,这个问题影响不大。
二、最优方案的具体实现步骤
1. 编写自定义Filter
public class BalticCharFilter implements Filter { // 波罗的海字符正则匹配(包含所有需要拦截的字符) private static final String BALTIC_CHAR_PATTERN = "[ĀāČčĒēĢģĪīĶķĻļŅņŌōŠšŪūŽž]"; // 白名单URL(13个支持波罗的海字符的菜单路径,可从配置文件读取) private Set<String> whiteListUrls; @Override public void init(FilterConfig filterConfig) throws ServletException { // 初始化白名单,比如从web.xml的init-param读取 String whiteListStr = filterConfig.getInitParameter("whiteListUrls"); if (whiteListStr != null) { whiteListUrls = new HashSet<>(Arrays.asList(whiteListStr.split(","))); } else { whiteListUrls = new HashSet<>(); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; // 检查当前请求是否在白名单内,跳过检查 String requestUrl = httpRequest.getRequestURI(); if (whiteListUrls.stream().anyMatch(requestUrl::contains)) { chain.doFilter(request, response); return; } // 设置正确的字符集,避免参数乱码 request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8"); // 遍历所有请求参数,检查波罗的海字符 Map<String, String[]> paramMap = request.getParameterMap(); boolean hasBalticChar = false; for (String[] values : paramMap.values()) { for (String value : values) { if (value != null && value.matches(".*" + BALTIC_CHAR_PATTERN + ".*")) { hasBalticChar = true; break; } } if (hasBalticChar) break; } if (hasBalticChar) { // 返回错误提示,比如跳转到错误页面或输出JSON提示 httpResponse.sendRedirect(httpRequest.getContextPath() + "/error.jsp?msg=请不要输入波罗的海字符"); // 如果是AJAX请求,可返回JSON: // response.setContentType("application/json"); // response.getWriter().write("{\"code\":400,\"msg\":\"请不要输入波罗的海字符\"}"); return; } // 无违规字符,继续执行请求 chain.doFilter(request, response); } @Override public void destroy() { // 清理资源 } }
2. 配置Filter到web.xml
注意要把这个Filter放在Struts2核心Filter(org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter)之前,确保先执行参数检查:
<filter> <filter-name>BalticCharFilter</filter-name> <filter-class>com.yourcompany.filter.BalticCharFilter</filter-class> <init-param> <param-name>whiteListUrls</param-name> <param-value>/support/menu1,/support/menu2</param-value> <!-- 替换为你的13个菜单路径 --> </init-param> </filter> <filter-mapping> <filter-name>BalticCharFilter</filter-name> <url-pattern>/*</url-pattern> <!-- 拦截所有请求 --> </filter-mapping> <!-- 原有的Struts2 Filter --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
三、其他补充方案(作为辅助)
1. 前端双重校验
在表单提交前用JavaScript检查输入内容,提前给用户提示,减少无效请求:
function checkBalticChar(input) { const pattern = /[ĀāČčĒēĢģĪīĶķĻļŅņŌōŠšŪūŽž]/; if (pattern.test(input.value)) { alert("请不要输入波罗的海字符"); input.focus(); return false; } return true; }
注意:前端校验只能作为辅助,不能替代后端Filter,因为用户可以通过禁用JS或直接构造请求绕过前端检查。
2. Struts2拦截器(可选)
如果只针对Struts2场景做更精细的Bean检查,可以写自定义拦截器,结合OGNL或反射遍历Action的属性:
public class BalticCharInterceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation invocation) throws Exception { Object action = invocation.getAction(); // 遍历Action的属性(可通过反射或BeanUtils) BeanInfo beanInfo = Introspector.getBeanInfo(action.getClass()); for (PropertyDescriptor pd : beanInfo.getPropertyDescriptors()) { Method getter = pd.getReadMethod(); if (getter != null) { Object value = getter.invoke(action); if (value instanceof String) { String strValue = (String) value; if (strValue.matches(".*[ĀāČčĒēĢģĪīĶķĻļŅņŌōŠšŪūŽž].*")) { // 抛出异常或返回错误Result return "input"; } } } } return invocation.invoke(); } }
然后在struts.xml中配置拦截器栈,应用到需要的Action上,但这种方案无法覆盖Servlet场景,所以还是Filter更通用。
总结
综合你的业务场景(两种架构并存、90个菜单需要统一处理),全局Filter方案是最优选择,它能一次性解决所有请求的参数检查问题,实现成本低、维护简单,且能和前端校验形成双重保障。
内容的提问来源于stack exchange,提问作者cFrags
相关产品推荐
相关产品推荐

