需求:
- 方法注解实现参数验证
- 消息文件存储消息字符串
实现:
- 注解定义
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface ValidBody {
String desc() default "aop annotation for body validation";
}
- 切面Aspect
@Aspect
public class BodyValidationAspect {
private static final int DEFAULT_MAX_RETRIES = 2;
private int maxRetries = DEFAULT_MAX_RETRIES;
private int order = 2;
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxRetries;
}
public int getOrder() {
return this.order;
}
public void setOrder(int order) {
this.order = order;
}
@Autowired
private ValidatorFactory validatorFactory;
@Before("pointcut()")
public void before(JoinPoint point) throws Exception {
Object[] args = point.getArgs();
BaseReqBody param = getBaseReqBodyFromArgs(args);
if(param == null)
return ;
Validator validator = validatorFactory.getValidator();
Set<ConstraintViolation<BaseReqBody>> requestViolations = validator.validate(param);
boolean requestHasViolations = !requestViolations.isEmpty();
if(requestHasViolations){
ConstraintViolation<BaseReqBody> requestViolation = requestViolations.iterator().next();
throw new ReqException(PARAM_INVALID, processForParaName(requestViolation.getMessage(),requestViolation));
}
}
private String processForParaName(String oriMessage,ConstraintViolation<BaseReqBody> requestViolation){
if(oriMessage.contains("paramName")){
return oriMessage.replaceAll("paraName",requestViolation.getPropertyPath().iterator().next().getName());
}
return oriMessage;
}
public BaseReqBody getBaseReqBodyFromArgs(Object[] args){
for(Object arg : args){
if(arg.getClass().getSuperclass().equals(BaseReqBody.class)||arg instanceof BaseReqBody)
return (BaseReqBody)arg;
}
return null;
}
@Pointcut("@annotation(com.xxxx.xx.xx.annotation.ValidBody)")
public void pointcut(){}
}
使用
@Override
@ValidBody
public TerminalScanOrderCreateRespBody addMerchantOrder(TerminalScanOrderCreateReqBody body) throws Exception {
return null;
}
public class TerminalScanOrderCreateReqBody extends BaseReqBody {
@JSONField(name = "ts_no")
@JsonProperty("ts_no")
@NotEmpty(message = "${NotEmpty}")
@Size(max = 32,message = "${Size}")
private String tsNo;//ts_no
@JSONField(name = "ts_time", format = "yyyy-MM-dd HH:mm:ss")
@JsonProperty("ts_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date tsTime;//ts_time
@JSONField(name = "order_fee")
@JsonProperty("order_fee")
@NotEmpty(message = "${NotEmpty}")
@Size(max = 12,message = "${Size}")
@Money
private String orderFee;//order_fee
@NotEmpty(message = "${NotEmpty}")
@Size(max = 12,message = "${Size}")
@Money
private String fee;//fee
@JSONField(name = "coin_type")
@JsonProperty("coin_type")
@NotEmpty(message = "${NotEmpty}")
@Size(max = 16,message = "${Size}")
private String coinType;//coin_type
@JSONField(name = "coupon_code")
@JsonProperty("coupon_code")
@NotEmpty(message = "${NotEmpty}")
@Size(max = 32,message = "${Size}")
private String couponCode;//coupon_code
@JSONField(name = "mch_code")
@JsonProperty("mch_code")
@NotEmpty(message = "${NotEmpty}")
@Size(max = 32,message = "${Size}")
private String shopCode;//mch_code
@NotEmpty(message = "${NotEmpty}")
@Size(max = 32,message = "${Size}")
private String sn;
@JSONField(name = "operator_id")
@JsonProperty("operator_id")
@NotEmpty(message = "${NotEmpty}")
@Size(max = 32,message = "${Size}")
private String operatorId;//operator_id
public TerminalScanOrderCreateReqBody() {
}
//getter setter
}
坑
- 消息模板EL 表达式不生效
- 原因
<property name="useCodeAsDefaultMessage" value="true" />
- 原因
CommonMessage.properties
NotEmpty = param paramName can not be empty
Size = {validatedValue} is too long for paramName
Money = {validatedValue} wrong format for paramName
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>i18n/messages/BaseRespMesage</value>
<value>i18n/messages/BizMessage</value>
<value>i18n/messages/CommonMessage</value>
</list>
</property>
<property name="fileEncodings">
<value>utf-8</value>
</property>
<property name="useCodeAsDefaultMessage" value="false" />
<property name="cacheSeconds" value="120"></property>
</bean>