场景说明
- Spring 已经集成支持hibernate-validator校验,可在controller 或service层自定义切面对参数进行校验
- 但是由于遇到的业务场景,是需要对上传的Excel数据解析后才做校验(当然也可以扔到切面做,但有些过于麻烦),同时兼容i18n方式
- 所以写下这篇文章记录用原生依赖方式做特殊的业务逻辑自定义i18n校验
1. 校验代码
相关依赖
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.19</version>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
Controller
@RestController
@RequestMapping("/test")
public class Controller {
@PostMapping("/add")
public String test(@RequestBody UserReq req) {
ValidatorUtils.validateEntity(req);
return "success";
}
}
请求类
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
@Data
public class UserReq {
@NotBlank(message = "{username-null}")
private String name;
@NotBlank(message = "{passwd-null}")
private String passwd;
}
校验工具
import cn.hutool.core.io.FileUtil;
import org.hibernate.validator.resourceloading.PlatformResourceBundleLocator;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Handler;
/**
* hibernate-validator校验工具类
*/
public class ValidatorUtils {
//缓存
static HashMap<String,Validator> validateMap = new HashMap<>();
static {
List<String> i18nFiles = FileUtil.listFileNames("classpath:i18n");
i18nFiles.stream().forEach(fileName->{
boolean defaultLang = fileName.indexOf("_") < 0;
String lang = "";
//若没有相关的语言设置,那就是message.properties文件
if (defaultLang ) {
Locale.setDefault(new Locale(lang)) ;
}
//对应相应的message_* 文件
if (!defaultLang){
lang = fileName.substring(fileName.indexOf("_") + 1, fileName.indexOf("."));
Locale.setDefault(new Locale(lang)) ;
}
Validator validator = Validation.byDefaultProvider().configure()
//指定i18n资源位于/resources/i18n/message_* 的文件
.messageInterpolator(new I18nMessageInterpolator(new PlatformResourceBundleLocator("i18n/message")))
.buildValidatorFactory()
.getValidator();
validateMap.put(lang,validator);
});
}
/**
* 校验对象
* @param object 校验对象
* @param groups 校验的组
*/
public static void validateEntity(Object object, Class<?>... groups) throws RuntimeException {
String lang = getLang();
Validator validator = validateMap.get(lang);
Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
ConstraintViolation<Object> constraint = (ConstraintViolation<Object>)constraintViolations.iterator().next();
throw new RuntimeException(constraint.getMessage());
}
}
//获取请求头的lang属性
public static String getLang(){
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
if(Objects.isNull(ra)){
return null;
}
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest();
return request.getHeader("lang");
}
}
I18N 配置校验拦截器
import org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator;
import org.hibernate.validator.spi.resourceloading.ResourceBundleLocator;
import java.nio.charset.StandardCharsets;
public class I18nMessageInterpolator extends ResourceBundleMessageInterpolator {
public I18nMessageInterpolator(ResourceBundleLocator userResourceBundleLocator) {
super(userResourceBundleLocator);
}
@Override
public String interpolate(String message, Context context) {
String result = super.interpolate(message, context);
return new String(result.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
}
}
2.I18N资源文件
message.properties
username-null=username1 not empty
passwd-null=password1 not empty
message_en.properties
username-null=username2 not empty
passwd-null=password2 not empty
message_zh.properties
username-null=用户名不能为空
passwd-null=密码不能为空
3.请求与测试
http://localhost:8080/test/add
POST
{
"name": null,
"passwd": "guest"
}
请求头使用lang切换不同的语言测试,lang=en、lang=zh