spring boo 拦截器教程推荐:http://lihao312.iteye.com/blog/2078139
自定义web请求参数校验拦截器,通过xml(request-validation.xml)配置url对应的字段进行校验,使校验代码通过配置文件分开,保持代码完整,更加符合领域驱动设计模式。
1.配置spring mvc的拦截器WebMvcConfigurerAdapter
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurerAdapter {
/**
* 添加拦截器
*/
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new ValidationHandlerInterceptor());
}
}
2、配置拦截器
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.whtr.nginf.infrastructure.util.JsonUtil;
import com.whtr.nginf.infrastructure.web.validation.DateValidation;
import com.whtr.nginf.infrastructure.web.validation.DatetimeValidation;
import com.whtr.nginf.infrastructure.web.validation.DigitValidation;
import com.whtr.nginf.infrastructure.web.validation.GEValidation;
import com.whtr.nginf.infrastructure.web.validation.GTValidation;
import com.whtr.nginf.infrastructure.web.validation.LEValidation;
import com.whtr.nginf.infrastructure.web.validation.LTValidation;
public class ValidationHandlerInterceptor implements HandlerInterceptor {
public static Map<String, ValidationConfig> vcMap = new ConcurrentHashMap<>();
protected Map<String, ParameterValidation> validationMap = new ConcurrentHashMap<>();
public ValidationHandlerInterceptor() {
//参数拦截拦截项参考附件
List<ParameterValidation> list = new ArrayList<>();
list.add(new StringNotBlankValidation());
list.add(new StringLengthValidation());
list.add(new DatetimeValidation());
list.add(new DateValidation());
list.add(new DigitValidation());
list.add(new NumberValidation());
list.add(new RegexValidation());
list.add(new GEValidation());
list.add(new GTValidation());
list.add(new LEValidation());
list.add(new LTValidation());
list.forEach((validation) -> validationMap.put(validation.getName(), validation));
if(validationMap.size() != list.size()) {
throw new RuntimeException("验证器名称有重复,请检查");
}
}
/**
* 预处理
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String url = request.getRequestURI();
ValidationConfig vc = vcMap.get(url);
if(vc != null) {
for(ValidationItem item : vc.getItems()) {
ParameterValidation pv = validationMap.get(item.getType());
String value = request.getParameter(item.getName());
boolean result = pv.validation(value, item.getAttach());
if(!result) {
/**
* 验证失败,直接返回
*/
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
response.getWriter().write(JsonUtil.toJson(new ResponseResult(item.getMsg(), -1)));
return false;
}
}
}
return true;
}
/**
*
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
//空方法
}
/**
*
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
//空方法
}
}
3、解析request-validation.xml,并且注册注册到拦截器
package com.whtr.nginf.application.initializer;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public final class ValidationInitializer {
private ValidationInitializer() {
throw new IllegalAccessError("Utility class");
}
private static final Logger LOG = LoggerFactory.getLogger(ValidationInitializer.class);
private static boolean initializationed = false;
/**
* doInitialization
*/
public static void doInitialization() {
if (initializationed) {
throw new RuntimeException("ValidationInitializer 已经初始化了");
}
try {
loadValidationConfig();
} catch (Exception e) {
LOG.error(e.getMessage(),e);
throw new RuntimeException("初始化验证配置出错", e);
}
initializationed = true;
}
/**
* 加载配置
* @throws IOException
* @throws ParserConfigurationException
* @throws SAXException
*
* @throws Exception
*/
private static void loadValidationConfig() throws IOException, ParserConfigurationException, SAXException {
try (InputStream input = ClassLoader.getSystemResourceAsStream("request-validation.xml")) {
int count = 0;
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(input);
NodeList nl = doc.getElementsByTagName("validation");
for (int i = 0; i < nl.getLength(); i++) {
Element node = (Element) nl.item(i);
String enable = node.getAttribute("enable");
if (StringUtils.isBlank(enable) || "true".equals(enable)) {
NodeList items = node.getElementsByTagName("item");
if (items.getLength() > 0) {
ValidationConfig vc = new ValidationConfig();
vc.setId(node.getAttribute("id"));
for (int index = 0; index < items.getLength(); index++) {
Element item = (Element) items.item(index);
vc.addItem(new ValidationItem(item.getAttribute("name"), item.getAttribute("type"),
item.getAttribute("msg"), item.getAttribute("attach")));
}
count++;
ValidationHandlerInterceptor.vcMap.put(vc.getId(), vc);
}
}
}
if (ValidationHandlerInterceptor.vcMap.size() != count) {
throw new RuntimeException("request-validation.xml 配置重复,请检查是否有相同的ID");
}
LOG.info("读取配置成功,总共读取" + count + "个配置项");
}
}
}
4、配置request-validate.xml
<?xml version="1.0" encoding="UTF-8"?> <validations> <validation id="/demo/list" enable="true"> <item name="orderKey" type="regex" msg="排序key只能是1、2、3" attach="[1|2|3]"/> <item name="clientType" type="digit" msg="clientType只能是整数" /> <item name="endDate" type="date" msg="结束日期错误,正确格式:(yyyy-MM-dd)" /> <item name="name" type="length" msg="用户名称长度不能超过10" attach="10"/> <item name="amount" type="gt" msg="本金必须大于0" attach="0"/> <item name="balance" type="number" msg="金额必须是数字" /> <item name="accountType" type="notBlank" msg="账户类型不能为空" /> </validation> <validation id="/demo/xxx" enable="true"> <item name="age" type="notBlank" msg="数据不能为空" /> </validation> </validations>