Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error 400 valiting form "The request sent was syntactically incorrect"

I have a problem trying to validate a form using Spring Boot and Thymeleaf. The from just register an user with the given fields. I'm using a multipart form because the form also uploads a picture, but I already tried to use the form without it, but still the same problem.

BTW, I know there are many of this question but none of the anwers helped me...

If the form fields are correct, everything works fine. But if I enter an invalid field I get as response:

HTTP Status 400 -

type Status report

message

description The request sent by the client was syntactically incorrect.

I simply want to show a bubble to warn about that field. Currently I'm using "pattern" in the html input tag, but user's can just remove it from the browser. I can invalidate the process checking in the controller and redirect to the same cleaned page, but that's just an uncomfortable workaround.

<form class="styleweb" id="registrationform" th:action="@{/site/new_user}" method="post" enctype="multipart/form-data">
        <fieldset>

            <div class="styleweb">
                <label for="login">Login</label> <input id="login" type="text"
                    placeholder="Username" th:field="${user.login}" />
                    <p th:if="${#fields.hasErrors('user.login')}" th:errors="*{user.login}">Incorrect stuff</p>
            </div>

            <div class="styleweb">
                <label for="password">Password</label>
                    <input id="password"
                    type="password" placeholder="Password" th:field="${user.password}"/>
            </div>

            <div class="pure-control-group">
                <label for="email">Email Address</label> <input id="email"
                    type="email" placeholder="Email Address" th:field="${user.email}"/>
            </div>

            <div class="pure-control-group">
                <label for="foo">Profile pic</label> <input type="file" name="profilePic" id="imgInp"/>
                <img id="profilepic" src="#" alt="avatar" />
            </div>

            <div class="styleweb">
                <button type="submit" class="styleweb">Submit</button>
            </div>
        </fieldset>
    </form>

This is the controller:

@RequestMapping(value="new_user", method = RequestMethod.GET)
    public String addUserPage(Model model) {
        model.addAttribute("user", new User());

        return "site/user/add_user";
    }

    @RequestMapping(value = "new_user", method = RequestMethod.POST)
    public String processAddUserWeb(@Valid @ModelAttribute(value = "user") User user,
            @ModelAttribute(value = "profilePic") MultipartFile profilePic,
            BindingResult result) throws LoginNotAvailableException {

        if (result.hasErrors()) {
            System.out.println("Form has errors");
            return "elovendo/user/add_user";
        } 
        else  {
            System.out.println("Form is ok");

            byte[] profilePicBytes = null;
            if (!profilePic.isEmpty()) try {
                profilePicBytes = profilePic.getBytes();
            } catch (IOException e) {
                System.out.println("Error converting to bytes image file");
            }

            userService.addUser(user, profilePicBytes);

            return "site/user/registered_successful";
        }
    }

And the User class is:

public class User implements UserDetails {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "userId")
    private Long userId;

    @NotNull(message="Login cannot be null")
    @Length(min = 2, max = 20, message="Invalid login lenght")
    @Pattern(regexp=Constant.loginPattern, message="Invalid login name")
    private String login;

    @Column(name = "password", length = 255)
    @Length(min = 8, max = 255)
    private String password;

    private String email;

    // constructor, getters and setters, ...

}

I also tried to use an implementation of Validator:

public class FormValidator implements Validator {

    private Pattern pattern;
    private Matcher matcher;

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

    @Override
    public void validate(Object target, Errors errors) {

        User user = (User) target;

        ValidationUtils.rejectIfEmptyOrWhitespace(errors, "login", "required.login");

        // input string conatains numeric values only
        if (user != null) {
            pattern = Pattern.compile(Constant.loginPattern);
            matcher = pattern.matcher(user.getLogin());
            if (!matcher.matches()) {
                errors.rejectValue("login", "login.invalid");
            }
        }
    }
}

and using it in the controller as (first there was no @Valid annotation, but with or without it does the same [same error] ):

@RequestMapping(value = "new_user", method = RequestMethod.POST)
    public String processAddUserWeb(@ModelAttribute(value = "user") User user,
            @ModelAttribute(value = "profilePic") MultipartFile profilePic,
            BindingResult result) throws LoginNotAvailableException {
    FormValidator formValidator = new FormValidator();
    formValidator.validate(user, result);

    if (result.hasErrors()) {
        System.out.println("Form has errors");
        return "elovendo/user/add_user";
    }
}

but didn't work too. If don't use the th:if="${#fields.hasErrors('user.login')}(...) tag (it's dumb but I'm just trying desperatly to found a solution) returns:

org.springframework.beans.NotReadablePropertyException: Invalid property 'login' of bean class [java.lang.String]: Bean property 'login' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter? (...).validator.FormValidator.validate(FormValidator.java:28)

Ask here it's the last stop before loose all my hair while dealing with this, hope somebody might help me. thank you!

EDIT

Here is the log when I send the form post with invalid data:

2014-08-06 14:42:01.717 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /site/new_user
2014-08-06 14:42:01.718 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sdfd.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]
2014-08-06 14:42:01.743 DEBUG 9759 --- .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]{1,20}$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.744 DEBUG 9759 --- .w.s.m.a.ResponseStatusExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]{1,20}$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.745 DEBUG 9759 --- .w.s.m.s.DefaultHandlerExceptionResolver : Resolving exception from handler [public java.lang.String es.sfacut.rest.web.UserWebController.processAddUserWeb(es.sfacut.model.user.User,java.lang.String,org.springframework.web.multipart.MultipartFile,org.springframework.validation.BindingResult,org.springframework.ui.ModelMap) throws es.sfacut.rest.controller.exception.LoginNotAvailableException,java.io.UnsupportedEncodingException]: org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
Field error in object 'user' on field 'login': rejected value [u]; codes [Pattern.user.login,Pattern.login,Pattern.java.lang.String,Pattern]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],[Ljavax.validation.constraints.Pattern$Flag;@23d2602c,^[a-zA-Z][a-zA-Z0-9-_\.]{1,20}$]; default message [Invalid login name]
Field error in object 'user' on field 'login': rejected value [u]; codes [Length.user.login,Length.login,Length.java.lang.String,Length]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [user.login,login]; arguments []; default message [login],20,2]; default message [Invalid login lenght]
2014-08-06 14:42:01.745 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Null ModelAndView returned to DispatcherServlet with name 'dispatcherServlet': assuming HandlerAdapter completed request handling
2014-08-06 14:42:01.746 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Successfully completed request
2014-08-06 14:42:01.748 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing POST request for [/error]
2014-08-06 14:42:01.749 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error
2014-08-06 14:42:01.749 DEBUG 9759 --- s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sfacut.rest.controller.MainController.errorPage()]
2014-08-06 14:42:01.751 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Rendering view [org.thymeleaf.spring4.view.ThymeleafView@503dc0cf] in DispatcherServlet with name 'dispatcherServlet'
2014-08-06 14:42:01.755 DEBUG 9759 --- o.s.web.servlet.DispatcherServlet        : Successfully completed request

And this is the log with valid data:

2014-08-06 14:54:25.703 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : DispatcherServlet with name 'dispatcherServlet' processing GET request for [/site/new_user]
2014-08-06 14:54:25.703 DEBUG 10138 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /site/new_user
2014-08-06 14:54:25.705 DEBUG 10138 --- [nio-8080-exec-3] s.w.s.m.m.a.RequestMappingHandlerMapping : Returning handler method [public java.lang.String es.sfacut.rest.web.UserWebController.addUserPage(org.springframework.ui.Model)]
2014-08-06 14:54:25.705 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Last-Modified value for [/site/new_user] is: -1
2014-08-06 14:54:25.712 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Rendering view [org.thymeleaf.spring4.view.ThymeleafView@4b34f94d] in DispatcherServlet with name 'dispatcherServlet'
2014-08-06 14:54:25.722 DEBUG 10138 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Successfully completed request
like image 636
qgadrian Avatar asked Jan 10 '23 02:01

qgadrian


1 Answers

You need to place BindingResult right after User user for Spring to able to handle the invalid data correctly.

The controller method would thus look like:

public String processAddUserWeb(@ModelAttribute(value = "user") User user,
                                BindingResult result,
                                @ModelAttribute(value = "profilePic") MultipartFile profilePic)
like image 115
geoand Avatar answered Jan 12 '23 20:01

geoand