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

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.

Related

right way to retrieve query parameters in Spring Boot rest?

I am developing REST api using Spring Boot. I've a controller which accepts POST requests.
http://localhost:8085/carride/end-ride
In the above request i want to access the parameter ride_transection_id for finding particular transection object and also some other value as well.
So basically i have 3 way to do that.
1. i can use #PathVariable
#RequestMapping(value = "/end-ride", method = RequestMethod.POST)
public ResponseEntity<?> endRide(#PathVariable("ride_transection_id") long ride_transection_id,#RequestBody
SomeDTORequest someDTORequest ) {
//find transaction using path varibale
}
2.i can use #RequestParam
#RequestMapping(value = "/end-ride", method = RequestMethod.POST
public #ResponseBody item getitem(#RequestParam("ride_transection_id")
long ride_transection_id,#RequestBody SomeDTORequest someDTORequest ){
//find transaction using RequestParam varibale
}
i can use DTO Object SomeDTORequest and accept ride_transection_id into that with other value as well.
#RequestMapping(value = "/end-ride", method = RequestMethod.POST)
public ResponseEntity<?> endRide(#RequestBody SomeDTORequest someDTORequest ) {
//find transaction using path someDTORequest .getID()
}
i am little bit confuses.just want ask which is safest and right way to access the ride_transection_id ?
thanks
You can use any of them but every way is designed for a certain use.
Path variable:
is used when you need to access an entity using a certain field for example i want to access an order and this order is defined by id so to access this order i need the following request Get /order/{id}
Request Parameter:
when you want to send a specific variable or flag for a certain method
for example Get /orders?is_shipped=true, so this will get all shipped orders or you may need orders at certain page Get /orders?page=1
Request body:
when you need to update the entity by the put or patch request as you will update the entity using the entity's json representation which can be send through the request body
for example PUT /orders/{id}
body: {"title": "order_1"}
then the order with id {id} will be updated with the new title
Spring data rest
See also
Basically, all these 3 methods are fine. But if you want to develop or design RESTful services with best practices, I strongly recommend you should provide the querying service with #PathVariable and GET method such as GET /tickets/12. Otherwise, to digest request body with #RequestBody annotation to retrieve querying criteria for POST method is the second suggestion.
Because POST method is usually to be used for creating something. And for querying something, both #PathVariable and #RequestParam annotations are suitable for GET method. More specifically, #RequestParam is often to be used in Filtering, Sorting and Searching results. For example:
Filtering: GET /tickets?state=open - Here, state is a query parameter that implements a filter.
Sorting: GET /tickets?sort=-priority,created_at - Retrieves a list of tickets in descending order of priority. Within a specific priority, older tickets are ordered first.
Searching: GET /tickets?state=closed&sort=-updated_at - Retrieve recently closed tickets.
Please also refer to this article Best Practices for Designing a Pragmatic RESTful API.
Hope this helps you! :)

Spring MVC :URI not working

I am using the below URL to send a request,but i am getting a 404 error.
with a warning on server:No mapping found for HTTP request with URI
The URI is
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?manufacturer="Google"
The method in controller used is
#RequestMapping(value="/products/{category}/{ByCriteria}",method=RequestMethod.GET)
public String getSpecificProductByFilter(#PathVariable("category")String ProductCategory,#MatrixVariable(pathVar= "ByCriteria") Map<String,List<Long>> filterParams,#RequestParam String manufacturer,Model model){
model.addAttribute("products",productService.getfilterproducts(ProductCategory,filterParams, manufacturer));
return "products";
}
The category signifies "tablet"in the URI
Criteria signifies"low" and "high"
manufacturer is"google"
For those who dont know, this is from book "Spring MVC begginers guide" by Amuthan G. This question is really old but I will give there my solution just in case somebody going to need that, just like me today.
First of all your #RequestMapping is wrong. It should looks like this:
#RequestMapping(value="/{category}/{ByCriteria}", method=RequestMethod.GET)
And reason for that is you already have #RequestMapping("/products") on this whole controller class (above your class declaration). And because you want to map
webstore/products/tablet and NOT webstore/products/products/tablet you have to leave that "products" mapping from this method.
Second thing is your URI. I know that in the books there is this one and its not really big deal, but if you dont want to have problems, leave quotation marks next to word Google. Its because you dont want to have value "Google" but just Google without these quation marks and if you let them there, you will have problems with comparing values. So your URI should looks like this.
http://localhost:8080/webstore/products/tablet/price;low=200;high=400?manufacturer=Google
For complete solution you have to do following steps:
In your repository and service interfaces and classes write method:
List<Product> getProductsByManufacturer(String manufacturer);
and implement it in same way like you wrote method GetProductsByCategory.
In your repository and service interfaces and classes write method:
Set<Product> getProductsByPrice(Map<String, List<String>> priceParams);
and implement it in same way like you wrote method getProductsByFilter.
Finnaly write method in Controller class:
#RequestMapping("/{category}/{ByPrice}")
public String filterProducts(#PathVariable("category") String productCategory,
#MatrixVariable(pathVar = "ByPrice") Map<String, List<String>> filterParams,
#RequestParam String manufacturer, Model model) {
List<Product> byCategory = productService.getProductsByCategory(productCategory);
List<Product> byManufacturer = productService.getProductsByManufacturer(manufacturer);
Set<Product> byPrice = productService.getProductsByPrice(filterParams);
byCategory.retainAll(byManufacturer);
byCategory.retainAll(byPrice);
model.addAttribute("products", byCategory);
return "products";
}
In my project this method look like this, but you can certainly do it in shorter way. After you complete these steps, your project should working. If not, feel free to ask me there. If you dont know how to write methods in steps 1 and 2 I will comment there code for you, but its almost same like that another methods as I said. I hope that this is going to help somebody.

Am I using #ModelAttribute wrong in my Controller?

For years I have been using #ModelAttribute to create and initialize my command object like so:
#RequestMapping()
public String someHandler(#ModelAttribute("formBean") FormBean formBean) {
// Do something
}
#ModelAttribute("formBean")
public FormBean createFormBean() {
FormBean formBean = new FormBean();
// Do some sort of initialization
return formBean;
}
In this example, I have a handler in a Controller that needs a FormBean, and a "create" method that gives it one if one isn't already in the Model (or session, if using #SessionAttributes). So, when my someHandler() method is ran, the FormBean is already there and populated because my createFormBean() had already ran.
However, my colleague is claiming that, although this works just fine, that I am misusing the #ModelAttribute for a purpose it wasn't intended for, namely in the creation of the Command object. In his interpretation from the JavaDoc, you should only use #ModelAttribute to create static data, like items used to populate a dropdown list or such.
I know this works for creating and initializing my Command object quite well, but am I using this for a purpose it was not originally intended for? Am I breaking some cardinal rule here?
#ModelAttribute("formBean")
public FormBean createFormBean() {
FormBean formBean = new FormBean();
// Do some sort of initialization
return formBean;
}
This can be useful if you need to initialize model attribute before binding form values from view. For example, you can query object from database (to get available it in current session).
In other cases I prefer to use this method:
#RequestMapping
public String someHandler(final Model model) {
FormBean formBean = new FormBean();
// Do some sort of initialization
model.addAttribute("formBean", formBean);
}
I think it more clear to understand. But I don't think that you "breaking some cardinal rule here".

spring 3 not rendering model in jsp

I am a bit disapointed concerning Spring 3 not rendering my model in a jsp using Expression Language and I have to admit that I dont understand why. If anyone could help me understanting why I can't make it work it will be really great.
Here's my context:
My controller have a method (called by ajax from my client) returning a jsp fragment:
#RequestMapping(value = "/datagrid/getGoatCard", method = RequestMethod.POST)
public String getGoatCard(#RequestParam Long id,
#ModelAttribute("goat") Goat goat) {
goat = goatDataService.findGoatById(id);
return "goatCard";
}
I call this method with a requestParam allowing hibernate to retrieve the desired Bean (the model contains all the requiered data, it has been checked).
Then this method retruns a jsp named "goatCard"; here's the jsp code:
<input name="goat.goatName" type="hidden" value="${goat.goatName}"/>
(this isn't the whole page code, cause this won't be easy to read if too many code is presented. My jsp contains JQuery easyui and highcharts javaScript librairies)
I though that the annotation #ModelAttribute("goat") linked the model called "goat" to my jsp allowing to render the model using EL but it doesn't seem so.
Does anybody have any idea, perhaps it just a little thing that I did wrong but I don't see which one!!!!
#ModelAttribute is used for retrieving form model rather than setting to be displayed in JSP.
If you need to display data in JSP, you have to add the data into Model first.
#RequestMapping(value = "/datagrid/getGoatCard", method = RequestMethod.POST)
public ModelAndView getGoatCard(#RequestParam Long id) {
ModelAndView mv = new ModelAndView("goatCard");
Goat goat = goatDataService.findGoatById(id);
mv.addObject("goat",goat);
return mv;
}
And then goat is available in JSP file.
By the way, for retrieving data, better to use RequestMethod.GET.
Thank's a lot for your help. Just an answer to update your code.
As I use Spring 3, it is better to write
#RequestMapping(value = "/datagrid/getGoatCard", method = RequestMethod.POST)
public String getGoatCard(#RequestParam Long id,
Model model) {
model.addAttribute("goat", goatDataService.findGoatById(id));
return "goatCard";
}
It's just to fit more to the preconisation of Spring Foundation (I agree this lead to the same result, but SpringSource recommend the use of String return instead of mav).
Again thanks for your help

Can #RequestParam be used on non GET requests?

Spring documentation says:
Use the #RequestParam annotation to bind request parameters to a
method parameter in your controller.
AFAIK, request parameters are variables retrieved from query strings if the request method is GET. They are also the variables retrieved from the form values when the request method is POST. I've verified this using a simple JSP that displays request parameters through method request.getParameter("key").
But it seems to me that #RequestParam only works on GET method requests. It can only get values from query strings.
Is this a bug in the documentation? Can someone please cite me some documentation that describes exactly what #RequestParam is used for, what it cannot be used for, and how it gets populated?
Can I use #RequestParam for POST methods to get the form values? If I can't use #RequestParam, what else can I use? I'm trying to avoid calling request.getParameter("key").
It works with posts too. Can you post your method body and you html?
Yes it works perfectly with post method too. you can mention the method attribute of #RequestParam as RequestMethod=POST. Here is the code snippet
#RequestMapping(value="/register",method = RequestMethod.POST)
public void doRegister
(
#RequestParam("fname") String firstName,
#RequestParam("lname")String lastName,
#RequestParam("email")String email,
#RequestParam("password")String password
)
Instead of #RequestParam which binds to a single form value, you can use #ModelAttribute annotation and bind to the whole object. But it should be used in conjunction with form or bind Spring's JSTL.
Example:
- controller that calls JSP-page, it should add objects to a Model:
#RequestMapping(value="/uploadForm", method=RequestMethod.GET)
public String showUploadForm(Model model) {
Artist artist = new Artist();
Track track = new Track();
model.addAttribute("artist", artist);
model.addAttribute("track", track);
return "uploadForm";
}
JSP might look something like that:
Track Title *:
Controller that processes form submission;
#RequestMapping(value="/uploadToServer", method=RequestMethod.POST)
public String uploadToServer(#ModelAttribute("artist") Artist artist, #ModelAttribute("track") Track track) { .... }
Here I found a good explanation of using #ModelAttribute annotation - krams915.blogspot.ca

Resources