@Valid JSON-запрос с BindingResult вызывает исключение IllegalStateException - PullRequest
10 голосов
/ 25 января 2012

У меня есть служба REST, которая принимает запрос JSON. Я хочу проверить поступающие значения запросов JSON. Как я могу это сделать?

В Spring 3.1.0 RELEASE я знаю, что нужно убедиться, что они используют последние классы поддержки, перечисленные в 3.1.13 Новые классы поддержки на основе HandlerMethod для обработки аннотированных контроллеров

Старые - это такие вещи, как: AnnotationMethodHandlerAdapter. Я хочу убедиться, что я использую последнюю версию, такую ​​как RequestMappingHandlerAdapter.

Это потому, что я надеюсь, что это исправит проблему, где я вижу это:

java.lang.IllegalStateException: Аргументы Errors / BindingResult объявлены без предшествующего атрибута модели. Проверьте подпись метода вашего обработчика!

Мой @Controller метод обработчика и связанный с ним код:

@Autowired FooValidator fooValidator;

@RequestMapping(value="/somepath/foo", method=RequestMethod.POST)
public @ResponseBody Map<String, String> fooBar(
        @Valid @RequestBody Map<String, String> specificRequest,
        BindingResult results) {

    out("fooBar called");

    // get vin from JSON (reportRequest)

    return null;
}


@InitBinder("specificRequest") // possible to leave off for global behavior
protected void initBinder(WebDataBinder binder){
    binder.setValidator(fooValidator);
}

FooValidator выглядит так:

@Component
public class FooValidator  implements Validator {

    public boolean supports(Class<?> clazz) {
        out("supports called ");
        return Map.class.equals(clazz);
    }

    public void validate(Object target, Errors errors) {
        out("validate called ");
    }


    private void out(String msg) {
        System.out.println("****** " + getClass().getName() + ": " + msg);
    }
}

Если я удаляю BindingResult, все работает нормально, за исключением того, что я не смогу определить, проверен ли JSON.

Я не сильно привязан к концепции использования Map<String, String> для запроса JSON или использования отдельного валидатора в отличие от пользовательского компонента с аннотацией проверки (как это сделать для запроса JSON?). Все, что может подтвердить запрос JSON.

Ответы [ 3 ]

15 голосов
/ 25 января 2012

3.1.17 @Valid On @RequestBody Аргументы метода контроллера говорит, что:

Аргумент метода @RequestBody может быть аннотирован с помощью @Valid для вызова автоматической проверки аналогак поддержке @ModelAttribute аргументов метода.Полученный MethodArgumentNotValidException обрабатывается в DefaultHandlerExceptionResolver и приводит к коду ответа 400.

Другими словами, если вы используете @Valid @RequestBody, тогда Spring отклонит неверный запрос перед этимдоходит до вызова вашего метода.если ваш метод вызван , то вы можете предположить, что тело запроса допустимо.

BindingResult используется для проверки объектов формы / команды, а не @RequestBody.

6 голосов
/ 08 февраля 2012

Я должен был сделать что-то подобное один раз.Я просто сделал свою жизнь проще, создав объект Java, в который JSON можно было бы преобразовать и использовать GSON для преобразования.

На самом деле все было просто:

@Autowired
private Gson gson;

@RequestMapping(value = "/path/info", method = RequestMethod.POST)
public String myMethod(@RequestParam(value = "data") String data,
                       Model model,
                       @Valid MyCustomObject myObj,
                       BindingResult result) {
    //myObj does not contain any validation information.
    //we are just using it as as bean to take advantage of the spring mvc framework.
    //data contains the json string.
    myObj = gson.fromJson(data, MyCustomObject.class);

    //validate the object any way you want. 
    //Simplest approach would be to create your own custom validator 
    //to do this in Spring or even simpler would be just to do it manually here.
    new MyCustomObjValidator().validate(myObj, result);

    if (result.hasErrors()) {
        return myErrorView;
    }
    return mySuccessView;
}

Выполните все проверки в своем пользовательском Validator классе:

public class MyCustomObjValidator implements Validator {

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

    @Override
    public void validate(Object target, Errors errors) {
        MyCustomObj c = (MyCustomObj) target;
        Date startDate = c.getStartDate();
        Date endDate = c.getEndDate();
        if (startDate == null) {
            errors.rejectValue("startDate", "validation.required");
        }
        if (endDate == null) {
            errors.rejectValue("endDate", "validation.required");
        }
        if(startDate != null && endDate != null && endDate.before(startDate)){
            errors.rejectValue("endDate", "validation.notbefore.startdate");
        }
    }

}

MyCustomObject не содержит никаких комментариев для проверки, это потому, что иначе Spring попытается проверить этополя в этом объекте, которые в настоящее время пусты, потому что все данные находятся в строке JSON, это может быть, например:

public class MyCustomObject implements Serializable {
    private Date startDate;
    private Date endDate;

    public Date getStartDate() {
        return startDate;
    }

    public Date getEndDate() {
        return endDate;
    }

    public void setStartDate(Date theDate) {
        this.startDate = theDate;
    }

    public void setEndDate(Date theDate) {
        this.endDate = theDate;
    }
}
1 голос
/ 27 июля 2012

Попробуйте использовать следующее:

@Autowired
private FooValidator fooValidator;

@InitBinder("specificRequest") // possible to leave off for global behavior
protected void initBinder(WebDataBinder binder){
    binder.setValidator(fooValidator);
}
@ModelAttribute("specificRequest")
public Map<String, String> getModel() {
    return new HashMap<String, String>();
}

Это заставит ваш контроллер сериализовать запрос в указанный вами тип.Я должен сказать, что обычно я не делаю сервис (автонастройка) валидатора, но он мог бы быть лучше.

Ваш обработчик теперь выглядит так:отлично и исправляет ошибку, которую вы получаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...