Spring: Registration form remove object from model - spring

In my Spring MVC Project I created a registration page.In this page there is a form in which the user insert his information(name,surname and so on).I have used the Spring tag form to bind the object "cliente" to the form. In my controller I have:
#RequestMapping(value="/registration",method=RequestMethod.GET)
public String viewRegistration(ModelMap model){
model.addAttribute("cliente",clienteFactory.createCliente());
return "registrazione";
}//registrazione
In registration.jsp
<form:form method="post" action="add" modelAttribute="cliente">
....
</form:form>
In this project I have not used Spring Security,because I'm a student and I hadn't learned this part yet.
If the user leaves the page without register, I want to delete the object "Cliente" from the model.How can I solve it?Thanks

At first you don't need to delete object from model as if client leaves page with mapping /registration model ref will be overriden with model of another mapping method.
Second in more cases it's no good idea to call your method clienteFactory.createCliente()) in GET request method. Better to call it in POST after user fill all form fields and post his request than you know that you need to call clientFactory.Also use #ModelAttribute annotation as method argument.
As you have in your form form:form method="post" it will not working without such method
#RequestMapping(value="/registration",method=RequestMethod.POST)
public String makeRegistration(ModelMap model){
.....
Also see simple Sring tutorial for handling forms.

Related

Can model class in mvc only contain methods, not contain attributes?

I have an project that I have to do in mvc pattern. But I'm confused. If my model only contains method for manipulating the database and do not have any attribute, will that be the right way ?
For example, for login :
The model will have a method
static insertAccount(String username, String password) {
// the code to insert username and password to the database
}
And when the user push "submit", the form will pass the username and password to the controller, which has this method
createNewAccount(String username, String password) {
Model.insertAccount(username,password);
}
Your model should not contain methods to insert data. That should be abstracted out to the Data Access Layer of your application. The MVC pattern is for interacting with the UI.
The controller will pass data (a model) to be rendered. After some type of action, the view will pass data (a model) back to the controller.
From the controller, you can run some business logic, make calls to the data access layer, call another API. And, if nessecary, pass that model to the other layer.

passing a model to the next controller from view

I have a form with few inputs, name, email, message and some checkboxes. I've created a model for these inputs and set all the validations i require.
But now I also want to pass my model (i.e. from #model MyModel) or rather some object property of my model together with those inputs.
Is populating a VewBag/viewData with my model a way to go?
#{
ViewBag.MyModel = Model;
// or ViewBag.ThatProperty = Model.ThatProperty
}
or do i still have a better way up my sleeve?
ViewBag and ViewData persist in one trip from server to client, and not the other way around.
There is no way to pass an object from the view to the controller. If it's a database object, you can pass the object Id using one of the two methods described below, then query the DB on post.
If you have no other way, you can encode the object as a JSON string (using the Newtonsoft package, for example) and pass it also using one of the two methods described below, but this isn't the best option.
To pass a property from the View to the Controller, you have two options:
Url Parameter
Hidden field
Url Parameter
<form ... asp-route-ThatProperty="#Model.ThatProperty">
...
</form>
Form Field
<form>
<input type="hidden" name="ThatProperty" value="#Model.ThatProperty" />
</form>
Controller Action
If 'ThatProperty' doesn't exist on your model, receive it as an extra parameter.
public IActionResult MyAction (MyModel model, string ThatProperty)
{
...
}

Spring Boot Post Request Method not having all Object values

Using Spring Boot, Hibernate JPA and Thymeleaf.
I have an Order database table which currently only holds 1 record. This record has a few columns and some of the columns are not seen on any forms, they are set upon saving the Order, for instance the creation date.
On the GET request below I select the specific Order and all values are returned into the Order object as expected.
This is my GET Request method:
#RequestMapping(value = "/editorder/{orderId}", method = RequestMethod.GET)
public String editOrderGet(Model model, #PathVariable long orderId)
{
Order order = orderService.findById(orderId);
model.addAttribute("order", order);
return "/editorder";
}
This is a small snippit of my edit order html form using Thymeleaf, binding the Order object to the form using th:object as below:
<form role="form" th:action="#{/editorder}" th:object="${order}" method="post">
<input type="hidden" th:field="*{orderId}"/>
<button type="submit" class="btn btn-primary">Update Order</button>
.
.
</form>
And this is my POST Request method:
#RequestMapping(value = "/editorder", method = RequestMethod.POST)
public String editOrderPost(Model model,
#Valid #ModelAttribute("order") Order order, BindingResult bindingResult)
{
//rest of code here
}
As you can see, on the GET request I am adding the Order object to the model.
On the html form, I am binding the Order object to the entire form. Then on the POST request I am getting the Order object.
But on the POST it is seen as a new Order and only contains the fields as specified in the form, it does for instance not contain the creation date as seen in the GET request.
My question is this:
Am I missing something or do I explicitly need to go set each of those fields as hidden fields on my form?
In your GET response you may be returning the whole Order object into the Model, but Thymeleaf when trying to build the actual html from template will pick only the items it needs to build the template. So only the fields that are used in the form are used to build the form in your html page.
So when u resubmit the form to the POST service only those fields that are available in the form is reposted.
If u want these fields to be displayed on the page then add these fields in the Form. Thymeleaf picks them and displays in the form. If you dont want them to be shown in the Page then just ignore them. The Order object which u receive in the POST would not have that fields as they were not available in original form.
U can get them by querying the database, any how you do have the order id saved as the Hidden field.
public String editOrderPost(Model model,
#Valid #ModelAttribute("order") Order order, BindingResult bindingResult){
Order orderFromDB = orderService.findById(order.getId());
// Code to update the orderFromDB from order object
orderService.save(order);
}
This will save the updated fields to the database.
Generally its not a good practice to expose the Entity objects to the API. Try using a DTO/value object. This can have only fields that define your business fields. Also u can use BeanMapper frameworks like dozer/mapstruct/modelmapper to copy from DTO to Entity and vice versa.

How to correctly initialize an object that have to contain the data retrieved by 2 methods of my controller in this Spring MVC application?

I am pretty new in Spring MVC and I have the following doubt about how correctly achieve the following task.
I am working on a web application that implement a user registration process. This registration process is divided into some consecutive steps.
For example in the first step the user have to insert a identification code (it is a code that identify uniquely a user on some statal administration systems) and in the second step it have to compile a form for his personal data (name, surname, birth date, and so on).
So, actually I have the following controller class that handle these steps:
#Controller
public class RegistrazioneController {
#Autowired
private LoadPlacesService loadPlacesService;
#RequestMapping(value = "/iscrizioneStep1")
public String iscrizioneStep1(Model model) {
return "iscrizioneStep1";
}
#RequestMapping(value = "/iscrizioneStep2", method=RequestMethod.POST)
public String iscrizioneStep2(Model model, HttpServletRequest request, #RequestParam("cf") String codicFiscale) {
System.out.println("INTO iscrizioneStep2()");
//String codicFiscale = request.getParameter("cf");
System.out.println("CODICE FISCALE: " + codicFiscale);
model.addAttribute("codicFiscale", codicFiscale);
return "iscrizioneStep2";
}
#RequestMapping(value = "/iscrizioneStep3", method=RequestMethod.POST)
public String iscrizioneStep3(#ModelAttribute("SpringWeb")Step2FormCommand step2Form, ModelMap model, HttpServletRequest request) {
System.out.println("INTO iscrizioneStep3()");
System.out.println("NOME: " + step2FormCommand.getName());
return "iscrizioneStep3";
}
Into the iscrizioneStep2() it is retrieved the first code (#RequestParam("cf") String codicFiscale).
Into the iscrizioneStep3() it is retrieved a command object containing the data inserted into the form of the view in which this form was submitted, this one:
#ModelAttribute("SpringWeb")Step2FormCommand step2FormCommand
It works fine.
Now my problem is that I have another object named Step3View that have to be initialized with the aggregation of the #RequestParam("cf") String codicFiscale object retrieved into the iscrizioneStep2() method and the #ModelAttribute("SpringWeb")Step2FormCommand step2FormCommand retrieved into the iscrizioneStep3() method.
This Step3View class simply contain the String codicFiscale and all the fields of the Step2FormCommand class.
Now my doubts are: what is the best way to handle this situation? Where have I to declare this Step3View object? at controller level? (so I can use it in all my controller methods?). Have I to annotate this class with #Component (or something like this) to inject it in my controller?
What is the best solution for this situation?
I think in order to get an answer you need to understand the question and ask the right question. I think your question is "how do I pass a parameter from one page to another page in SpringMVC?". You specifically want to know how to pass the "cf" param, but readers here will tend to pass over questions that are too specific because it takes too much time to figure out what you want.
In answer to that, see Spring MVC - passing variables from one page to anther as a possible help.
Also, there are many good answers about this question for JSP in general, which can be worked into the SpringMVC architecture. See How to pass value from one jsp to another jsp page? as a possible help.

Does a variable with #ModelAttribute get populated from request parameters?

I am interested in the specifics of Spring #ModelAttribute's work on method parameters.
As we know, when a requested attribute is absent from the model, then its instance gets created and populated from the view form.
My question concerns the scenario when the form does not have expected properties but when such properties are available in URL template parameters.
I would like to know if in this case our variable will be populated with the values of those request parameters?
Like here, for instance, will the variable attributeToPopulate get populated with the parameters 1,2,3 from the URL http://localhost:8080/MyApp/parameter1=whatever?parameter2=whatever?parameter3=whatever?:
RequestMapping(method = RequestMethod.GET)
public String fooMethod(#ModelAttribute("attributeName") FooClass attributeToPopulate){
// method implementation
return "view";
}
Neither Spring documentation, reference documentation, nor Q&A sites refer to such situations explicitly. However, one post here on Stack Overflow does mention that variables annotated with ModelAtrribute get populated in this way (answer of the user Xelian):
name="Dmitrij"&countries=Lesoto&sponsor.organization="SilkRoad"&authorizedFunds=&authorizedHours=&
Considering a small number of upvotes for that answer, I am bit skeptical but at the same time curious about whether #ModelAttribute indeed functions in such way.
Any informative input will be greatly appreciated.
You can set default values to fields in the FooClass instead of setting them in RequestMapping annotation. In this case you will not have to copypaste RequestMapping with default values in all the methods where you are working with FooClass as a ModelAttribute.
#tomatefraiche I have tried to do this by
<spring:url value="/hello?name=default" var="userActionUrl" />
<form:form method="get" modelAttribute="user" action="${userActionUrl}">
<form:input path="name" type="text" disabled="true" />
</form:form>
and
#GetMapping("/hello")
public String hello(#ModelAttribute("user") User user, Model model) {
model.addAttribute("name", user.name);
model.addAttribute("user", user);
return "hello";
}
and looks like Spring override values in the url. In the controller there is an empty value. Also URL is hello?name= after form submission. So looks like you can not set default values through url since it will be replaced.

Resources