Spring MVC Controller Mapping with Properties Files - java

Is it possible to define things externally into Properties files for our annotations on Spring Controllers?
Suppose I have the following Controller
#Controller
#RequestMapping(value = "processModel.jsp")
public class ProcessorController {
#RequestMapping(method = RequestMethod.GET)
public String displayModel() {
//Code to load processor
return "processModel";
}
#RequestMapping(method = RequestMethod.POST, params="submit=Refresh")
public String refreshModel() {
//Code to refresh data
return "processModel";
}
#RequestMapping(method = RequestMethod.POST, params="submit=Save Model")
public String saveModel() {
//Code to save model
return "processModel";
}
}
Assume the following HTML is generated:
<input type="submit" name="submit" value="Save Model" />
<input type="submit" name="submit" value="Refresh" />
It'd be nice to have these params externalized so that we only have to define them once in a properties file. That way if we need to change the label on a submit button in the JSP, we only need to change it in the properties file, rather than in two places.
Is this possible?

Annotation parameter values need to be a literal or refer to a constant field, so the externalized dynamic value cannot be injected into the #RequestMapping annotation. An alternative may be to drive the behavior using some other hidden form variable mapped to a literal(SAVEMODEL/REFRESH) instead of the text that is displayed to the user(you may get a requirement to internationalize the text displayed to the user at some point and this model will break then)

You may also create a modelAndView methods in your controller and you don't have to put a #requestMapping on the head of the controller. So your controller become something like this:
#Controller
public class ProcessorController {
#RequestMapping(value="getView.html" method = RequestMethod.GET)
public ModelAndView displayModel(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
//Code to load processor
mav.setViewName = "processModel";
return mav;
}
#RequestMapping(value="refreshModel.html" method = RequestMethod.POST)
public ModelAndView refreshModel(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//Code to refresh data
mav.setViewName="refreshModel";
return mav;
}
#RequestMapping(value="saveModel.html" method = RequestMethod.POST)
public String saveModel(HttpServletRequest request, HttpServletResponse response) {
ModelAndView mav = new ModelAndView();
//Code to save model
mav.setViewName="saveModel";
return mav;
}
}
After, you just have to create the three jsp files (saveModel.jsp,refreshModel.jsp,processModel.jsp) and you have 3 views in one controller. And thats all

Related

Differentiation of #ModelAttribute, ModelAndView mode, HttpServletRequest request

I'm new to mvc spring and I have some code from the internet like the following:
#RequestMapping(value = "/newContact", method = RequestMethod.GET)
public ModelAndView newContact(ModelAndView model) {
Contact newContact = new Contact();
model.addObject("contact", newContact);
model.setViewName("ContactForm");
return model;
}
#RequestMapping(value = "/saveContact", method = RequestMethod.POST)
public ModelAndView saveContact(#ModelAttribute Contact contact) {
contactDAO.saveOrUpdate(contact);
return new ModelAndView("redirect:/");
}
#RequestMapping(value = "/deleteContact", method = RequestMethod.GET)
public ModelAndView deleteContact(HttpServletRequest request) {
int contactId = Integer.parseInt(request.getParameter("id"));
contactDAO.delete(contactId);
return new ModelAndView("redirect:/");
}
My question is,
what is the purpose of using and using in any case with # ModelAttribute, ModelAndView mode and HttpServletRequest request?
Thanks you.
Please check https://stackoverflow.com/a/33422321/3530898. I my opinion ModelAttribute is used usually with form transport objects (i.e. bean classes whose fields contain the form data), ModelAndView is used when you want to set view name and model object in a single method of a controller. Both ModelAndView and Model uses HttpServletRequest internally, Spring has added wrapper classes over HttpServletRequest to make development easier for developer. But sometime you need HttpServletRequest class for instance, when you want to capture a query parameter in an Ajax call etc

How to access the model of another RequestMapping in the same Controller?

How do I make the objects associated to a RequestMapping in a controller be accessible by another RequestMapping in the same controller that returns to the same view page? Thank you.
Here is my sample code which is placed in only one controller:
#RequestMapping(value="firstMapping",method=RequestMethod.POST)
public ModelAndView firstMapping (HttpServletRequest request) {
//myObject is processed here
ModelAndView mav = new ModelAndView();
mav.setViewName("samplepage");
mav.addObject("myObject",myObject); //How do I pass this object to the mapping below?
return mav;
}
#RequestMapping(value="secondMapping",method=RequestMethod.POST)
public ModelAndView secondMapping (HttpServletRequest request) {
//I want to do something else here but I need the object from
//the mapping above. For example myObject2 is processed here
ModelAndView mav = new ModelAndView();
mav.setViewName("samplepage");
mav.addObject("myObject",myObject);
mav.addObject("myObject2",myObject2);
return mav;
}
In the first method, instead of setting a view you should forward the request to the second method after setting the attribute.Set view in second method.By using this request is forwarded to the second method after processing.
#RequestMapping(value="firstMapping",method=RequestMethod.POST)
public ModelAndView firstMapping (HttpServletRequest request) {
Object myObject=new Object();
request.setAttribute("myObject",myObject);
return "forward:/secondMapping";
}
you can also use ModelandView to carry object from method 1 to 2.

Return a ModelAndView with a List Object Simultaneously

I have a List of Managers that I need to return in my #Controller method. I also have a User form view that I need to return simultaneously. managerList is returned from a previous #Controller. I may have been staring at this screen to long, it may not even make sense to do so, but can this be done?
#RequestMapping(value = "/getuserForm", produces = "text/html", method = RequestMethod.GET)
public ModelAndView returnUserForm(
#ModelAttribute("managerList") List<Manager> managerList,
Model model) {
//how to include managerList
return new ModelAndView("userForm");
}
Output would be a blank user form with a List of managers that say would be loaded into a select input. Any ideas?
Thanks much
You can use use public ModelAndView(String viewName, Map<String, ?> model).In model you can put your list.
You can use the model map of the ModelAndView Object
try the below code
#RequestMapping(value = "/getuserForm", produces = "text/html", method = RequestMethod.GET)
public ModelAndView returnUserForm(
#ModelAttribute("managerList") List<Manager> managerList,
Model model) {
//how to include managerList
ModelAndView mnv= new ModelAndView("userForm");
mnv.getModelMap().addAttribute("managerList", managerList);
return mnv;
}
#RequestMapping(value = "/getuserForm", produces = "text/html", method = RequestMethod.GET)
public ModelAndView returnUserForm(
#ModelAttribute("managerList") List<Manager> managerList,
Model model) {
//how to include managerList
model.addObject("managerList", managerList);
ModelAndView mnv= new ModelAndView("userForm");
mnv.getModelMap().addAttribute("managerList", managerList);
return mnv;
}

Spring REST service to consume and produce both HTML form POST and AJAX/JSON in a single method

I'm trying to teach myself Spring by creating a very simple web application. I have a class to create "Note" objects:
#Controller
#RequestMapping(value = "/notes")
public class NoteRestController {
#Autowired
private MappingJackson2JsonView jsonView;
[...]
#ResponseStatus(HttpStatus.CREATED)
#RequestMapping(method = RequestMethod.POST, consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_FORM_URLENCODED_VALUE })
public ModelAndView create(final Model model,
#Valid #ModelAttribute final Note note, final BindingResult result) {
ModelAndView mav;
// how can I test the request source?
if (<requesting from HTML FORM>) {
// return jsonView
mav = new ModelAndView(jsonView);
} else {
// return JSP view
mav = new ModelAndView("note", "model", model);
}
model.addAttribute("note", note);
if (result.hasErrors()) {
model.addAttribute("errors", result.getAllErrors());
// on error, redirect back to note page with form
// return new ModelAndView("note/note", "model", model);
return mav;
}
note.setId(daoService.createNote(note));
return mav;
}
}
I would like to be able to use a single method (like the above) to handle requests from both an AJAX post AND a HTML form post. If triggered by AJAX I would like to return JSON (with validation errors if present), and if it is triggered by a HTML form, I would like to return to the JSP using the form taglib
<%# taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
and show validation errors next to input fields using e.g.
<form:errors path="title" cssClass="errorMessage"></form:errors>
Is this possible, or should I be creating two controllers; one for the REST/JSON, and one for HTML/form? Maybe there is something I can pass into the method that can be interrogated to determibne the request source, but I can't see it right now.
What would be the "best practice" in this case?
EDIT 1:
Trying answer from #ring-bearer first as it allows for the same URL pattern, but having issues.
Using methods:
// used to handle JSON/XML
#RequestMapping(method = RequestMethod.POST, produces = {
MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public #ResponseBody Note create(
#Valid #ModelAttribute final Note note, final BindingResult result) {
[...]
}
// used to handle form view
#RequestMapping(method = RequestMethod.POST)
public ModelAndView createForView(final Model model,
#Valid #ModelAttribute final Note note, final BindingResult result) {
[...]
}
Interestingly, the HTML form submission, still gets handled by create() and not createForView(). After looking at the form submission request headers, I see that this Accept header:
text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
By adding produces = "text/html" to #RequestMapping on createForView(), all 3 scenarios work (form, AJAX/JSON, AJAX/XML).
Is this normal, or am I still missing something?
This can be achieved using "content negotiation". Spring MVC needs to be enabled for content negotiation using a "contentNegotiationManager" definition. It can be set up using Java or XML configuration. The configuration will centrally manage media type mappings(json, xml etc). Once that is set up, a controller class can be built to cater to both JSON and View(HTML). Below is a generic example(uncompiled), it should be easy to refactor your class to similar structure to avoid violation of DRY.
#Controller
class ReportController{
//1- Method for JSON/marshalling types(XML)
#RequestMapping(value="/report", produces={"application/xml", "application/json"})
#ResponseStatus(HttpStatus.OK)
public #ResponseBody List<ReportPara> generateReport(Principal principal) {
return reportService.generateReport(principal);
}
//2- For View technologies ( Eg:JSP HTML)
#RequestMapping("/report")
public String generateReportForView(Model model, Principal principal) {
model.addAttribute( generateReport(principal) );
// Return the view to use for rendering the response
return ¨reports/main¨;
}
}
Which of the two #RequestMapping methods will execute? It is determined by content negotiation definition. Eg: URLs such as report.xml or report.json map to the first method, any other URLs ending in report.anything map to the second.
The following will be easier to maintain:
#Controller
class NoteController {
#Autowired NoteService service;
#RequestMapping(method = RequestMethod.POST, value = "/note")
public ModelAndView createFromForm(#ModelAttribute #Valid Note note, BindingResult result) {
return new ModelAndView("note", create(note));
}
#RequestMapping(method = RequestMethod.POST, value = "/api/note")
#ResponseBody
public Note createFromApi(#RequestBody Note note) {
return create(note);
}
private Note create(Note note) {
return service.create(note);
}
}

.getJSON 404 Error with ModelAndView

I am trying to retrieve some JSON data in my javascript by making a call to the controller. The controller returns a MappingJacksonJsonView ModelandView, but the .getJSON is always reporting a 404 at .../handhygiene.json.
Is there a problem with the way I am returning the ModelandView from the controller?
Controller
#RequestMapping(value = "/{room}/handhygiene.json", method = RequestMethod.GET)
public ModelAndView getHandHygienePageAsync(
#PathVariable(value = "room") String roomCode) {
ModelAndView mav = new ModelAndView(new MappingJacksonJsonView());
mav.getModelMap().addAttribute(blahblahblah); //adds some attributes
...
return mav;
}
Javascript
var currentURL = window.location;
$.getJSON(currentURL + ".json",
function(data) {
... //does stuff with data
}
If you're trying to get only an JSON object from Ajax request, you need to add #ResponseBody to your method, and make you result object as return from your method.
The #ResponseBody tells to Spring that he need to serialize your object to return to the client as content-type. By default, Spring uses JSON Serialization. ModelAndView will try to return an .JSP page. Maybe you don't have this jsp page on your resources so, the server return 404 error.
I Think this code should work for you:
#RequestMapping(value = "/{room}/handhygiene.json", method = RequestMethod.GET)
public #ResponseBody Room getHandHygienePageAsync(#PathVariable(value = "room") String roomCode) {
Room room = myService.findRoomByRoomCode(roomCode);
return room;
}
I'm assuming you're using the Room as your result object, but it may be another object or ArrayList, for example.
You cant take a look here for Spring example, and here for example and configuration.

Categories