Should we perform db operation using #PathVariable in Spring? - spring

GET should be used for viewing something, without changing it, while POST should be used for changing something. For example, a search page should use GET, while a form that changes your password should use POST.
So in Spring we have #PathVariable annotation and we can access it in our controller.
My questions is:
1)Should we use path variable in our controller to perform any DB operation like delete or update as it seems clearly in the URL.If yes then it can be a hole in our application that anyone can make that request again.
I know that we can use #RequestParam with POST method in spring as well as with GET method but I just want to know that if it is okay to use PathVariable to change our database.

It is not a matter of #RequestParam, #RequestBody, or #PathVariable. You should check for correct user ROLES to do the database operation as long as these three methods can be automated using tools. Pure case of logic!

There is no matter if you use #PathVariable or #RequestParam.
I think the important part you have to think about is, that you can use hidden input fields. And they can be catched with the #RequestParam annotation.
So I would say it depends on what you want to show in your url and what you want to "hide".

Related

When To Use #SessionAttribute Over #ModelAttribute

I'm having a hard time figuring out a specific time in which one would use #SessionAttribute over #ModelAttribute.
This question arose because after making a web application I realised that I have got a lot of methods that I passed in Principal principal to. In these methods, I use principal.getName() to get the username of the logged-in user and then retrieve the relevant data from the database using that username. In short, a lot of my methods needed access to the current user data and I resolved this in what I believe to be an inefficient manner.
To rectify this I was going to create a model attribute in a class annotated with #ControllerAdvice, in which I get the principal and get the user data from the database and add it to the model.
E.g model.addAttribute("currentUser", currentUser);
so that in the parameter list of these methods I can have (#ModelAttribute("currentUser") UserAccount currentUser)
saving unnecessary work by getting the principal and then proceeding to get the user from the database.
While I don't know a whole lot about #SessionAttribute, I feel like this sort of data(UserAccount currentUser) is more relevant to the session as opposed to the model. Am I Wrong?
I also heard that #SessionAttribute doesn't make its data available across multiple controllers which in this case I need. Hence why I'm using #ControllerAdvice.
My questions are as follows:
What is the best practice for implementing the above where I need to
repeatedly access the current users data. Maybe I can further increase efficiency by adding a current user bean on login and then use #Autowired so that I wouldn't even need to have currentUser in the parameter list. But I don't know if that's even possible. Is it?
Is it true that the method annotated with #ModelAttribute is called
prior to every #RequestMapping, #GetMapping, #PostMapping etc. call?
and that an object specific to #SessionAttribute remains in the
model for the duration of the session?
Also In what situation should I user #SessionAttribute over
#ModelAttribute?
The #SessionAttrributes annotation is for the use-case where you need to have a model attribute that you need to access over multiple screens. Like doing a checkout for a shopping cart, you would store the Order in the session, screen 1, confirm, screen 2 payment details, screen 3, delivery details, screen 4 OK. After screen 4 you would then call SessionStatus.setComplete() and it will clean that attribute.
That is the use case for #SessionAttributes and should be used in conjunction with #ModelAttribute. It is not intended to be used to store a, for instance, the user in the session for the duration of the HttpSession.
The #SessionAttribute (a different annotation!) is to retrieve an attribute from the HttpSession that was placed there earlier. In your case after authentication, you would place the User in the HttpSession with HttpSession.setAttribute("currentUser", user);. In a controller method, you could use #SessionAttribute("currentUser") User user to retrieve and use it. No need for an #ControllerAdvice or model attribute anymore.
However I would strongly to ditch your custom security implementation and use something like Spring Security instead. That way all that, and more, is already provided out of the box. In a controller method you can then use the #AuthenticationPrincipal annotation to retrieve the current user.

Spring #ModelAttribute and #SessionAttribute behaviour

What is the best way to use SessionAttributes and ModelAttributes together? When I use, for example, a tagged ModelAttribute method and the SessionAttribute on the class, then the POJO is added to session, but in other controller that uses the same name for this kind of ModelAttribute then it does not retrieve the one I want but takes the one present in the session.
Then, what is the best way to manage the behaviour of ModelAttributes with SessionAttributes?
Thanks.
When you have done with the model in the session (I assume you just want to use that 'model in session' in specific Controller only) you have to set mySessionStat.setComplete() where in the parameter you declare SessionStatus mySessionStat
see:
SessionStatus api docs

Best practice for using #SessionAttributes

I am trying to share data between two controllers in a Spring mvc application.
In Controller A I have annotated the class with #SessionAttributes({"mymodel1"}) and in the method which receives the first GET request I add it to the ModelMap:
model.addAttribute("mymodel1", MyModel1);
I now want to read myModel1 from Controller B.
In this Controller I have the following method which intercepts the POST requests and already has a different model in its parameters:
public String processSubmit(#ModelAttribute("mymodel2") MyModel2 mymodel2, BindingResult result, SessionStatus status, HttpServletRequest httpRequest)
Up to this point everything works fine and I am able to read mymodel2 from processSubmit however if I now want to add another #ModelAttribute("mymodel1") MyModel1 mymodel1 to this method signature I would have expected to be able to read the value I was setting in Controller A however I'm getting exceptions that the first model is no longer recognised.
So my question is: how can I read mymodel2 from Controller B?
You can't do that with #SessionAttributes :
Session attributes as indicated using this annotation correspond to a specific handlers model attributes, getting transparently stored in a conversational session. Those attributes will be removed once the handler indicates completion of its conversational session. Therefore, use this facility for such conversational attributes which are supposed to be stored in the session temporarily during the course of a specific handlers conversation.
For example I use this annotation when I want to validate elements with Hibernate validation, and after I submit the page and SOME elements are invalid I want the rest to be still on the page, but this is not your case. I think that the only way to do it would be with:
HttpSession.getAttribute()
The javadoc excerpt above is the most typical way #SessionAttributes is used. However, what Joly is describing should also work. Session attributes are stored via DefaultSessionAttributeStore, which by default does not prefix attribute names when it stores them in the session. That means if ControllerA and ControllerB both list an attribute called "mymodel1", they're actually referring to the same session attribute. You'll need to provide a little more information on the error you're getting and the actual controller code.

Best practice for validating a URL with Spring-MVC?

I am using Spring MVC for my web application.
I need to validate that the URL the user inputs is valid and was wondering if there is something in Spring that can do the basic checks for me (for example starts with http/https, has domain name etc).
ValidationUtils only contains very basic checks and I know I can write a regular expression in the validate() method however prefer to avoid it inm case someone has already done it :)
Thanks
In the past, I have always utilized Hibernate Validator. Simply annotate the appropriate field in your form bean with a #URL constraint.
If you've never used the ORM part of Hibernate before, don't let that scare you. The Validator portion is not dependent on the ORM stuff, and integrating it into Spring is very straightforward.
If for some reason you can't use Hibernate Validator... or you just want to stick with what you're comfortable with, a good place for regex's is RegExLib.com; several patterns that can match a URI are listed there.
Ended up using UrlValidator from apache commons.
I know this question is quite old, but I just need the same and I think I'll go with the PropertyEditors in SpringFramework.
More precisely there is URLEditor, which you can use to convert a String representation to an actual URL object.
Here is a link to the respective documentation:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-beans-conversion
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/beans/propertyeditors/URLEditor.html
In my case, I think about using the following code within a Spring Validator to check whether a String entered by a user is a valid URL or not:
try {
PropertyEditor urlEditor = new URLEditor();
urlEditor.setAsText(field.getValue());
} catch (IllegalArgumentException ex) {
errors.rejectValue("nameOfTheFieldToBeValidated", "url_is_invalid");
}
However, as for now, I'm unsure whether it is possible to configure which protocol is going to be accepted as valid (i.e. URLEditor seems to also accept URLs starting with "classpath:")
Use a spring interceptor:
http://java.dzone.com/articles/using-spring-interceptors-your

Spring 3.0 URL pattern validation

I'm wanting to to add an endpoint like /user/foo where foo is one of a set of values determined at runtime. I'm wondering what the best way is to do this in Spring, or indeed if it should even been done in Spring an not handled at the controller level.
I'm currently using Springs security filter chain, so I did think about putting a filter in front of /user/* to do this validation. Is this a reasonable solution or is there a more desirable solution I have missed?
You can use #PathVariable annotation on a method argument. #PathVariable also allows regex if you need to validate the structure of the varible.
http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/PathVariable.html
and for the regex
http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/bind/annotation/RequestMapping.html

Resources