【问题标题】:Spring rest controller @RequestParam validationSpring 休息控制器@RequestParam 验证
【发布时间】:2018-01-17 13:49:45
【问题描述】:

我想验证请求参数。我浏览了许多博客并回答并做了同样的事情。 在控制器类上添加了@Validated。

控制器中的方法:

public ResponseEntity<Employee> getHistory(
@Valid @Pattern(regexp = "^[A-Z]{2}[0-9]{6}[A-Z]{0,1}$", message = "Invalid 
emp") @NotNull(message = "input cannot be null") @RequestParam(name = "emp") 
String emp) { method body..........}

控制器建议

@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public String handleValidationFailure(ConstraintViolationException ex) {

  StringBuilder messages = new StringBuilder();

  for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
      messages.append(violation.getMessage() + "\n");
  }

  return messages.toString();
}

配置:

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
  return new MethodValidationPostProcessor();
}

现在完成所有这些操作后,我收到了 404 错误。 "status":404,"error":"Not Found","message":"没有可用的消息"

【问题讨论】:

  • 我用的是弹簧靴
  • 您的日志中有更详细的错误吗?
  • 日志中没有异常
  • 你之前有没有处于工作状态?
  • 是的,从控制器中删除 @validation 后它工作正常。但是请求参数没有得到验证

标签: spring rest spring-mvc spring-boot


【解决方案1】:

您在控制器建议中的方法上缺少 @ResponseBody 注释。它会导致错误,因为 Spring 正在尝试从该方法中查找名称返回为 String 的模板,因此在 REST 调用期间您会得到如下内容:

{
    "error": "Not Found", 
    "exception": "javax.validation.ConstraintViolationException", 
    "message": "No message available", 
    "path": "/history", 
    "status": 404, 
    "timestamp": 1502293311543
}

handleValidationFailure(ConstraintViolationException ex)方法添加@ResponseBody注解意味着当你返回一个String时,它不是模板名而是响应对象本身。

或者,您可以在您的通知方法中使用ResponseEntity&lt;String&gt; 作为返回类型,例如

@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
public ResponseEntity<String> handleValidationFailure(ConstraintViolationException ex) {
    StringBuilder messages = new StringBuilder();

    for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
        messages.append(violation.getMessage());
    }

    return ResponseEntity.badRequest().body(messages.toString());
}

因此您不必使用@ResponseBody 来注释方法,Spring 现在将您的响应不是视图名称而是响应主体本身。希望对你有帮助。

更新

我假设您调用的端点不正确。我创建了一个小型 Spring Boot 应用程序,它使用提供的信息复制您的问题:

https://github.com/wololock/rest-validation-demo

随意克隆它并运行它。运行后你可以尝试调用/history端点:

curl "localhost:8080/history?emp=AZ000001A"

它会作为回报显示:

{"id":"AZ000001A","name":"Joe Doe"}%

如果您使用违反验证规则的emp 调用此端点:

curl "localhost:8080/history?emp=sd"

您将收到以下回复:

{"message":"Your request contains errors","errors":[{"getHistory.arg0":"Invalid emp"}]}

我的假设是,在您的情况下,您错误地调用了端点。使用@RestController 注解存在普遍的误解。我看到人们像@RestController("/someRootPath") 这样使用它,然后他们希望有像

这样的端点
localhost:8080/someRootPath/...

这是不正确的。传递给@RestController注解的值只不过是:

该值可能表示对逻辑组件名称的建议,在自动检测到组件的情况下将其转换为 Spring bean。

您可以随时查看控制台日志以查看您的控制器的最终映射是什么,例如

2017-08-09 20:40:45.663  INFO 1340 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@6385cb26: startup date [Wed Aug 09 20:40:44 CEST 2017]; root of context hierarchy
2017-08-09 20:40:45.696  INFO 1340 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/history],methods=[GET]}" onto public org.springframework.http.ResponseEntity<com.github.wololock.restvalidationdemo.Employee> com.github.wololock.restvalidationdemo.EmployeeController.getHistory(java.lang.String)
2017-08-09 20:40:45.698  INFO 1340 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2017-08-09 20:40:45.698  INFO 1340 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2017-08-09 20:40:45.708  INFO 1340 --- [           main] o.s.w.s.h.BeanNameUrlHandlerMapping      : Mapped URL path [/employee] onto handler '/employee'
2017-08-09 20:40:45.714  INFO 1340 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2017-08-09 20:40:45.714  INFO 1340 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]

希望对你有帮助。

【讨论】:

  • 我做了同样的事情,但没有运气:(同样的 {"timestamp":1502294676236,"status":404,"error":"Not Found","message":"No message available", "路径":"*****"}
  • 我得到这个甚至是有效数据
  • @ChandreshMishra 请查看更新后的答案。我准备了一个小型 Spring Boot 应用程序来复制您的验证问题。它应该可以帮助您解决问题。
  • 感谢您的代码。这对我帮助很大。我感谢你的努力。我在我的代码中发现了问题,并在您的代码库中复制了同样的问题。我的控制器类正在实现具有合同的接口。如果添加实现 EmployeeContract public interface EmployeeContract { public ResponseEntity getHistory(String emp); } 你会得到 404 错误。
  • @ChandreshMishra 我已经用你之前提到的接口更新了代码,但它不像你描述的那样工作。 @Validated注解+实现接口似乎在Spring中被打破了。添加此接口并保留@Validated 注释后,它会使/history 端点未映射到应用程序,这很奇怪。我从来没有使用过控制器接口,建议你也这样做。定义接口更有意义,例如对于可以使用@Autowired 注入控制器的服务。如果我找到根本原因,我会发布更新。
猜你喜欢
  • 1970-01-01
  • 2018-12-27
  • 1970-01-01
  • 2019-11-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 1970-01-01
相关资源
最近更新 更多