【问题标题】:How to check argument value formatting before controller method?如何在控制器方法之前检查参数值格式?
【发布时间】:2016-06-01 05:18:45
【问题描述】:

在我的控制器中,我有如下方法:

public QueryResult<TrsAccount> listExclude(String codeAccount, String searchFilter, String order, int pageNumber,
     int pageSize){}

但在执行此方法之前,我必须检查是否:

Assert.TRUE(codeAccount.matches("^[0-9]{1,20}$"));

因为这在我的应用程序中非常频繁,而且不仅是这种情况,我想要一种通用的方法来检查参数格式。我现在使用的方式是使用AOP,其中:

@Aspect
public class HijackBeforeMethod {

@Pointcut("within(@org.springframework.stereotype.Controller *)")
public void controllerBean() {
}

@Pointcut("execution(* *(..))")
public void methodPointcut() {
}

@Before(value = "controllerBean() && methodPointcut()", argNames = "joinPoint")
public void before(JoinPoint joinPoint) {

  MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  Object[] args = joinPoint.getArgs();
  String[] paramNames = signature.getParameterNames();
  for (int count = 0; count < paramNames.length; count++) {
     String tempParam = paramNames[count];
     Object tempValue = args[count];
     if (tempParam.toLowerCase().equalsIgnoreCase("codeAccount") && Assert.isNotNull(tempValue)
           && Assert.isNotEmpty((String) tempValue)) {
        Assert.TRUE(((String) tempValue).matches("^[0-9]{1,20}$"));
     }
  }
}
}

如您所见,这是非常基本且容易出错的代码 sn-p。有没有更好的解决办法??

【问题讨论】:

  • 只是不要...使用对象并通过 JSR303 验证或自定义验证器对其进行验证。

标签: java spring spring-mvc spring-aop


【解决方案1】:

真的不推荐在控制器中使用 AOP。更好的方法是to use JSR 303 / JSR 349 Bean Validation,但这可能需要将字符串包装在一个值对象中,然后对其进行相应的注释。

如果你坚持用 AOP 解决这个问题,you'll probably need a ControllerAdvice

【讨论】:

  • 如何使用 ControllerAdvice 做到这一点?谢谢。
【解决方案2】:

正如@Sean Patrick Floyd所说,使用Bean Validation更可取。

首先,定义一个从org.springframework.validation.Validator 扩展的类,例如:

@Component
public class CodeAccountValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return String.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
        if (Assert.isNotNull(target) && Assert.isNotEmpty((String) target)) {
            Assert.TRUE(((String) target).matches("^[0-9]{1,20}$"));
        }
    }
}

然后将@Validated 注释添加到您的控制器中,例如:

public QueryResult<TrsAccount> listExclude(
    @Validated(CodeAccountValidator.class)String codeAccount,
    String searchFilter,
    String order, int pageNumber,
    int pageSize) {
    ... ...
}

【讨论】:

  • 有趣,但 CodeAccountValidator 不起作用。
  • 参数codeAccount可以使用@RequestParam注解吗?
  • 也许,但这里不是。有什么区别吗?
  • 请以@M 的身份行事。 Deinum 说,这是一个标准的解决方案。我的需要更多设置,你可以查看this
【解决方案3】:

你不应该尝试用 AOP 来解决这个问题。而是使用一个对象来绑定您的属性并验证该对象。

public class QueryCriteria {
    private String codeAccount;
    private String searchFilter;
    private int pageNumber;
    private int pageSize;
    private String order;
    // Getters / Setters.
}

然后修改你的控制器方法

public QueryResult<TrsAccount> listExclude(@Valid QueryCriteria criteria, BIndingResult result) { ... }

然后使用 Spring Validator 来验证您的需求。

public QueryCriteriaValidator implements Validator {

    private final Pattern ACCOUNT_EXPR = Pattern.compile("^[0-9]{1,20}$");

    public boolean supports(Class<?> clazz) {
       return QueryCriteria.isAssignable(clazz);
    }

    public void validate(Object target, Errors errors) {
        final QueryCriteria criteria = (QueryCriteria) target;
        if (!ACCOUNT_EXPR.matcher(criteria.getCodeAccount()).matches()) {
            errors.rejectValue("codeAccount", "invalid.format");
        }
    }
}

在您的控制器方法中的@InitBinder 中注册此验证器

@InitBinder
public void initBinder(WebDataBinder binder) {
    binder.setValidator(new QueryCriteriaValidator());
}

使用 JSR-303 时,您不需要这个,您可以简单地使用 @Pattern 注释来注释 codeAccount 字段。

@Pattern(regexp="^[0-9]{1,20}$")
private String codeAccount;

验证与 Spring MVC 和使用 I18N 的错误报告很好地结合使用。因此,与其尝试用异常来解决它,不如使用框架。

我建议阅读 Spring 参考指南的 validation sectionbinding section

【讨论】:

    猜你喜欢
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 2019-07-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多