I use Spring MVC and need to provide ability to change fields of some object separately. For example in controller I have method for every field (new value is assigned in service method) but I'm wondering if there is good design pattern to use in this situation. I mean to have in controller only one method for all fields. I thought about sending new value of field and name and then check which field should be changed in controller but in this situation I get many if statements... Is there any widely used method in this situation?
class Controller {
#RequestMapping(value = "/field", method = RequestMethod.POST)
public String changeFieldValue(#RequestParam("fieldname") String fieldName, #RequestParam("newValue") String newValue, ModelMap model){
if(fieldname.equals("age")){
Object.setAge(newValue);
}
.
.
.
}
}
I think about sth similar to this, I know that I can populate whole object at once. but requirements are to change fields separately
Spring has a BeanWrapper implementation to ease this task.
http://static.springsource.org/spring/docs/3.2.x/javadoc-api/org/springframework/beans/BeanWrapperImpl.html
BeanWrapper wrapper = new BeanWrapperImpl(object);
wrapper.setPropertyValue(fieldName, newValue);
Related
I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable
I am trying to figure out how to pass two different parameters of the same class through the URL to a handler method in the controller. For example, given a "Foo" class with an "id" parameter(I am saying just one parameter to keep it simple, but think from a class with loads of them), the code of the controller looks as it follows:
#Controller(value = "customerCareRemoteService")
public class CustomerCareRemoteServiceImpl {
// Othe methods/requests
#RequestMapping(value = "/" + "prueba" , method = RequestMethod.GET)
public #ResponseBody String prueba(Foo pFoo1, Foo pFoo2) {
//stupid and not interesting code
String answer = "pFoo1.id is " + pFoo1.id + ". pFoo2.id is " + pFoo2.id.";
System.out.println(answer);
return answer;
}
}
So, when I call this method, there is no way to differ between the two parameters:
http://myfakeurl/prueba?id=1&id=2
How should I deal with that? Is there any way to "prefix" the parameters? I have seen #RequestParam but it does not work for me, because it can not be used with my very own and beauty personal classes(or am I wrong?). Also I would like to avoid wrapper classes. Thank you for your time.
You should use #PathVariable to solve this problem.
Your mapping url would be like this.
#RequestMapping(value = "/" + "prueba" + "/{id1}/{id2}" , method = RequestMethod.GET)
and the arguements in your function would be.
public #ResponseBody String prueba(#PathVariable int pFoo1, #PathVariable int pFoo2)
In this way you can get both the ID in your controller for further operation using them.
Hope this helped you.
Cheers.
So, with some help from a workmate, I have came to the next page that talks about that thema:
Customizing Parameter Names When Binding Spring MVC Command Objects
Which leads to the next StackOverFlow question:
How to customize parameter names when binding spring mvc command objects
So it looks like there is no easy solution available like "using annotation X", but to create your own resolver, and use custom annotations (as a good newbie, I am still trying to understand it :-S).
I'm writing an application with Spring framework and I have a question how to do a form validation with extra fields.
I'm new to this but as far as I understand to fill the form with form:form tag I set attribute with
#RequestMapping(value = "/register", method = RequestMethod.GET)
public String register(Model model) {
model.addAttribute("tenant", new Tenant());
return "register";
}
Then create validator class and use it on POST request:
#RequestMapping(value = "/register", method = RequestMethod.POST)
public String registerPost(#ModelAttribute("tenant") Tenant tenant,
Model model,
BindingResult result) {
TenantValidator validator = new TenantValidator();
validator.validate(tenant, result);
if (result.hasErrors()) {
return "register";
}
tenantService.save(tenant);
return "redirect:accountOverview";
}
It works very well and I'm fascinated by how convenient this is!
The only problem is what do I do with extra fields?
For example I have "repeat password" field.
If I create extra fields without using tags and by using and validate them directly I would not be able to use:
<form:errors path="repeatPassword>
tag as 'repeatPassword' is not a member of form object.
The first solution that comes to mind is to create special form object TenantDTO that would hold those extra fields and on save just transfer the data to 'Tenant' (entity bean).
Is this a good approach? What are the best practices in this situation?
Thanks!
Leonty
You can still have these values in the form object. I guess you don't want to save these to the database. You can avoid that by using the annotation Transient (http://docs.oracle.com/javaee/5/api/javax/persistence/Transient.html). This will give a leverage for you to do the path mapping, having in the form object and do all the validation but still dont save in the database. hope it helps.
I have a Spring MVC controller with an action that's called using AJAX.
#SessionAttributes({"userContext"})
public class Controller
{
...
#RequestMapping(value = "/my-url", method= { RequestMethods.POST })
public ModelAndView doSomething(#ModelAttribute("userContext") UserContext context,
SessionStatus sessionStatus)
{
BusinessObject obj = doSomeBusinessLogic(context.getUserName());
sessionStatus.setComplete();
ModelAndView mav = new ModelAndView("jsonView");
mav.addObject("someInt", obj.getId());
return mav;
}
}
When I run this action, I get the following exception:
net.sf.json.JSONException: There is a cycle in the hierarchy!
at t.sf.json.util.CycleDetectionStrategy$StrictCycleDetectionStrategy.handleRepeatedReferenceAsObject(CycleDetectionStrategy.java:97)
at net.sf.json.JSONObject._fromBean(JSONObject.java:833)
at net.sf.json.JSONObject.fromObject(JSONObject.java:168)
at org.springframework.web.servlet.view.json.writer.jsonlib.PropertyEditorRegistryValueProcessor.processObjectValue(PropertyEditorRegistryValueProcessor.java:127)
at net.sf.json.JSONObject._fromMap(JSONObject.java:1334)
Truncated. see log file for complete stacktrace
After doing some debugging I found out that Spring is placing the UserContext object onto the ModelAndView that I am returning. If I hard-code my user name and remove the context object from the method's parameters, the action runs successfully. Is there a way to configure Spring to omit the ModelAttribute-annotated parameters from the returned ModelAndView? As you can see, sessionStatus.setComplete() has no effect.
I've had similar problems in the past with #SessionAttributes. By declaring #SessionAttributes({"userContext"}) you're telling Spring that you want "userContext" to always be available in the model, and so Spring has no choice but to send your UserContext object out to the model, just in case you're going to be redirecting or doing something else which might end up at another Controller.
The "solution" (and I didn't like it much, but it worked) was to omit the #SessionAttributes annotation on the controller, add an HttpSession parameter to the necessary methods and "manually" manage what's in it.
I'm interested to see if there's a better way, because it seems #SessionAttributes has tremendous potential to tidy up controller-level code.
I registered a WebArgumentResolver to get to my session variable. This allowed me to keep this session variable out of the response while keeping my action unit testable.
Along with #ModelAttribute, pass #ModelMap as a method argument.
Based on business logic, error conditions -- if you do not need the attribute for certain scenarios, then remove it from the map.
public ModelAndView foo(#ModelAttribute("userContext") UserContext, #ModelMap map){
if(success){
return success.jsp
}
else{
map.remove("userContext");
return "error.jsp"
}
}
Not totally satisfied with having to pass the ModelMap as well, but I did not find any other easier way of doing it.
Cheers!!
I'm just taking a look at ASP.Net MVC3 and in one of the auto-generated views for Create, it uses "Html.EditorFor(model => model.User)" to provide a text box for the user to enter their username. Ideally, I would auto-populate this with #User.Identity.Name.
What is the correct way to achieve this? Does Html.EditorFor allow me to automatically populate it in the view, or should I be setting that at the controller when passing it in?
I've found that if I change the Create method in the controller from this:
public ActionResult Create()
{
return View();
}
To this:
public ActionResult Create()
{
MyObject myobject = new MyObject();
myobject.User = User.Identity.Name;
return View(myobject);
}
This seems to work. Is this the correct way to do this?
Thanks in advance for any confirmation that I'm doing this right.
Absolutely, the assignment is fine.
This is absolutely the correct way. You define a view model (MyObject) containing the User string property, then have your controller action instantiate and populate this model and finally pass the view model to the view for displaying. It is also easy to unit test because the User.Identity property on the controller is an abstraction that could be mocked.
its a good way in this case, but if you bild a big project it's better to create a global model class where you will put all your models, not in controller.