Как Spring MVC разрешает и проверяет параметры метода обработчика?

Я новичок в Spring MVC, и я импортировал учебный проект, связанный с проверкой на стороне сервера, и у меня есть некоторые сомнения в том, как именно он работает.

Итак, у меня есть страница входа с именем login.jsp, содержащая эту форму входа:

<form:form action="${pageContext.request.contextPath}/login" commandName="user" method="post">

    <table>

        <tr>
            <td><label>Enter Username : </label></td>
            <td><form:input type="text" path="username" name="username" />
                <br> <form:errors path="username" style="color:red;"></form:errors>
            </td>
        </tr>

        <tr>
            <td><label>Enter Password : </label></td>
            <td><form:input type="password" path="password" name="password" />
                <br> <form:errors path="password" style="color:red;"></form:errors>
            </td>
        </tr>

        <tr>
            <td>&nbsp</td>
            <td align="center"><input type="submit" value="Login" /></td>
        </tr>

    </table>

</form:form>

что я думаю использовать объект, указанный атрибутом commandName = "user", полученным из модели (исправьте меня, если я делаю неправильное утверждение), чтобы сохранить имя пользователя и пароль, введенные пользователем.

Этот commandName = "user" является экземпляром этого класса User:

import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.NotBlank;

public class User {

    @NotBlank(message="Username can not be blank")
    private String username;

    @Size(min=6,message="Password must be atleast 6 characters long")
    private String password;

    private String gender;
    private String vehicle;
    private String country;
    private String image;

    ...............................................
    ...............................................
    GETTER AND SETTER METHODS
    ...............................................
    ...............................................
}

Как видите, в полях имя пользователя и пароль объявлены аннотации проверки @NotBlank и @Size. .

И тут первое сомнение: в чем именно отличие от 2-х используемых библиотек javax.validation и org.hibernate.validator?

Почему в учебнике используются оба варианта? Могу ли я сделать то же самое, используя только библиотеку валидатора гибернации? (Я думаю, что могу указать допустимую длину строки с помощью валидатора Hibernate или нет)?

Итак, когда форма входа отправлена, она генерирует и HttpRequest для ресурса / login, который обрабатывается этим методом, объявленным в классе контроллера:

@RequestMapping(value="/login" , method=RequestMethod.POST)
public String do_login(HttpServletRequest req , Model md , HttpSession session , @Valid User user, BindingResult br)
{
    try
    {
        //System.out.println(br.getAllErrors().size());

        String username = req.getParameter("username");
        String password = req.getParameter("password");

        System.out.println("Username and pasword are : "+username +"  "+ password);
        if(br.getAllErrors().size() > 0){
            System.out.println("Server side validation takes place....");
        }
        else{
        Login_Model lm = new Login_Model();
        String message = lm.do_login_process(username, password);

        if(message.equals("login success"))
        {
            session.setAttribute("username", username);
            return "redirect:/myprofile";
        }
        else
        {
            md.addAttribute("error_msg", message);
        }
        }
        return "login";
    }
    catch(Exception e)
    {
        return "login";
    }
}

Хорошо, и теперь у меня есть следующие сомнения по поводу этого метода:

1) Принимает этот объект в качестве входного параметра: @Valid User user. Кто на это перейдет? Я думаю, это может зависеть от того, что в форме я указал commandName = "user", поэтому Spring автоматически сделает это. Это правильно?

2) Насколько я понимаю, аннотация @Valid автоматически вызывает процесс проверки. Как это случилось? связано ли что-то с функцией AOP, предоставляемой Spring? или что? Почему эта аннотация @Valid связана только с библиотекой javax.validation, а не также с валидатором Hibernate (так что эта аннотация @Valid также проверяет поле аннотировано аннотацией валидатора Hibernate? почему?)

3) Насколько я понимаю, если пользователь вводит неправильные значения в форму входа, я могу получить эту ошибку с помощью входного параметра BindingResult br. Используя отладчик, я вижу, что этот объект содержит сообщение об ошибке, определенное аннотацией, определенной в объекте модели Пользователь. Как именно работает?

Tnx


person AndreaNobili    schedule 10.10.2015    source источник
comment
Некоторые другие реализации: stackoverflow.com/questions/1384968/ и сама спецификация: beanvalidation. org / 1.0 / spec   -  person zapl    schedule 10.10.2015
comment
stackoverflow.com/q/38716703/4723795, похоже, на него хорошо дан ответ   -  person xenteros    schedule 11.08.2016


Ответы (3)


И тут первое сомнение: в чем именно разница между двумя используемыми библиотеками javax.validation и org.hibernate.validator?

javax.validation исходит из JSR-303 API. Вы можете посмотреть классы API, например, в этой зависимости Maven .

валидатор Hibernate является одной из реализаций JSR 303 (на самом деле эталонная реализация), поэтому он реализует весь API, но добавляет свои собственные расширения, например указанную вами аннотацию @NotBlank. Другой реализацией JSR 303 является, например, Apache BVal.


Он принимает этот объект как входной параметр: @Valid User user. Кто передает его методу-обработчику?

Значения методов обработчика в Spring MVC предоставляются реализациями интерфейса _ 6_. В вашем случае реализация, которая будет вызываться для разрешения параметра User, вероятно, будет _ 8_. Вы можете просмотреть исходный код и JavaDocs этих классов, чтобы увидеть, как они работают внутри.


Аннотация @Valid автоматически вызовет процесс проверки. Как это случилось? Использует ли он АОП? Почему эта аннотация @Valid относится только к библиотеке javax.validation, а не также к валидатору Hibernate (так что эта аннотация @Valid также проверяет поле, аннотированное аннотацией валидатора Hibernate?)

Процесс проверки запускается ModelAttributeMethodProcessor, от которого наследуется ранее упомянутый класс ServletModelAttributeMethodProcessor. Он содержит следующий метод:

protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) {
    Annotation[] annotations = parameter.getParameterAnnotations();
    for (Annotation ann : annotations) {
        if (ann.annotationType().getSimpleName().startsWith("Valid")) {
            Object hints = AnnotationUtils.getValue(ann);
            binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints});
            break;
        }
    }
}

Если вы присмотритесь, вы увидите условие для следующего выражения:

ann.annotationType().getSimpleName().startsWith("Valid")

Это означает, что Spring вызовет проверку, если параметр имеет любую аннотацию, которая начинается с Valid. Это может быть @Valid JSR 303 или _ 19_, который поддерживает группы проверки. Это может быть даже ваша пользовательская аннотация, если ее имя начинается с Valid.


Насколько я понимаю, если пользователь вставляет неправильные значения в форму входа, я могу получить эту ошибку из параметра обработчика BindingResult. Используя отладчик, я вижу, что этот объект содержит сообщение об ошибке, определенное аннотацией, определенной в объекте модели User. Как именно работает?

Вернемся к классу ModelAttributeMethodProcessor. В его resolveArgument методе есть следующий код:

WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);

Это создает экземпляр WebDataBinder, для которого выполняется проверка в ранее упомянутом методе validateIfApplicable. Сама проверка заполняет BindingResult, который затем передается методу обработчика контроллера через класс ErrorsMethodArgumentResolver, который снова реализует HandlerMethodArgumentResolver.


TL; DR: многое из того, о чем вы спрашиваете в этом вопросе, можно отнести к различным реализациям HandlerMethodArgumentResolver. Я предлагаю пройти через эти классы и пройти их через отладчик, чтобы лучше понять их.

person Bohuslav Burghardt    schedule 10.10.2015
comment
Tnx так много. Прекрасное объяснение. Только еще вопрос. Где я могу найти такое глубокое объяснение фреймворка? Есть ли какие-нибудь действующие книги в дополнение к официальной онлайн-документации? - person AndreaNobili; 11.10.2015
comment
@AndreaNobili Боюсь, что официальная документация не содержит подробного объяснения этих низкоуровневых концепций. Я изучаю это, просматривая код фреймворка (статически или пошагово с помощью отладчика) и читая JavaDocs компонентов. - person Bohuslav Burghardt; 11.10.2015
comment
Так что я думаю, что последую вашему совету ... в свободное время ... потому что на работе я всегда слишком занят, чтобы сделать что-то вроде этого :-( - person AndreaNobili; 11.10.2015

в чем именно разница от двух используемых библиотек javax.validation и org.hibernate.validator?

Bean Validation - это спецификация Java, которая позволяет выражать ограничения для объектных моделей с помощью аннотаций, позволяет вам писать собственные ограничения с возможностью расширения. Это просто спецификация без какой-либо реализации. Hibernate Validator - это реализация этой спецификации. Hibernate Validator полностью реализует Bean Validation, а также имеет некоторые особенности, уникальные для гибернации. Проще говоря, javax.validation - это спецификация, а org.hibernate.validator - уникальные особенности гибернации.

Могу ли я сделать то же самое, используя только библиотеку валидатора гибернации? (Я думаю, что могу указать допустимую длину строки с помощью валидатора Hibernate или нет)?

Да, вы можете, но лучше придерживаться пространства имен javax.validation и использовать только уникальные функции конкретного пространства имен поставщика, например org.hibernate.validator. Преимущество этого подхода заключается в том, что вы можете переключить реализацию Bean Validation из Hibernate Validator на что-то еще с минимальными изменениями.

Почему в учебнике используются оба варианта?

Поскольку ограничение @NotBlank не доступно в спецификации Bean Validation и предоставляется только Hibernate Validator.

В качестве входного параметра он принимает этот объект: @Valid User user. Кто на это перейдет? Я думаю, это может зависеть от того факта, что в форме я указал commandName = "user", поэтому Spring автоматически сделает это. Это правильно?

Вероятно, у вас есть GET контроллер для login url, который возвращает пустой объект User, который, в свою очередь, связывается с тегами Spring, такими как <form:input type="text" path="username" name="username" />. Когда пользователь заполняет форму и отправляет ее, Spring собирает эти значения тегов, создает экземпляр User и передает его контроллеру.

Почему эта аннотация @Valid связана только с библиотекой javax.validation, а не также с валидатором Hibernate (так что эта аннотация @Valid также проверяет поле, аннотированное аннотацией валидатора Hibernate? Почему?)

Уже объяснено, история Spec / Impl!

person Ali Dehghani    schedule 10.10.2015

  1. Правильная, так называемая привязка свойств
  2. Spring 3+ поддерживает проверку JSR303Bean через @Validannotation, если в пути к классам есть среда валидатора JSR 303. Hibernate Validator - одна из эталонных реализаций JSR 303.

  3. Любые нарушения ограничений будут отображаться как ошибки в объекте BindingResult, поэтому вы можете проверить наличие нарушений в методе контроллера, например, в том, что у вас есть.

    if (br.getAllErrors (). size ()> 0) {System.out.println ("Выполняется проверка на стороне сервера ...."); }

Резюме: Spring MVC будет проверять объект модели, аннотированный аннотацией @Valid после binding its properties, с входными данными из формы JSP, которая использует теги формы Spring. Любые нарушения ограничений будут отображаться как ошибки в объекте BindingResult вот хороший пост

person iamiddy    schedule 10.10.2015