【问题标题】:Spring3 doesn't work @valid when json request I got 400 Bad Request errorSpring3 在 json 请求时不起作用 @valid 我收到 400 Bad Request 错误
【发布时间】:2013-06-15 12:10:28
【问题描述】:

我正在使用 Spring3 框架、hibernate 验证器和 jackson。

当我向服务器请求 jsondata 时。返回 400 Bad Request 错误。

那么我的数据是不匹配类型。

当我请求匹配类型时,它运行良好。

我的控制器代码:

@RequestMapping(consumes = MediaType.ALL_VALUE, produces = MediaType.ALL_VALUE,value =
    "doAdd", method = RequestMethod.POST)
@ResponseBody
public Customer doAdd(@RequestBody @Valid Customer inData){
    this.customerService.addData(inData);
    return inData;
}

错误处理方法是:

@ExceptionHandler
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public void ajaxValidationErrorHandle(MethodArgumentNotValidException errors ,
    HttpServletResponse response) throws BusinessException {
    List<String> resErrors = new ArrayList<String>();
    for(ObjectError error : errors.getBindingResult().getAllErrors()){
        resErrors.add(error.getCode());
    }
    response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    throw new BusinessException("E000001", "VALIDATION");
}

Customer.java(模型):

package test.business.model;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Range;

public class Customer {
    @Size(min = 0, max = 3)
    public String id;

    @NotNull
    @Size(min = 1)
    public String name;

    @NotNull
    @Range(min = 10, max = 99)
    public Integer age;

    public String updateTime;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(String updateTime) {
        this.updateTime = updateTime;
    }
}

json 数据:

1.{"name":"ken","age":11,"updateTime":"2013-06-18"}
2.{"name":"ken","age":"","updateTime":""}
3.{"name":"ken","age":"joe","updateTime":""}

json数据1正常返回。

json数据2正常返回(我抓到MethodArgumentNotValidException customer.age,NotNull)。

json 数据 2 返回 400 Bad Request 错误。但我希望 Server 返回 typeMismatch.int 错误。


@帕维尔·霍拉尔 非常感谢!

我可以捕获 HttpMessageNotReadableException 并进行处理。

已更改的错误处理方法。

    @ExceptionHandler
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public void ajaxValidationErrorHandle(Exception errors , HttpServletResponse response) throws BusinessException {
    if(errors instanceof MethodArgumentNotValidException){
        MethodArgumentNotValidException mane = (MethodArgumentNotValidException)errors;
        for(ObjectError error : mane.getBindingResult().getAllErrors()){
            resErrors.add(error.getCode());
        }
    }
    if(errors instanceof HttpMessageNotReadableException){
        JsonMappingException jme = (JsonMappingException)errors.getCause();
        List<Reference> errorObj = jme.getPath();
        for(Reference r : errorObj){
            System.out.println(r.getFieldName());
        }
    }
・・・

但是,就是继承做基类或者把这段代码写在所有的控制器里,感觉好像没见过spring的设计理念,因为,决定去那边处理,做一个新的ExceptionResolver。

我的新异常解析器是:

public class OriginalExceptionHandler extends SimpleMappingExceptionResolver {

@Override
public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object o, Exception e) {
    ModelAndView m = null;
    StringBuilder exceptionMessage = new StringBuilder(ajaxDefaultErrorMessage) ;
    if(e instanceof BusinessException){
                   ・・・
    }else if(e instanceof HttpMessageNotReadableException){
        Throwable t = e.getCause();
        if(t instanceof JsonMappingException){
            JsonMappingException jme = (JsonMappingException)t;
            List<Reference> errorObj = jme.getPath();
            for(Reference r : errorObj){
                exceptionMessage.append("VE9999:Unmatched Type Error!!("+r.getFieldName()+")");
            }
        }else{
            exceptionMessage.append(e+"\n"+o.toString());
        }
    }else if(e instanceof MethodArgumentNotValidException){
        MethodArgumentNotValidException mane = (MethodArgumentNotValidException)e;
        for(ObjectError error : mane.getBindingResult().getAllErrors()){
            if(error instanceof FieldError){
                FieldError fe = (FieldError) error;
                exceptionMessage.append("VE0001:Validation Error!!"+fe.getField()+"-"+fe.getDefaultMessage());
            }else{
                exceptionMessage.append("VE0001:Validation Error!!"+error.getDefaultMessage());
            }
        }
    }else{
                 ・・・

而且,我已经在 application-context.xml 中添加了香:

    <bean class="test.core.OriginalExceptionHandler" p:order="1">
    <property name="exceptionMappings">
        <props>
            <prop key="sample.core.BusinessException">
                ExceptionPage
            </prop>
            <prop key="test.core.LoginSessionException">
                LoginSessionException
            </prop>
        </props>
    </property>
    <property name="defaultErrorView" value="error" />
</bean>

这种思维方式正确吗?

谢谢,

【问题讨论】:

  • {"ken","11","2013-06-18"}{"ken","",""}{"ken","joe",""} 都不是 JSON。

标签: json spring


【解决方案1】:

数据绑定(将请求映射到对象)是一个独立于数据验证的过程。在 Spring 中,数据绑定自身的绑定错误会导致整体验证错误。

Spring 的标准 WebDataBinder 支持绑定错误,当方法参数使用 @ModelAttribute 注释时,该标准就会启动

@RequestBody 注释使用完全不同的机制 - HttpMessageConverters(在你的情况下可能是 MappingJackson2HttpMessageConverter)。当 JSON 解组失败时,将引发 HttpMessageNotReadableException 异常。

您可以在全局 HandlerExceptionResolver 中处理异常,或者在处理程序本身或全局 @ControllerAdvice 中使用特殊的 @ExceptionHandler 注释处理程序方法处理异常。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 2019-04-20
    • 1970-01-01
    • 2020-11-27
    • 2015-09-19
    • 1970-01-01
    相关资源
    最近更新 更多