In Spring controller, I want to invoke same method for different HTML - Forms submission
So, taking HttpServletRequest as a RequestBody
#RequestMapping(value = "/Search")
public String doSearch(HttpServletRequest httpServletRequest, ModelMap map) {
// Now, looking for something like this...
if(req.getType.equals("x")
//X x = SOME_SPRING_UTIL.convert(httpServletRequest,X.class)
else
// Y y = SOME_SPRING_UTIL.convert(httpServletRequest,Y.class)
}
I want to convert request parameters to bean through Spring, As it converts while I take Bean as method argument
Use the params attribute of the #RequestMapping annotation to differentiate the request mapping mapping.
#RequestMapping(value="/search", params={"actionId=Actionx"})
public String searchMethod1(X search) {}
#RequestMapping(value="/search", params={"actionId=ActionY"})
public String searchMethod2(Y search) {}
This way you can create methods for each different action and let spring do all the heavy lifting for you.
Related
Hi everyone I'm trying to get or pass the values from my JSP to my controller because I want to write a method whose main function will be to save a new user in the database but I got an error like this:
(((java.lang.IllegalStateException: Mode mappings conflict between method and type level: [/myPath] versus [VIEW])))
I guess this two annotations, first in the class declaration #RequestMapping("VIEW") and the second in the method declaration for save the new user
#RequestMapping(value="/saveUser", method = RequestMethod.POST)
are in conflict by the use of the same annotation in tow times at the same controller but I have to say that I´ve been tried to remove the #RequestMapping annotation in the class declaration and after that, I get a different error like this:
(((java.lang.IllegalStateException: No portlet mode mappings specified - neither at type nor at method level)))
I don't know if I can use as many necessary controllers for differents operations as I will need, if I can, I will be happy to know the correct way to implement with this technique
Here is my controller:
#Controller
#RequestMapping("VIEW")
public class UsersController {
User currentUser = null;
#RenderMapping
public ModelAndView view(RenderRequest request, RenderResponse response)throws Exception {
ModelAndView modelView = new ModelAndView();
UserDTO usuarioAdd = new UserDTO();
//blah, blah, blah...
return modelView;
}
#RequestMapping(value="/saveUser", method=RequestMethod.POST)
public void saveUser(HttpServletRequest request) {
logger.info("***SAVE USER***);
System.out.println("***SAVE USER***);
}
}
Given a controller like:
#RequestMapping(value = "/", method = GET)
#ApiOperation(value = "Find items")
public List<Item> find(Query query) {
...
}
class Query {
String text;
int limit;
}
Spring MVC lets me do requests like /items/?text=foo&limit=10. Unfortunately, Swagger (or SpringFox?) thinks this endpoint takes a single "query" (JSON object) parameter. What am I doing wrong?
Looks like the key is to both have getters/setters (setters alone are not sufficient) and use #ModelAttribute (which otherwise isn't necessary in Spring MVC).
Question about Spring MVC #ModelAttribute methods, Setting model attributes in a controller #RequestMapping method verses setting attribute individually with #ModelAttribute methods, which one is considered better and is more used?
From design point of view which approach is considered better from the following:
Approach 1
#ModelAttribute("message")
public String addMessage(#PathVariable("userName") String userName, ModelMap model) {
LOGGER.info("addMessage - " + userName);
return "Spring 3 MVC Hello World - " + userName;
}
#RequestMapping(value="/welcome/{userName}", method = RequestMethod.GET)
public String printWelcome(#PathVariable("userName") String userName, ModelMap model) {
LOGGER.info("printWelcome - " + userName);
return "hello";
}
Approach 2
#RequestMapping(value="/welcome/{userName}", method = RequestMethod.GET)
public String printWelcome(#PathVariable("userName") String userName, ModelMap model) {
LOGGER.info("printWelcome - " + userName);
model.addAttribute("message", "Spring 3 MVC Hello World - " + userName);
return "hello";
}
The #ModelAttribute annotation serves two purposes depending on how it is used:
At Method level
Use #ModelAttribute at the method level to provide reference data for the model. #ModelAttribute annotated methods are executed before the chosen #RequestMapping annotated handler method. They effectively pre-populate the implicit model with specific attributes, often loaded from a database. Such an attribute can then already be accessed through #ModelAttribute annotated handler method parameters in the chosen handler method, potentially with binding and validation applied to it.
In other words; a method annotated with #ModelAttribute will populate the specified “key” in the model. This happens BEFORE the #RequestMapping
At Method Parameter level
At Method Parameter level
When you place #ModelAttribute on a method parameter, #ModelAttribute maps a model attribute to the specific, annotated method parameter. This is how the controller gets a reference to the object holding the data entered in the form.
Examples
Method Level
#Controller
public class MyController {
#ModelAttribute("productsList")
public Collection<Product> populateProducts() {
return this.productsService.getProducts();
}
}
So, in the above example, “productsList” in the Model is populated before the the #RequestMapping is performed.
Method parameter level
#Controller
public class MyController {
#RequestMapping(method = RequestMethod.POST)
public String processSubmit(#ModelAttribute("product") Product myProduct, BindingResult result, SessionStatus status) {
new ProductValidator().validate(myProduct, result);
if (result.hasErrors()) {
return "productForm";
}
else {
this.productsService.saveProduct(myProduct);
status.setComplete();
return "productSaved";
}
}
}
Look here for detailed information with examples.
One is not better then the other. They both serve another purpose.
Method: If you need the model for a particular controller to be always populated with certain attributes the method level #ModelAttribute makes more sense.
Parameter: Use it on a parameter when you want to bind data from the request and add it to the model implicitly.
To answer your question on the better approach
I would say approach 2 is better since the data is specific to that handler.
I have a Spring MVC controller. And I have in the method 50 parameters. All of the parameters have very specific name, for example: FOO[].
I don't want write 50 parameters in the method signature like this:
#RequestMapping(value = "/test", method = RequestMethod.POST)
#ResponseBody
public String test(
#RequestParam(value = "FOO[]") String foo,
#RequestParam(value = "BAR[]") String bar,
// Other 48 parameters
)
{
return "test";
}
I want to map all the parameters on the one object, I mean, I want to write a simple bean class with getter/setter and use it like method parameter.
But how can I set custom names to my class fields?
e.g.:
class FooBar {
#SomeAnnotation_for_binding_the_field_to_my_field_FOO[]
private String foo;
private String bar;
// Other 48 fields
// getters/setters
}
I know annotations are kinda cool, but think rationally. You HAVE to enumerate, in code, all the mappings. There is nothing implicit about mapping FOO[] to foo, it seems to be beyond your control. Just take the parameters as a map (you can always ask Spring to give you map of all parameters) and do something like:
#RequestMapping
public String test(#RequestParam Map<String, Object> map) {
MyObject mo = new MyObject();
mo.setFoo(map.get("FOO[]").toString());
mo.setBar(map.get("WOBBLE13[][]").toString);
return "whatever";
}
If you want to make this process more automatic, and if there exists an alorithm that maps parameter names to property names, you can use Spring's bean wrapper:
#RequestMapping
public String test(#RequestParam Map<String, String> map) {
BeanWrapper bw = new BeanWrapperImpl(new MyObject);
for (Entry<String, Object> entry : map.entrySet()) {
bw.setProperty(entry.getKey(), entry.getValue());
}
}
private static String decodeName(String n) {
return n.toLowerCase().substring(0,n.length() - 2);
}
You could make the process even more automatic by using a different Binder, you could (really, not a problem) add some custom annotations... but really, there is no point, if you just have a single case of 50 params. If you insist, add a comment.
THis sounds like a good time to use a hashmap, with key as the var name and value as value. Wrap that in a form backing object.
You could have a resource class i.e FooBarResource.jave and in your controller use that as a request body something like the following:
#ResponseBody
#RequestMapping(value = "/test", method = RequestMethod.POST)
#Secured({"ROLE_ADMIN"})
public ResponseEntity<ModelMap> createTest(#Valid #RequestBody FooBarResource body, UriComponentsBuilder builder) {
In my application based on spring mvc and spring security I am using #Controller annotation to configure controller.
I have configured Spring Handler Interceptor and in preHandle() method , I want to get method name which is going to be call by interceptor.
I want to get custom annotation defined on controller method in preHandle() method of HandlerInterceptor so that I can manage by logging activity for that particular method.
Please have a look at my application requirement and code
#Controller
public class ConsoleUserManagementController{
#RequestMapping(value = CONSOLE_NAMESPACE + "/account/changePassword.do", method = RequestMethod.GET)
#doLog(true)
public ModelAndView showChangePasswordPage() {
String returnView = USERMANAGEMENT_NAMESPACE + "/account/ChangePassword";
ModelAndView mavChangePassword = new ModelAndView(returnView);
LogUtils.logInfo("Getting Change Password service prerequisit attributes");
mavChangePassword.getModelMap().put("passwordModel", new PasswordModel());
return mavChangePassword;
}
}
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// here I want the controller method name(i.e showChangePasswordPage()
// for /account/changePassword.do url ) to be called and that method annotation
// (i.e doLog() ) so that by viewing annotation , I can manage whether for that
// particular controller method, whether to enable logging or not.
}
I am using SPRING 3.0 in my application
Don't know about the Handler interceptor, but you could try to use Aspects and create a general interceptor for all your controller methods.
Using aspects, it would be easy to access your joinpoint method name.
You can inject the request object inside your aspect or use:
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
To retrieve it from your advice method.
For instance:
#Around("execution (* com.yourpackages.controllers.*.*(..)) && #annotation(org.springframework.web.bind.annotation.RequestMapping)")
public Object doSomething(ProceedingJoinPoint pjp){
pjp.getSignature().getDeclaringType().getName();
}