Spring MVC maven Controller called twice - spring

I am new to Spring mvc, maven and tomcat. I have written a controller for which I have defined a bean. Now when I type the url in broswer like: localhost:8080/hello.htm my controller is called and it is called again when I hit this URL.
Eg
<bean name="/hello.htm" class="com.paytm.controller.InventoryController">
<property name="jdbcProductDao">
<bean class="com.paytm.repository.JdbcProductDao">
<constructor-arg ref="dataSource"></constructor-arg>
</bean>
</property>
</bean>
And in the controller
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Product product = new Product();
product.setPrice(23.45);
product.setDescription("Test Product");
this.jdbcProductDao.saveProduct(product);
...
}
As a result the product is saved twice in the DB. My query is why is the controller called when I type the URL(and not hit it)?

Your browser caches your url when it sees
the same url in the omnibox every now and then. Clear your cache and it will fix your issue. You can check your chrome prerenders by typing this in your chrome browser.
chrome://net-internals/#prerender
For more details your can take a look at this source

Related

Is my app's Controllers thread safe ? Spring 4.1

I am developing an app in spring 4.1 . I know that Controllers / any other bean in spring are not thread safe . ie: Singleton. That mean same instance of Controller will be used to process multiple concurrent requests. Till here I am clear . I want to confirm that do I need to explicitly set #Scope("prototype") or request in the Controller class ? I read on StackOverflow previous post that even if scope is not set as request/prototype , Spring container will be able to process each request individually based on #RequestParams passed or #ModelAttribute associated with method arguements .
So i want to confirm is my below code is safe to handle multiple request concurrently ?
#Controller
public class LogonController {
/** Logger for this class and subclasses */
protected final Log logger = LogFactory.getLog(getClass());
#Autowired
SimpleProductManager productManager;
#Autowired
LoginValidator validator;
#RequestMapping( "logon")
public String renderForm(#ModelAttribute("employee") Logon employeeVO)
{
return "logon";
}
#RequestMapping(value="Welcome", method = RequestMethod.POST)
public ModelAndView submitForm(#ModelAttribute("employee") Logon employeeVO,
BindingResult result)
{
//Check validation errors
validator.validate(employeeVO, result);
if (result.hasErrors()) {
return new ModelAndView("logon");
}
if(!productManager.chkUserValidation(employeeVO.getUsername(), employeeVO.getPassword())){
return new ModelAndView("logon");
}
ModelAndView model = new ModelAndView("Welcome");
return model ;
}
}
Also i have another doubt.
since i am using SimpleProductManager productManager; Do i need to specify scope="prototype in its bean declaration in app-servlet.xml ?
Below is my configuration.xml
<bean id="mySessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="configLocation" value="classpath:hibernate.cfg.xml" />
</bean>
<bean id="productManager" class="com.BlueClouds.service.SimpleProductManager" >
<property name="productDao" ref="productDao"/>
</bean>
<bean id="productDao" class="com.BlueClouds.dao.HbmProductDao">
<property name="sessionFactory"><ref bean="mySessionFactory"/></property>
</bean>
<bean id="loginValidator" class="com.BlueClouds.service.LoginValidator" >
</bean>
Being singleton single instance of validator is being shared among all request , for that do i need to add scope=request in bean configuration xml or do i need to surround validate() in synchronized block ? Please advise.
Thanks much .
You can tell your code is thread safe or not by answering following questions
Are there threads might modify a static field, which is not thread safe(ex: arrayList), in the same time?
Are there threads might modify a field of an instance, which is not thread safe, in the same time?
If any answer of the above is yes, then your code is not thread safe.
Since your code doesn't change any field, so it should be thread safe.
The general idea about thread safe is that if there are threads might change/access the same memory section in the same time, then it's not thread safe, which means "synchronized" is needed.
You'd better learn more about stack memory, heap memory and global memory in JAVA. So that you can understand if your code changes the same memory section in the same time or not.

How do I use Spring/JUnit to verify a controller is not sending me to a non-existent view?

I'm using Spring 3.1.1.RELEASE and JUnit 4.11. I setup my JUnit tests like so
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({ "classpath:test-context.xml" })
public class MySpringTest
{
protected MockHttpServletRequest request;
protected MockHttpServletResponse response;
protected MockHttpSession session;
#Autowired
protected RequestMappingHandlerAdapter handlerAdapter;
#Autowired
protected RequestMappingHandlerMapping handlerMapping;
When testing controllers, I have this line to verify that the view the controller's method is returning is the right view …
import static org.springframework.test.web.ModelAndViewAssert.assertViewName;
...
final ModelAndView mav = submitMyForm(…);
assertViewName(mav, "folder/myView");
...
protected ModelAndView submitMyForm(… params ...) throws Exception {
request = new MockHttpServletRequest();
response = new MockHttpServletResponse();
request.setRequestURI("/myurl");
request.setMethod("POST");
request.addParameter("param1", param1);
...
final Object handler = handlerMapping.getHandler(request).getHandler();
return handlerAdapter.handle(request, response, handler);
}
My question is, once I verify the view returned my the controller is the expected view, how do I verify it won't result in a 404? The main problem I'm gaving now is testing whether or not the view actually maps to an underlying page in my WAR file.
why don't use spring-mvc-test and do something like this ?
#Autowired
private ViewResolver viewResolver;
// code
View view = viewResolver.resolveViewName(viewName, locale);
//assert view not null
or something like this, in wich you can check both if the view is ok and the returned status (is status 200/404?)
(more code here: http://goo.gl/fMqBsl)
#Test
public void indexTest() throws Exception {
mockMvc.perform(get("/")).andDo(print())
.andExpect(handler().handlerType(MainController.class))
.andExpect(handler().methodName("index"))
.andExpect(view().name("index"))
.andExpect(forwardedUrl("/WEB-INF/tiles/template.jsp"))
.andExpect(status().isOk());
}
i am using standard jsp view
basically, you need to know the view resolver(s). can a specific view be resolved? that means, if you DON'T have a file called abc.xml, it might still be a valid view.
for simplicity sake, lets assume that we have only one view resolver, and, its
"org.springframework.web.servlet.view.UrlBasedViewResolver"
and here is the bean definition
spring 3.2.4 documentation pdf, page 477
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
eg: the view name "page1" => /WEB-INF/jsp/page1.jsp and "admin/page2" => /WEB-INF/jsp/admin/page2.jsp
using this, you can Inject the view resolved to your junit test using #Autowired and/or #Qualifier
then read the "prefix" and suffix value and find the full path like "src/main/webapp/" + prefix + viewname + suffix
and check if the file exists.
you may have multiple view resolvers, so you may want to inject the context and handle the view => filename resolution using a strategy pattern.
something like
foreach resolver
{
if i can resolve the view to a file (resolver type, viewname)
return the physical filename
else
try next resolver
}

#RequestBody or #ModelAttribute with Spring+REST web services

I am creating a Restful website and Web services for iPhone and android apps with Spring 3.1. In my application, i am using Spring Message Convertors (org.springframework.http.converter.json.MappingJacksonHttpMessageConverter) to converting JSON into Java object and vice-versa.
My objective is that there should be only single controller
method(same URL) that should be used by JSP page, Iphone/Andois app.
I am using Spring form tag for object binding from JSP to controller with the help of #ModelAttribute like below.
#RequestMapping(value = "reset-password", method = RequestMethod.POST)
public ModelAndView resetPassword(#ModelAttributeForgot forgotPassword,
HttpServletRequest request) {
System.out.println("data recived=="+forgotPassword.getNewPassword());
}
But the same is NOT working in the case if the data is being posted from iPhone/Android app and the result is:
data recived==null;
So to overcome this problem i have used #RequestBody annotation at place of #ModelAttribute.
So my controller looks like below:
#RequestMapping(value = "reset-password", method = RequestMethod.POST)
public ModelAndView resetPassword(#RequestBody Forgot forgotPassword,
HttpServletRequest request) {
System.out.println("data recived=="+forgotPassword.getNewPassword());
}
It works then and the result i got is:
data recived==somedata;
But #RequestBody then doesn't work with spring form on JSP page and the data doesn't get converted into object and i got null values.
Can't i use #RequestBody annotation to post data in form of JSON
with spring form tag from JSP page??
Is there any way by using which i can post data from my JSP form as
well as from I phone App by using only a single controller method(either #ModelAttribute or #RequestBody).
EDIT:
While writing String in place of Bean class, i am able to get the content in form of plain text, as below:
#RequestMapping(value = "reset-password", method = RequestMethod.POST)
public ModelAndView resetPassword(#RequestBody String string,
HttpServletRequest request) { }
Result from web page call:
uid=11&confirmPassword=somepassword&newPassword=somepassword
Result from iPhone using web service call(in **JSON)**
{"newPassword":"somepassword","confirmPassword":"somepassword","uid":"11"}
But problem is that using this approach i have to parse the JSON string into Java object manually. And in web page content i have to find the values manually that i don't want.
Please help.
Regards,
Arun Kumar
Sorry, but I don't believe there is a way, because #ModelAttribute is bound from form post parameters and #RequestBody passes the body straight to the Json converter. You could replace the spring form tag with a simple json post, but that is probably less convenient than having two #RequestMapping methods.
Its #RequestBody. I feel its better to specify the mime type that you are expecting and producing as output using #RequestMapping as,
#RequestMapping(value="/authenticate",produces="application/json",
consumes="application/json",method=RequestMethod.POST)
Then register appropriate message converters with AnnotationMethodHandlerAdapter
This message converter is responsible for Marshalling & unmarshalling of your request & response entity based on produces & consumes attributes.
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" >
<property name="order" value="1" />
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter" >
<property name="supportedMediaTypes" value="application/json"/>
</bean>
<bean class = "org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
</bean>
</list>
</property>
</bean>

Adding custom RequestCondition's in Spring mvc 3.1

I have a Spring mvc (3.1.1) app, and I want to define conditions beyond what's available in RequestMapping. I have a couple of things I want to use it for.
First, it would be nice if I could show a different home page for different user types:
#Controller
public class HomepageController {
#RequestMapping(value = "/")
#CustomCondition(roles = Guest.class)
public String guestHome() { /*...*/ }
#RequestMapping(value = "/")
#CustomCondition(roles = Admin.class)
public String adminHome() { /*...*/ }
}
Second, I want the app to function both as a web site and as a REST service (e.g. for mobile apps), so I'd want to let the website access both html and json actions, and let the service (different subdomain) only access json actions (some kind of #CustomCondition(web = true) which only matches website urls)
Can this work for any of the two uses I'm planning?
I found very little documentation about custom conditions, but I did find one example that implements custom conditions which might be what I want, but it uses a #Configuration class instead of the XML configuration which I'm using and I don't want to move my entire spring xml definitions to a #Configuration class.
Can I define a customMethodCondition for RequestMappingHandlerMapping in the XML?
I tried subclassing RequestMappingHandlerMapping and override getCustomMethodCondition, to return my custom RequestCondition, but it didn't work - getMatchingCondition() in my condition didn't fire.
Any help would be greatly appreciated!
UPDATE
I read a little more, and it looks like RequestMappingHandlerMapping is a new class (since ver 3.1).
What happens in my app is that the #Configuration that tries to override and thereby redefine the requestMappingHandlerMapping bean actually works, but the url mappings (#RequestMapping methods in #Controllers) seem to get processed twice, once by the subclass ExtendedRequestMappingHandlerMapping and once by the original RequestMappingHandlerMapping --first with a custom condition, and then again without it.
Bottom line is my custom conditions are simply ignored.
This is supposed to be an advanced pattern, but IMO it should be quite common...
Comments anyone?
Spring MVC already provides a mechanism for distinguishing between json and html, the RequestMapping annotation takes a consumes attribute which looks at the content type of the request...
// REST version, Content-type is "application/json"
#RequestMapping(value = "/", consumes = "application/json")
public void myRestService() {
...
// HTML version, Content-type is not "application/json"
#RequestMapping(value = "/", consumes = "!application/json")
public void myHtmlService() {
...
Another way to use the same url but have distinct methods is with the param or headers attribute...
// the url is /?role=guest
#RequestMapping(value = "/", param = "role=guest")
public void guestService() {
// the url is / with header role=admin
#RequestMapping(value = "/", headers = "role=admin")
public void adminService() {
I would think you would want distinct urls for security. Typically, with something like Spring Security, you would put all of the admin functionality under /admin and let the framework manage it all...
<http auto-config="true">
<intercept-url pattern="/admin/**" access="ROLE_ADMIN" />
...
Would this be sufficient for your use case(s)?
If you have extended RequestMappingHandlerMapping(say ExtendedRequestMappingHandlerMapping) you have to register this new mapping a little differently in application context xml.
You cannot use <mvc:annotation-driven/> to configure the Spring MVC as that defines it's own handlerMapping internally, you can instead do something along these lines(or follow the approach in the link with #Configuration that you have provided):
<bean name="handlerAdapter" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer">
<property name="conversionService" ref="conversionService"></property>
<property name="validator">
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
</property>
</bean>
</property>
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.ByteArrayHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.ResourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.SourceHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter"></bean>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean>
</list>
</property>
</bean>
<bean name="handlerMapping" class="..ExtendedRequestMappingHandlerMapping">
</bean>
This should ensure that your mapping takes effect and will ensure that the appropriate handler method is found by the handlerAdapter component.

Keeping request parameters on Spring SimpleFormController with Validator

I hope I'll be able to explain this properly. I'm developing a portlet for Liferay by using Spring. It's a pinboard system. So I have a view (Jsp) which shows the detail of a certain pinboard entry, given its id. Furthermore there is a link which goes to an AddCommentController for adding a new comment to the pinboard entry the user is currently watching at. The AddCommentController extends Spring's SimpleFormController and has also a validator attached to it:
<bean id="addCommentController" class="com.lifepin.controllers.AddCommentController" parent="lifePinControllerTemplate">
<property name="formView" value="addComment" />
<property name="successView" value="viewEntryDetail" />
<property name="validator" ref="commentValidator"/>
</bean>
The validator is really simple and looks as follows:
public class CommentValidator implements Validator {
public boolean supports(Class clazz) {
return clazz.equals(Comment.class);
}
public void validate(Object obj, Errors validationError) {
ValidationUtils.rejectIfEmptyOrWhitespace(validationError, "content", "err.content.empty", "This value is required");
}
}
Now the view where the user can enter his comment has two buttons, Save and cancel. Here are the two generators for the according urls.
<portlet:actionURL var="actionUrl">
<portlet:param name="action" value="addComment"/>
<portlet:param name="pinboardEntryId" value="${param.pinboardEntryId}"/>
</portlet:actionURL>
<portlet:renderURL var="cancelUrl">
<portlet:param name="action" value="viewPinboardEntry"/>
<portlet:param name="pinboardEntryId" value="${param.pinboardEntryId}"/>
</portlet:renderURL>
In the onSubmitAction of the AddCommentController I read out the parameter (see the 1st actionURL above) and pass it to the ActionResponse s.t. in the detail view of the pinboard entry I can again load the entry and display it.
public class AddCommentController extends SimpleFormController{
...
#Override
protected void onSubmitAction(ActionRequest request, ActionResponse response, Object command, BindException bindException)
throws Exception {
long pinboardEntryId = PortletRequestUtils.getLongParameter(request, ParameterNameConstants.PINBOARDENTRY_ID, -1);
...
}
...
}
This all works fine, except when a validation error occurs. In that case I loose the "pinboardEntryId" parameter from the URL, and I don't have any way to read that parameter in the CommentValidator to pass it to the response again since I don't have any PortletRequest or response.
For now I solved this problem by storing the id on the session and by retrieving it from there. I wanted to ask however if some of you has an alternative solution without having to use the session. I'm quite sure there is one.
Thanks,
Juri
An even easier solution is to set the renderParameters property. The renderParameters property is an array of parameter names that SimpleFormController will always forward. For example:
<bean id="addCommentController" class="...">
....
<property name="renderParameters">
<list>
<value>pinboardEntryId</value>
</list>
</property>
</bean>
This will cause the 'pinboardEntryId' parameter to be passed every time without any additional code.
On validation errors showForm(..) gets called again. You could overwrite this method and manipulate Request and Response as you like.
I first tried the showForm(..) approach suggested by Oliver Gierke (thanks for the feedback) but that didn't work out as expected. The showForm(..) wants to return a new ModelAndView which I don't want to care since that should be done by the onSubmitAction(...).
The right approach is to override the
#Override
protected void processFormSubmission(ActionRequest request, ActionResponse response, Object command, BindException errors){
...
}
There, all the needed information is available. I can check now the BindingException whether there have been validation errors by using errors.hasErrors(). If that's the case, I can read the needed parameters and forward them to the response to have them on the form again. Otherwise I just call the onSubmitAction(..), passing the needed parameters such as the request, reponse etc.. which I have available in the processFormSubmission.

Resources