Modify and return ModelAttribute object if validation fails

早过忘川 提交于 2020-07-22 21:35:12

问题


I have simple entity ...

@Entity
public class WatchedDirectory {
    @Column(nullable=false)
    @NotBlank(message="Filesystem path CANNOT be empty")
    String filesystemPath;
}

... and GET endpoint for creating one ...

    @GetMapping("/add")
    public String add(@ModelAttribute WatchedDirectory watchedDirectory) {
        return "mng-dir-add";
    }

... that shows form made in Thymeleaf, with error validation and all. Once you hit sumbmit button data goes into POST endpoint ...

    @PostMapping("/add")
    public String addExecute(@Valid @ModelAttribute WatchedDirectory watchedDirectory, BindingResult result, RedirectAttributes redirect, Model model) {
        if(result.hasErrors()) {
            // here I want to iterate through
            // errors and clean erroneous fields
            return "mng-dir-add";
        }
        watchedDirectory = fs.persistDirectory(watchedDirectory);
        redirect.addFlashAttribute("added", watchedDirectory);
        return "redirect:/list";
    }

... and everything is nice and dandy. When data is valid it get persisted and redirect to list is issued (POST/Redirect/GET). When data is invalid thymeleaf's error fields are populated and I list error messages below appropriate fields.

The only thing I want to change, but I can't figure out how to, is to clear some data from model.

Things I tried so far: modifying @ModelAttribute parameter, setting attributes in Model, setting attributes in RedirectAttributes. Every time I get the very same data user provided without any changes in output form, for some reason I can't change a thing. I tried also redirecting to GET method but it seems it clears slate clean, which I don't want.

If someone is interested this is how form in thymeleaf looks:

        <form id="content" action="#" th:action="@{/add}" th:object="${watchedDirectory}" method="post" class="was-validated">
            <div class="form-group has-feedback has-error">
                <label for="filesystemPath">Filesystem path:</label>
                <input th:field="*{filesystemPath}" type="text" id="filesystemPath" name="filesystemPath" class="form-control" placeholder="~/" required />
                <label th:if="${#fields.hasErrors('filesystemPath')}" th:errors="*{filesystemPath}"></label>
            </div>          
            <button type="submit" class="btn btn-outline-success">Save</button>
        </form>

required attribute on input field will shut up when provided with whitespace but there will be error message from Spring's validation. Clearing this field and returning it to user will make things more consistent than showing mixed signals such as:

Any help would be really appreciated.


回答1:


You need to define a BeanPropertyBindingResult object that provides the fields having the errors. Then make a model with this results,

@PostMapping( "/add" )
public String addExecute( @Valid @ModelAttribute WatchedDirectory watchedDirectory, BindingResult result, RedirectAttributes redirect, Model model )
{
    if( result.hasErrors() )
    {
        BeanPropertyBindingResult result2 = new BeanPropertyBindingResult( watchedDirectory, theBindingResult.getObjectName() );
        for( ObjectError error : theBindingResult.getGlobalErrors() )
        {
            result2.addError( error );
        }
        for( FieldError error : theBindingResult.getFieldErrors() )
        {
            result2.addError( new FieldError( error.getObjectName(), error.getField(), null, error.isBindingFailure(), error.getCodes(), error.getArguments(), error.getDefaultMessage() ) );
        }

        model.addAllAttributes( result2.getModel() );
        return "mng-dir-add";
    }
    watchedDirectory = fs.persistDirectory( watchedDirectory );
    redirect.addFlashAttribute( "added", watchedDirectory );
    return "redirect:/list";
}



回答2:


According to Validation by Using Spring’s Validator Interface from the Spring Framework Documentation:

The Validator interface works by using an Errors object so that, while validating, validators can report validation failures to the Errors object.

validate(Object, org.springframework.validation.Errors): Validates the given object and, in case of validation errors, registers those with the given Errors object.

And the Errors interface doesn't provide any API for deregistering binding errors.

So, it seems there is no Spring provided way to achieve what you want.



来源:https://stackoverflow.com/questions/61568366/modify-and-return-modelattribute-object-if-validation-fails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!