如何验证Spring MVC @PathVariable的值?

6mzjoqzu  于 2022-11-14  发布在  Spring
关注(0)|答案(7)|浏览(204)

对于在SpringMVC中实现的简单RESTfulJSONapi,我可以使用BeanValidation(JSR-303)来验证传递到处理程序方法中的路径变量吗?
例如:

@RequestMapping(value = "/number/{customerNumber}")
 @ResponseBody
 public ResponseObject searchByNumber(@PathVariable("customerNumber") String customerNumber) {
 ...
 }

在这里,我需要使用Bean验证来验证customerNumber变量的长度。这在Spring MVC v3.x.x中是否可行?如果不可行,那么对于这种类型的验证,最好的方法是什么?

  • 谢谢-谢谢
ehxuflar

ehxuflar1#

Spring不支援行程常式方法中@PathVariable注解参数上的@javax.validation.Valid。有改善要求,但它仍是unresolved
最好的办法是只在处理程序方法体中进行自定义验证,或者考虑使用其他答案中建议的org.springframework.validation.annotation.Validated

axr492tv

axr492tv2#

您可以这样使用:使用org.springframework.validation.annotation.Validated可使RequestParamPathVariable有效。

*
 * Variant of JSR-303's {@link javax.validation.Valid}, supporting the
 * specification of validation groups. Designed for convenient use with
 * Spring's JSR-303 support but not JSR-303 specific.
 *

步骤1初始化ValidationConfig

@Configuration
public class ValidationConfig {
    @Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        MethodValidationPostProcessor processor = new MethodValidationPostProcessor();
        return processor;
    }
}

step.2将@Validated添加到您的控制器处理程序类中,例如:

@RequestMapping(value = "poo/foo")
@Validated
public class FooController {
...
}

step.3将validators添加到处理程序方法中:

@RequestMapping(value = "{id}", method = RequestMethod.DELETE)
   public ResponseEntity<Foo> delete(
           @PathVariable("id") @Size(min = 1) @CustomerValidator int id) throws RestException {
        // do something
        return new ResponseEntity(HttpStatus.OK);
    }

最后一步。将异常解析器添加到上下文:

@Component
public class BindExceptionResolver implements HandlerExceptionResolver {

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        if (ex.getClass().equals(BindException.class)) {
            BindException exception = (BindException) ex;

            List<FieldError> fieldErrors = exception.getFieldErrors();
            return new ModelAndView(new MappingJackson2JsonView(), buildErrorModel(request, response, fieldErrors));
        }
    }
}
tpxzln5u

tpxzln5u3#

解决方案很简单:

@GetMapping(value = {"/", "/{hash:[a-fA-F0-9]{40}}"})
public String request(@PathVariable(value = "hash", required = false) String historyHash)
{
    // Accepted requests: either "/" or "/{40 character long hash}"
}

是的,PathVariables需要验证,就像任何用户输入一样。

fdx2calv

fdx2calv4#

除了使用@PathVariable,您还可以利用SpringMVC的功能将路径变量Map到bean中:

@RestController
@RequestMapping("/user")
public class UserController {

    @GetMapping("/{id}")
    public void get(@Valid GetDto dto) {
        // dto.getId() is the path variable
    }

}

Bean包含实际的验证规则:

@Data
public class GetDto {
     @Min(1) @Max(99)
     private long id;
}

确保路径变量({id})与bean字段(id)相对应;

r6hnlfcb

r6hnlfcb5#

@PathVariable并不意味着要通过验证才能将可读消息发送回用户。原则上,pathVariable不应无效。如果pathVariable无效,原因可能是:
1.一个bug生成了一个错误的url(比如jsp中的href)。不需要@Valid,也不需要任何消息,只需修复代码即可;
1.“the user”正在操作url。同样,不需要@Valid,不应该给用户任何有意义的消息。
在这两种情况下,只要让异常气泡一直保持在上面,直到它被通常的Spring ExceptionHandlers捕获,以便生成一个漂亮的错误页面或一个有意义的json响应来指示错误。为了得到这个结果,你可以使用自定义编辑器进行一些验证。
创建一个CustomerNumber类,可能是不可变的(不需要实现一个CharSequence,但允许您基本上像使用String一样使用它)

public class CustomerNumber implements CharSequence {

    private String customerNumber;

    public CustomerNumber(String customerNumber) {
        this.customerNumber = customerNumber;
    }

    @Override
    public String toString() {
        return customerNumber == null ? null : customerNumber.toString();
    }

    @Override
    public int length() {
        return customerNumber.length();
    }

    @Override
    public char charAt(int index) {
        return customerNumber.charAt(index);
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        return customerNumber.subSequence(start, end);
    }

    @Override
    public boolean equals(Object obj) {
        return customerNumber.equals(obj);
    }

    @Override
    public int hashCode() {
        return customerNumber.hashCode();
    }
}

创建一个实现验证逻辑的编辑器(在本例中没有空格,长度固定,仅作为示例)

public class CustomerNumberEditor extends PropertyEditorSupport {

    @Override
    public void setAsText(String text) throws IllegalArgumentException {

        if (StringUtils.hasText(text) && !StringUtils.containsWhitespace(text) && text.length() == YOUR_LENGTH) {
            setValue(new CustomerNumber(text));
        } else {
            throw new IllegalArgumentException();
            // you could also subclass and throw IllegalArgumentException
            // in order to manage a more detailed error message
        }
    }

    @Override
    public String getAsText() {
        return ((CustomerNumber) this.getValue()).toString();
    }
}

在控制器中注册编辑器

@InitBinder
public void initBinder(WebDataBinder binder) {

    binder.registerCustomEditor(CustomerNumber.class, new CustomerNumberEditor());
    // ... other editors
}

更改控制器方法的签名,接受CustomerNumber而不是String(无论ResponseObject是什么...)

@RequestMapping(value = "/number/{customerNumber}")
@ResponseBody
public ResponseObject searchByNumber(@PathVariable("customerNumber") CustomerNumber customerNumber) {
    ...
}
jljoyd4f

jljoyd4f6#

路径变量不能与系统中的任何Bean链接。要使用JSR-303注解来注解什么内容?要验证路径变量,应使用此方法Problem validating @PathVariable url on spring 3 mvc

mwecs4sa

mwecs4sa7#

您可以通过以下方法使用ConstraintViolationException中的字段来创建所需的答案;

@ExceptionHandler(ConstraintViolationException.class)
    protected ResponseEntity<Object> handlePathVariableError(final ConstraintViolationException exception) {
        log.error(exception.getMessage(), exception);

        final List<SisSubError> subErrors = new ArrayList<>();
        exception.getConstraintViolations().forEach(constraintViolation -> subErrors.add(generateSubError(constraintViolation)));

        final SisError error = generateErrorWithSubErrors(VALIDATION_ERROR, HttpStatus.BAD_REQUEST, subErrors);
        return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
    }

您需要将@Validated注解添加到Controller类,并在路径变量字段之前添加任何验证注解

相关问题