在web项目中,经常会通过Map进行接收参数进行查询,其中经常有这样的需求,需要对某个参数要验证必须有值,要验证某些参数的传参格式是否符合需要的类型。
经常是这样的实现:
@PostMapping(value = "/user/list")
public String list(Map<String, Object> params) {
Object userName = params.get("userName");
if(userName == null || String.valueOf(userName).equal("")) {
return "参数userName不能空"!
}
}
@PostMapping(value = "/role/list")
public String list(Map<String, Object> params) {
Object roleName = params.get("role");
if(roleName == null || String.valueOf(roleName).equal("")) {
return "角色名称不能为空"!
}
}
类似这样的一些列表进行查询的时候都需要参数进行校验,当有多这样的查询的时候都需要写相关的校验,这时就会显得很冗余,如何解决该类型的写法呢?
下面介绍项目中常用的一种实现,基于validation-api的验证。
定义检查类:
@Constraint(validatedBy = RequiredFieldCheckImpl.class)
@Target(value = {ElementType.PARAMETER})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
public @interface RequiredFieldCheck {
/**
* 拦截的字符串
*
* @return
*/
String[] requiredField() default {};
/**
* 值类型.
*
* @return
*/
String[] requiredFieldValueType() default {};
/**
* 验证不通过时的错误提示信息
* @return
*/
String message() default "参数值不能为空!";
/**
* 分组
* @return
*/
Class<?>[] groups() default {};
/**
* 负载
* @return
*/
Class<? extends Payload>[] payload() default {};
/**
* 分页页数
* @return
*/
int pageNum() default 1;
/**
* 分页条数
* @return
*/
int pageSize() default 10;
}
检查类的具体实现:
public class RequiredFieldCheckImpl implements ConstraintValidator<RequiredFieldCheck, Map<String, Object>> {
private String[] required;
private int pageSize;
private int pageNum;
//private String[] requiredType;
private Map<String, String> fieldTypeMap;
/**
* 初始化
*
* @param constraintAnnotation
*/
@Override
public void initialize(RequiredFieldCheck constraintAnnotation) {
this.required = constraintAnnotation.requiredField();
this.pageNum = constraintAnnotation.pageNum();
this.pageSize = constraintAnnotation.pageSize();
String[] checkFieldType = constraintAnnotation.requiredFieldValueType();
fieldTypeMap = new HashMap<>();
for (String type : checkFieldType) {
String[] tmps = type.split(":");
fieldTypeMap.put(tmps[0], tmps[1]);
}
TopsecLogUtil.info("check field :" + ArrayUtil.join(required, ","));
}
/**
* 检验逻辑
*
* @param value
* @param context
* @return
*/
@Override
public boolean isValid(Map<String, Object> value, ConstraintValidatorContext context) {
if (ArrayUtil.isEmpty(required)) {
return true;
}
if (CollUtil.isEmpty(value)) {
bulidValidResult(context, ArrayUtil.join(required, ","));
return false;
}
for (String each : required) {
if (!value.containsKey(each) || StrUtil.isEmpty(value.get(each).toString())) {
bulidValidResult(context, each);
return false;
}
/* if (fieldTypeMap.containsKey(each)) {
if(!bulidParams(fieldTypeMap.get(each), value, each)) {
bulidValidTypeResult(context, each);
return false;
}
}*/
}
for(String key : fieldTypeMap.keySet()) {
if(value.containsKey(key) && value.get(key) != null) {
if(!bulidParams(fieldTypeMap.get(key), value, key)) {
bulidValidTypeResult(context, key);
return false;
}
}else {
initParams(fieldTypeMap.get(key),value, key);
}
}
if (!value.containsKey(Pages.pageNum.getName())) {
value.put(Pages.pageNum.getName(), pageNum);
}
if (!value.containsKey(Pages.pageSize.getName())) {
value.put(Pages.pageSize.getName(), pageSize);
}
return true;
}
private void initParams(String valueType, Map<String, Object> params, String field) {
try {
switch (valueType) {
case "Long[]":
params.put(field, new Long[]{});
break;
case "Long":
params.put(field, 0L);
break;
case "String[]":
params.put(field, new String[]{});
break;
}
}catch (Exception e) {
e.printStackTrace();
}
}
private Boolean bulidParams(String valueType, Map<String, Object> params, String field) {
try {
switch (valueType) {
case "Long[]":
List<Integer> clueIds = (List<Integer>)params.get(field);
Long[] clueIdsLong = new Long[clueIds.size()];
for(int i=0; i<clueIds.size(); i++) {
clueIdsLong[i] = clueIds.get(i).longValue();
}
params.put(field, clueIdsLong);
break;
case "Long":
String value = String.valueOf(params.get(field));
params.put(field, Long.parseLong(value));
break;
case "String[]":
List<String> strList = (List<String>)params.get(field);
String[] strArray = new String[strList.size()];
for(int i=0; i<strList.size(); i++) {
strArray[i] = strList.get(i);
}
params.put(field, strArray);
break;
}
return Boolean.TRUE;
}catch (Exception e) {
e.printStackTrace();
}
return Boolean.FALSE;
}
/**
* 构建校验出错信息!
*
* @param context
* @param message
*/
private void bulidValidResult(ConstraintValidatorContext context, String message) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("[" + message + "]参数不能为空!").addConstraintViolation();
}
/**
* 构建校验出错信息!
*
* @param context
* @param message
*/
private void bulidValidTypeResult(ConstraintValidatorContext context, String message) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("[" + message + "]值格式不对!").addConstraintViolation();
}
}
用法: 类需要添加@Validated, requiredField 字段包括必填字段,requiredFieldValueType 字段是参数要求的类型
@ApiOperation(value = "xxx列表", notes = "")
@PostMapping(value = "/list")
public void list(
@RequestBody @RequiredFieldCheck(requiredField = {"pageNum", "pageSize"},
requiredFieldValueType={"tags:String[]"}) Map<String, Object> params) {
}