scope of a controller and a validator - java

We are developing an application using Spring MVC. There is a page which displays list of user, a check box next to it, and a submit button at the bottom of the page.
A logged in user can select those check boxes and submit, currently a controller checks whether the selected user list is empty or not and acts accordingly. Should we just bring a validator only to do this check ? or else is it fine to do it in the controller itself ? Is there any doc which says what a controller, validator should do and should not do ?

Until Spring 3.0 is released - there is no built-in support for model validation. You'll have to handle validation on your own - like this:
#RequestMapping
public String post(#ModelAttribute MyModel myModel, BindingResult result){
myValidator.validate(myModel, result);
if (result.hasErrors()) return "myView";
...
}
You can do what you like, it's your code. But by convention, the controller should just be concerned with directing things - validation should really be in a separate validator.

Related

How can I return custom hibernate validation message in my controller with i18n?

I use Spring Boot and Hibernate validator and Thymeleaf.
Everything is ok when I validate a form item.
But after I add a verify code, I check if it's wrong code;
When the code is wrong I add a new FieldError and return it.
if (!captchaCode.equalsIgnoreCase(user.getVrifyCode())) {
bindingResult.addError(new FieldError("user", "vrifyCode", "{singup.vrifycode.error}"));
}
And of course I defined the singup.vrifycode.error in my ValidationMessages.properties file.
But at web page it just show singup.vrifycode.error not the correct value.
But in my model everything is ok like this:
#NotBlank(message="{signup.email.null}")
#Email(message="{signup.email.fomart}")
private String email;
How can I show correct value in my page?
If I can not, tell me how can I get the correct value(by locale) in ValidationMessages_en_US.properties, ValidationMessages_ja_JP.properties and so on.
Thanks!
First we must understand that there are two different validations API:s in the mix here; first the Spring validation with BindingResult and FieldError classes, and then the Bean Validation API (Hibernate Validator) with the annotations. The good news is that Spring translates validation errors from Bean Validation API, so these work together.
One difference is that Spring doesn't use { and } around its translation keys (in spring called codes), keep that in mind.
For i18n you must use the 7-arguments constructor of FieldError:
new FieldError("user", "vrifyCode", user.getVrifyCode(), false, new String[] {"singup.vrifycode.error"}, null, null)
Note that the translation should be in the Spring messages file, because it is Spring validation we are working with here.

Thymeleaf + Spring MVC Post/Redirect/Get

I'm doing a Post/Redirect/Get thingy, using thymeleaf and Spring MVC and it works fine. Apart from when I get to the page doing the GET and do a refresh, the ModelAttribute is reset. Here's a snippet of something similar I'm doing.
#RequestMapping("/site")
public class SiteController {
#RequestMapping(values = {"", "/"}, method = RequestMethod.GET)
public String index(#ModelAttribute("form") Form form, Model model) {
return "/site/index";
}
#RequestMapping(values = {"/postit"}, method = RequestMethod.POST)
public String indexPoster(#ModelAttribute("form") Form form, Model model, RedirectAttributes redirectAttributes) {
redirectAttributes.addFlashAttribute("form", form);
return "redirect:/site/result";
}
#RequestMapping(values = {"/result"}, method = RequestMethod.GET)
public String indexResult(#ModelAttribute("form") Form form, Model model) {
// This will print the form, but if I do a page reload, the form properties will be reset.
System.out.println(form);
return "/site/result";
}
}
My Form object is just a simple java bean with one String property called name, obviously my real form has a buttload of properties, but this is for simplicity in the question.
On my html page for /site/index I have a simple form using th:object="${form}" and th:field="*{name}" that does a post to /postit. And on my /site/result I just output the name entered in the form. (so it's sort of a Hello World at the moment :) ).
This flow works for me, but if I hit refresh after the /site/result has been loaded, the form variable in indexResult gets reset.
I've tried using
private Form form;
#ModelAttribute("form")
public Form getForm() {
if (this.form == null) {
this.form = new Form();
}
return this.form;
}
on the class level, but it feels "hacky". And if I navigate away from the page, do other stuff and then return the old data will still be there.
In this project we are refraining (as far as we can) to use the session to store data.
What you are experiencing is the exact behavior of flash attributes. They are stored in the session right before the redirect, then loaded as model attributes after the redirect and removed from the session immediately. They are only present for a single request after redirecting.
Unfortunately there doesn't seem to be a very elegent way of handling requests to a request mapping that requires certain flash/model attributes to be present. One way of doing it would be adding a flash attribute with a predefined key/value. This will be present as a model attribute after the redirect. If it's missing you can take action accordingly (e.g. redirect to the initial form).
If you want the form data to be available after multiple refreshes of the result page you have to either use the session or send them as request attributes through the URL although the latter is not really an elegant option.
A word of caution though: Your "sollution" of storing the form as a private will not work at all. Remember that spring controllers are singleton beans so now this single form model instance will be used for every concurrent request on your site effectivly making them share the submitted data.

How to handle/display errors without a ModelAttribute in Spring MVC?

In my insert/edit form I have a submit button to save changes to my model attribute, while I handle delete command by a simple link.
Now I'd like to show delete errors the same way I show global errors for form submission, but it seems I cannot use BindingResult without a ModelAttribute in my controller method.
For clarity, my code is like this:
#RequestMapping(value = "/delete")
public String deleteJob(Integer jobId, BindingResult result) {
// DELETE BY ID
return "myView";
}
But as expected I get this exception:
java.lang.IllegalStateException: An Errors/BindingResult argument is expected to be immediately after the model attribute argument in the controller method signature
Is there any way to do something similar?
you dont need the BindingResult result, what you can do is to create your errors and add them in the Errors object. and return it to your view
What you could do is add an attribute to your domain object - like "delete", bind it to a hidden field on the form and set that to true when the user clicks on the remove button and then submit it to the server to be processed as a model attribute. All validation checks and binding result will behave as expected.

Spring MVC Forms - Retrieve a list of beans or strings from multiple values?

I will prefix this with the fact that I am new to Spring.
I have a list of beans off of a backing bean which I am using to create a form with checkboxes. Is it possible, after submitting this form to have the same list of beans populated only with the beans that the user has checked?
I am running into problems with this approach and I know I could set it up to get the ID attribute for these beans as a list of Strings but I would ideally like to have it populate a list of the same type of beans (I'm just not sure if Spring forms work this way).
I think adding code might convolute my question but here is the basics of what I am working with:
When Java gets to my controller code, should myBackingBean have a list of myGenericBeans that were selected via checkbox? What am I missing?
Java
class MyBackingBean
{
List<MyGenericBean> myGenericBeans;
public function getMyGenericBeans()
{
return myGenericBeans;
}
}
HTML
<form:form action="/path/formHandler" commandName="myBackingBean" class="popup-form">
<form:checkboxes path="myGenericBeans" items="${myBackingBean.myGenericBeans}" />
</form:form>
Java (controller code)
#RequestMapping(value = "/formHandler", method = RequestMethod.POST)
public String editAccountTeam(#ModelAttribute("myBackingBean") MyBackingBean myBackingBean, BindingResult result) {
...
return "";
}
I think the best you are going to be able to do is generate a list of bean names that is used as the value of the check boxes. Then when the user submits the page, build a list of selected beans (from the check boxes) and get the beans from your application context (i.e. getBean("bean name");)

Spring Ajax controller - Accept submissions without refreshing page

I am using Starbox in my Spring page. I want to submit the user rating so I can store it in the database and not have to refresh the page for the user. How can I have a Spring controller that accepts this value and doesn't have to return a new view. I don't necessarily need to return any updated html - if the user clicks the Starbox, that is all that needs to happen.
Similarly, if I have a form with a submit button and want to save the form values on submit but not necessarily send the user to a new page, how can I have a controller do that? I haven't found a great Spring AJAX tutorial - any suggestions would be great.
If you use annotations, perhaps the more elegant way to return no view is to declare a void-returning controller method with #ResponseStatus(HttpStatus.OK) or #ResponseStatus(HttpStatus.NO_CONTENT) annotations.
If you use Controller class, you can simply return null from handleRequest.
To post a from to the controller via AJAX call you can use the appropriate features of your client-side Javascript library (if you have one), for example, post() and serialize() in jQuery.
The AJAX logic on the browser can simply ignore any data the server sends back, it shouldn't matter what it responds with.
But if you really want to make sure no response body gets sent back, then there are things you can do. If using annotated controllers, you can give Spring a hint that you don't want it to generate a response by adding the HttpServletResponse parameter to your #RequestMapping method. You don't have to use the response, but declaring it as a parameter tells Spring "I'm handling the response myself", and nothing will be sent back.
edit: OK, so you're using old Spring 2.0-style controllers. If you read the javadoc on the Controller interface, you'll see it says
#return a ModelAndView to render, or
null if handled directly
So if you don't want to render a view, then just return null from your controller, and no response body will be generated.

Categories

Resources