Can we pass dynamic value to #RequestMapping annotation of spring mvc? - spring

I am trying to map URL's in a dynamic way as follows,
consider that I am trying to access with different URL's
http://localhost:8080/MyApp/XYZ/Login.htm
http://localhost:8080/MyApp/PQR/Login.htm
http://localhost:8080/MyApp/ABC/Login.htm
From the above URL's I want to show different Login.htm page to the different user.
Here in above URL's there is only change in request of XYZ, PQR and ABC and rest of all is same, So this will be handled at class level #RequestMapping annotation of the controller class as per my knowledge .
If I manage to pass value dynamically to #RequestMapping annotation so I think I can achieve what I want to .
Please, can anyone suggest me how can I get dynamically value in the #RequestMapping annotation? Or any other suggestion to get Different Login page when URL changes.

You can use path variable matching
#RequestMapping(value = "/MyApp/{id}/Login.htm", method = GET)
#ResponseBody
public String getFoosBySimplePathWithPathVariable(
#PathVariable("id") String id) {
return id;
}
See documentation:
RequestMapping
PathVariable

you used if else condition, URL's in a dynamic way as follows, if condition we request mapping we give any string direct correct jsp page otherwise go to else part point out 404 error.
i want correct code....

Related

Spring Controller Url

I have question about controllers. Always when i working with controller im start to declare #RequestMapping for example if have UserController then is #RequestMapping("/user");
What if i want to declare another path in this same controller? For example im have #GetMapping("/info") and i will get info about user, but what if i want to declare on this same controller path localhost:8080/topic/blablabla? Is another solution than delete #RequestMapping from controller and make on every Get/PostMapping another path?
Defining a #RequestMapping at the controller level; it means narrowing it down to your criteria.
You can use the #RequestMapping annotation to map requests to controllers methods. It has various attributes to match by URL, HTTP method, request parameters, headers, and media types. You can use it at the class level to express shared mappings or at the method level to narrow down to a specific endpoint mapping. Read More
It is good you want to do, sometimes I need it too but as far as I research it is not supported now.

How do I test form submission with Spring MVC test?

Most of my experience with creating controllers with Spring are for REST controllers that consume JSON formatted requests. I've been searching for documentation on how to do testing for form submission, and so far this is how I understand it should go using MockMvc:
MvcResult result = mockMvc.perform(post("/submit")
.param('title', 'test title')
.param('description', 'test description'))
.andReturn()
However, I'm not sure how to map the form parameters to a model object. I've seen the #ModelAttribute annotation pop up in my searches but I can't figure out how it should be used for mapping. In addition, this quick start guide from the official documentation does not elaborate on how things like th:object and th:field translate to HTML and subsequently to URL encoded form.
I have my controller code similar to the following:
#PostMapping('/submit')
def submit(#ModelAttribute WriteUp writeUp) {
//do something with writeUp object
'result'
}
I discovered through trial and error that my specific problem might have been Groovy specific. There test code and the controller code, it turns out, have no issues. To reiterate, for testing form submission, use the param method through perform method of MockMvcRequestBuilders. Another thing to note is that this doesn't seem to work if content type is not specified. Here's a sample test code that works for me:
MvcResult result = webApp.perform(post("/submit")
.contentType(APPLICATION_FORM_URLENCODED) //from MediaType
.param('title', 'test title')
.param('description', 'test description'))
.andReturn()
As you can see, it's not much different from what I posted originally. The controller code is pretty much just the same, with #ModelAttribute working just fine.
The problem with my setup though was that since I was using Groovy, I assumed that getters and setters were automatically generated in my WriteUp class. Here's how the WriteUp class looked originally:
class WriteUp {
private String title
private String description
}
I haven't written code in Groovy for a while, and the last time I did, classes like the one above can be assumed to have getters and setters implicitly. However, it turns out that is not the case. To solve my specific issue, I updated the access modifier in the fields to be default (package level):
class WriteUp {
String title
String description
}
I've seen the #ModelAttribute annotation pop up in my searches but I
can't figure out how it should be used for mapping.
When you mark your writeUp object with #ModelAttribute, then the Spring container populates the parameters (like title, description, etc..) from HttpServletRequest object & injects the object to the controller method, when the request comes to the server from the client (could be a Browser or MockMvc unit test client or anything else).
Also, few other basic points for your quick understanding:
(1) Controller methods are mapped to an URI and RequestMethod (like POST/GET/DELETE/PUT et..) like shown below:
#RequestMapping(value="/submit", method=RequestMethod.POST)
public String submit(#ModelAttribute WriteUp writeUp) {
//Call the service and Save the details
model.addAttribute("Writeup details added successfully");
return "writeUpResult"; //Returns to the View (JSP)
}
(2) #ModelAttribute will be mapped to an object (like your writeUp) for http POST/PUT requests where the html formd data is part of http body.
(3) #RequestParam or #PathParam will be used for http GET requests where the parameters are part of URL (i.e., not part of http body).
You can look here for understanding the DispatcherServlet request handling & Spring MVC basic web flow.

Using #Value annotation with static final variable in Spring Framework

I want to make the Request Mappings in my Spring application dynamic. So that my url can not be understandable. And I can show anything meaningless to the user and still mapping purpose will be resolved.
For that I am storing the dynamic part of the URL in properties file. And want to use that in the #RequestMapping annotation. And the same thing will be done on the client side in JSP. I will read the value from the property file and then create the href.
I am using #Value annotation to read the property file values.
There is one class that holds all such values in final static variables.
public class UrlMappingAbstraction {
public static final #Value("#{urlAbstractionProperties['url.message']?:'message'}") String MESSAGE = "";
}
And I am extending this class in my controller and using the static final field in the #RequestMapping annotation like below.
#RequestMapping(value="/"+MESSAGE+"/{id}", method=RequestMethod.GET)
And in jsp also I am reading the value from property file using <spring:message/> and generating the url in href.
The problem is jsp able to create the correct url based on the property file value but in the #RequestMapping annotation my value is not getting replaced.
Can anybody tell me the exact problem? I know that we can not change the value of static final variable after its initialized. Then what's the use of #Value annotation.
If this can be done another way then you can also show me it.
Thanks in advance.
Annotations are static by their nature, therefore you cannot do it this way.
#Value cannot be used on static fields, but it doesn't matter here - the real problem is that there is no way to use values other than compile time constants as attributes of annotations.
You can use one of the following alternatives:
Add a URL rewrite filter (such as this or this) and configure it to perform the necessary conversion.
This approach looks more elegant due to clear separation of responsibilities - controllers are responsible for doing their jobs, rewrite filter is responsible for obfuscation of URLs.
Intercept creation of controller mappings by overriding RequestMappingHandlerMapping. getMappingForMethod() and change their URL patterns at this step (not tested)
I will augment #axtavt's suggestions by saying you should just do it in reverse. Do you really need to make the message URL runtime configurable?
If you don't than just make a static variable just like you have it but with out the #Value:
public final class UrlMapping {
public static final String MESSAGE = "message";
}
Then in your JSP refer to UrlMapping.MESSAGE instead of the properties file.
Although its not as flexible its far simpler and IMHO its a bad idea to make endpoint URLs too configurable because inevitably you will hardcode something either in Javascript or in a template. Also changing URLs are bad for SEO.
You can follow this approach
#Value("${name}")
private String name;
private static String NAME_STATIC;
#Value("${name}")
public void setNameStatic(String name){
PropertyController.NAME_STATIC = name;
}
src - https://www.baeldung.com/spring-inject-static-field

Java Spring #ModelAttribute method model name

I have been reading this forum for quite awhile and find it VERY useful, thank you to the contributors. I have a question that has plagded me for several weeks. And here it goes.
#RequestMapping(value="updateNote.htm",method=RequestMethod.POST)
public String updateNote(#ModelAttribute("note")NoteBean nb, BindingResult res,Model model){
daoobj.updateNote(nb.getName(),nb.getPath(), nb.getNote());
model.addAttribute("note",daoobj.getByName(nb.getName()));
return("success");
}
#RequestMapping(value="updateNote.htm",method=RequestMethod.GET)
public String updateNote(#ModelAttribute("note")NoteBean nb,Model model){
populateNoteBean();
model.addAttribute("note",daoobj.getByName(nb.getName()));
return("editNote");
}
#ModelAttribute("WHAT")
public NoteBean populateNoteBean() {
NoteBean nnb = new NoteBean();
return nnb;
}
With the method populateNoteBean() the model attribute is "WHAT". But, the name that I use is "note". So when I run the code, the NoteBean is correctly saved to the data base. My question is HOW?? It seems that the name "WHAT" should be "note" or that the model attribute is saving it as no name.
Thank for your time.
With your current code you will have two instances of your notebean in the model!
First spring invokes all modelattribute annotated methods in your controller and places the results in the model. Second it evaluates the ones from your requestmapping method.
The point of a modelattribute annotated method is that you can choose how to create your bean. Load it for example from a database.
We use this approach like that:
modelattr method (name="note")
Loads beans from db
requestmapping method with modelattr param (name="note")
Merges the note bean created by the first method with the request paramters from a submit for example and you habe directly access to the modifed one.
One nice effect:
We do not want to put hidden input fields for all attributes in a form just to be able to merge the entity with the entitymanager. This way you can have a form with only one attribute (plus one for the id to be able to fetch the entity)
Or another one:
If your note bean is an abstract class spring has no possibility to instanciate the bean because it does not know what to instanciate. You can for example add a requestparam parameter in the modelattr annotated method and decide what to do yourself.
This is very well described in the documentation. Either the reference or in the api of either controller, reqestmapping or modelattribute i believe.

How to troubleshoot spring mvc mapping issue?

I have a simple Spring program, the backend is Spring MVC with Restful web service, the front end is pure HTML + ajax.
My problem is, when I try to use the following to map a HTTP request params to a pojo, it always fails:
#RequestMapping(value = "/books", method = RequestMethod.PUT)
public #ResponseBody
String updateBook(BookInfo book)
Here I use PUT method, because it's a modification operation. There's no exception, but I get nothing injected into book object.
With same HTTP request parameters, if I change the method to POST, and client send it via a POST, it would be success:
#RequestMapping(value = "/books", method = RequestMethod.POST)
public ResponseEntity<String> addBook(BookInfo book)
This time book will always get the filled.
Why there's difference between PUT and POST? or it's the issue of return type? (one is ResponseBody, the other is ResponseEntity)? Or, if you use PUT, then the pojo must be in persistent context?
How should I investigate the issue?
I think its not the problem with your configuration or code.
In Spring Framework there is a filter provided named HiddenHttpMethodFilter that serves all the method but initially it will do the POST request but with a hidden _method form field. And this filter reads this hidden field value and then changes the method value accordingly. Please refere this link to know more about this. I think configuring with this filter will resolve your problem.
Hope this helps you. Cheers.

Resources