I am trying to reload the same page with different content that varies depending on which link is clicked on the page. The url pattern for the page is "/owners", which triggers the running of this method in OwnerController.java:
#RequestMapping(value = "/owners", method = RequestMethod.GET)
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
Collection<Owner> results = this.clinicService.findOwnerByLastName("");
model.put("selections", results);
model.put("sel_owner",this.clinicService.findOwnerById(ownerId));//ownerId is not defined yet
return "owners/ownersList";
}
The jsp includes a dynamically generated list of ownerId integer values, each of which can be used to send a unique ownerId back to the server. What do I need to add to my jsp in order to get ownerId to have a user-specified value when processFindForm() is run? In other words, what does the hyperlink need to look like?
You are using GET request type.If you want to send any parameter to controller then you have to use either #RequestParam or #PathParam annotations based on requirement as an arguments to controller method. In your case it will be something like...
public String processFindForm(#RequestParam("ownerID") String ownerId, BindingResult result, Map<String, Object> model) {... }
Take a look on this link as well: http://www.byteslounge.com/tutorials/spring-mvc-requestmapping-example
Related
I want to add a list of items to a Spring Model. It sometimes throws ConversionFailedException. The method in question:
private void addAuthoritiesToModel(Model model){
List<Authority> allAuthorities = Arrays.asList(
Authority.of("ROLE_ADMIN","Admin"),
Authority.of("ROLE_USER","User")
);
model.addAttribute("allAuthorities",allAuthorities);
}
The method throws on the last line. The curious thing it only does so, when called from a particular method and not others. For example, it works fine here:
#GetMapping("/users/new")
public String newUserForm(Model model){
model.addAttribute("user",User.blank());
model.addAttribute("newUser",true);
addAuthoritiesToModel(model);
return "user_details";
}
But it blows here:
#PostMapping(value = {"/users","/profile","/users/{any}"})
public String postUser(#Valid #ModelAttribute("user") User user,
BindingResult bindingResult,
#RequestParam("newPassword") Optional<String> newPassword,
#RequestParam("confirmPassword") Optional<String> confirmPassword,
RedirectAttributes redirectAttributes,
#PathVariable("any") String pathVariable
){
if(bindingResult.hasErrors()) {
if(user.getId()==null)
redirectAttributes.addAttribute("newUser",true);
addAuthoritiesToModel(redirectAttributes);
return "user_details";
}
...
}
I have tried exchanging Arrays.asList to another List implementation, but that doesn't solve the problem. And it wouldn't explain, why it doesn't work in the first case.
There is difference between Model and RedirectAttributes.
The values in RedirectAttributes are getting formatted as String.
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc/support/RedirectAttributes.html
A specialization of the Model interface that controllers can use to select attributes for a redirect scenario. Since the intent of adding redirect attributes is very explicit -- i.e. to be used for a redirect URL, attribute values may be formatted as Strings and stored that way to make them eligible to be appended to the query string or expanded as URI variables in org.springframework.web.servlet.view.RedirectView.
You should not use unless required for redirecting and in such case should be string values.
I have a view that is rendered with this method:
#RequestMapping("/employee/{id}")
public String showSpecificEmployee(#PathVariable String id, Model model){
model.addAttribute("employee", employeeService.findEmployeeById(new Long(id)));
DateCommand dateCommand = new DateCommand();
dateCommand.setEmployeeId(new Long(id));
model.addAttribute("date", dateCommand);
return "specificEmployee";
}
The view displayes some basic information about the Employee. On the same view, I do have a form to choose a month and filter the information by Date.
After the Date is chosen, I would like to have the view 'refreshed' with updated information. That means I do have a POST & GET methods bound to the same view.
#RequestMapping("/passdate")
public String updateWorkmonth(#ModelAttribute DateCommand dateCommand, Model model){
model.addAttribute("employee", employeeService.findEmployeeWithFilteredWorkdaysAndPayments(dateCommand.getEmployeeId(), dateCommand.getActualDate()));
model.addAttribute("date", dateCommand);
return "specificEmployee";
}
After the second method is invoked looks like
http://localhost:8080/passdate?employeeId=1&actualDate=2018-02, but I want it to be /employee/{id}. How do I combine those 2 methods, so they point to the same URL?
If I set #RequestMapping("/employee/{id}") on both methods, I keep getting an error.
You actually need only one GET method
#RequestMapping("/employee/{id}")
and optionally passed
#RequestParam("actualDate")
You can redirect user to that url. Just replace in method updateWorkmonth one line
return "specificEmployee";
with
return "redirect:/employee/" + dateCommand.getEmployeeId();
You can specify the type of HTTP request you want in the #RequestMapping parametters
When you don't specify it, it uses GET by default
#RequestMapping(value = "/employee/{id}",method = RequestMethod.POST)
I have a huge form with around 30 parameters and I don't think it's a good idea to do what I usually do.
The form will be serialized and pass all the parameters via ajax post to spring controller.
I usually do like this:
#RequestMapping(value = "/save-state", method = RequestMethod.POST)
public #ResponseBody
void deleteEnvironment(#RequestParam("environmentName") String environmentName, #RequestParam("imageTag") String imageTag) {
//code
}
but if I have 30 parameters I will have a huge parameter list in the function.
What is the usual and correct way to avoid this?
EDIT: What if I pass the HttpServlet request only?? The request will have all the parameters and I can simple call request.getParameters("").
There are two options I would suggest:
Take an HttpServletRequest object and fetch needed properties separately.
The problem is Spring's controllers are designed to eliminate such low-level API (Servlets API) calls. It's could be the right fit if a controller was too abstract (operates on abstract datasets), which means you wouldn't be able to define a DTO with a fixed-length number of parameters.
Construct a DTO class with the properties needed and take it as a parameter.
The advantage is you completely delegate low-level work to Spring and care only about your application logic.
You can do something like this:
#RequestMapping(value = "/save-state", method = RequestMethod.POST)
public void deleteEnvironment(#RequestBody MyData data) {
//code
}
Create a class containing all your form parameters and receive that on your method.
but if I have 30 parameters I will have a huge parameter list in the
function.
In your request, pass a JSON object that contains these information and create its counterpart in Java.
RequestMethod.POST is not design to perform deletion.
Usr rather RequestMethod.DELETE.
#RequestMapping(value = "/save-state", method = RequestMethod.DELETE)
public #ResponseBody
void deleteEnvironment(MyObject myObject) {
//code
}
Correct way is to serialize all parameters as Json and call back end api with one parameter.
On back-end side get that json and parse as objects.
Example:
` #RequestMapping(method = POST, path = "/task")
public Task postTasks(#RequestBody String json,
#RequestParam(value = "sessionId", defaultValue = "-1") Long sessionId)
throws IOException, AuthorizationException {
Task task = objectMapper.readValue(json, Task.class);
`
The get method will prepare the model and send to the "add person" jsp
It will also set the "mode" attribute to be "add" (so add and edit can share same jsp)
When the processSubmit result hasErrors ,mode attribute is gone
How to maintain mode attribute between calls?
#RequestMapping(value="/people/def/add" , method = RequestMethod.GET)
public String personAdd(#ModelAttribute("person") Person person,Model map) {
map.addAttribute("mode", "add");
//DO SOME LOGIC
return "personAdd";
}
#RequestMapping(value="/people/def/add" , method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("person") Person person,BindingResult result) {
personValidator.validate(person, result);
if (result.hasErrors()) {
//MODE ATTRIBUTE IS LOST
return "personAdd";
Request attributes live only for the life of request. So, if you want "mode" back in Post, you may have to submit it back as part of POST, may be by using hidden form control in your web form.
You have to add "#RequestParam("mode") String mode" to your "processSubmit" method to retrieve the value of mode from HTTP POST parameters
in My jsp I am using spring form tags to bind and update data.
my scenario is to show default values when user enters the page. these default values should come from database depending on some conditions.
But when user edits the data and submit, I want to save them in databse without updating the default values.
Any suggestion is greatly appreciated!
Standard approach to a form page is to have a controller with two methods, one for GET and one for POST. You'll also need an object to bind to the form.
The method that handles the GET sets up the bind object and puts it in the model, then returns the view for the form page. The bind object here can be created with default values which you can get from anywhere. Your bind object will probably have some key, like an ID. The default one can have a zero/default key.
The method that handles the POST takes the bind object as a parameter. It probably validates the values then inserts into the database. Its likely the database will generate the key/id.
Here's an example;
#Controller
public class PersonController {
#RequestMapping(value="/person.do", method=RequestMethod.GET)
public ModelAndView setup() {
ModelAndView response = new ModelAndView("person");
//Create default bind object, can get values
//from database if you like. Here they're just
//hard coded.
Person person = new Person();
person.setName("Joe Bloggs");
response.addObject("person", person);
return response;
}
#RequestMapping(value="/person.do", method=RequestMethod.POST)
public ModelAndView post(#ModelAttribute("person") Person person,
BindingResult result) {
Validator.validate(person, result);
if (result.hasErrors()) {
ModelAndView response = new ModelAndView("person");
response.addObject("person", person);
return response;
} else {
personDao.store(person);
}
return new ModelAndView("redirect:nextPage.do");
}
}
The form will be populated with any values you supply in the backing object. I don't understand the second part of your question.