spring mvc RequestMapping and redirecting to view - spring-mvc

I have a code in MyController
#RequestMapping("/hello.jsp")
public void handleRequest() {
System.out.println("hello.jsp");
logger.info("Returning hello view");
}
#RequestMapping("/hello2")
public ModelAndView hello2() {
System.out.println("123");
String message = "Hello World, Spring 3.0!";
return new ModelAndView("hello2", "message", message);
}
In dispatcher-servlet.xml I have:
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
In the end I have:
~8080/hello2.htm - OK
~8080/hello.htm - NOT OK, aloso I tried: hello.jsp, hello; moved hello.jsp to /WEB-INF/jsp/ and to/WEB-INF/ - no effect
1.hello2() is working well, and redirecting to the hello2.jsp
2.hello() is NOT working, and NOT redirecting
Before putting "viewResolver" into dispatcher-servlet.xml I had opposite behaviour - hello() was working hello2() was not. [but then I had all my jps in WEB-INF folder]
What is the reason?
my web.xml consists this:
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.htm</url-pattern>
</servlet-mapping>

I think this is because you are returning void instead of the view name.
#RequestMapping("/hello")
public String handleRequest() {
System.out.println("hello.jsp");
logger.info("Returning hello view");
return("hello");
}

It was because of '/hello.jsp' - it was trying to find '/hello.jsp.jsp', since I've defined 'viewResolver' with: suffix" value=".jsp".
And before: without 'viewResolver', it was behaving by some default logic, I guess.

Related

org.hibernate.validator.constraints not picking reloaded messages

I am trying to use Spring's ReloadableResourceBundleMessageSource for LocalValidatorFactoryBean so that when I update an error message it should reflect without requiring the server to be restarted. I am using Spring 4.1.4, hibernate-validator 4.3.2.Final.
Below are the code details -
context.xml -
<mvc:annotation-driven validator="validator" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>file:../conf/fileapplication</value> <!-- Messages here will override the below properties file-->
<value>/WEB-INF/application</value>
</list>
</property>
<property name="cacheSeconds" value="10"></property> <!-- Will check for refresh every 10 seconds -->
</bean>
<bean name="validator"
class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="validationMessageSource">
<ref bean="messageSource"/>
</property>
</bean>
Model -
import org.hibernate.validator.constraints.NotBlank;
public class InputForm {
#NotBlank ( message = "{required.string.blank}")
String requiredString;
Controller -
#RequestMapping(value = "/check/string", method = RequestMethod.POST)
public String checkString(
#ModelAttribute("formModel") #Valid InputForm inputForm ,
BindingResult result, Model model, HttpServletResponse response,
HttpServletRequest request) {
if (result.hasErrors()) {
model.addAttribute("formModel", inputForm);
return "userInput";
}
// Do some backend validation with String
result.reject("string.not.valid",
"String is Invalid");
model.addAttribute("formModel", inputForm);
return "userInput";
}
application.properties (in /WEB_INF/ folder)
required.string.blank=Please enter the required string.
string.not.valid=Please enter a valid string.
fileapplication.properties (in /conf/ folder. Will override above file)
required.string.blank=You did not enter the required string. #Does not reflect when I change here
string.not.valid=You did not enter a valid string. #Reflects when I change here
Now the problem I am facing is, when I update "string.not.valid" in fileapplication.properties it reflects at runtime and I see the updated message. But when I update "required.string.blank" in fileapplication.properties it does not reflect at runtime.
Note that the overriding part is working fine for both messages upon application start up. But the "reloading" part is not working fine for "required.string.blank".
This is what I figured out based on my research - We need to create our own MessageInterpolator and add it as dependency to the validator instead of message source. Because when we add a messageSource as dependency, it is cached by default by the validator and any message reloads spring does won't take effect in the validator's cached instance of messageSource.
Below are the details:
In context.xml, add the custom MessageInterpolator as dependency to LocalValidatorFactoryBean instead of messageSource:
<mvc:annotation-driven validator="validator" />
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basenames">
<list>
<value>file:../conf/fileapplication</value> <!-- Messages here will override the below properties file-->
<value>/WEB-INF/application</value>
</list>
</property>
<property name="cacheSeconds" value="10"></property> <!-- Will check for refresh every 10 seconds -->
</bean>
<bean name="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
<property name="messageInterpolator">
<ref bean="messageInterpolator"/>
</property>
</bean>
<bean name="messageInterpolator"
class="com.my.org.support.MyCustomResourceBundleMessageInterpolator">
<constructor-arg ref="messageSource" />
</bean>
Create your custom MessageInterpolator by extending Hibernate's org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator.
public class MyCustomResourceBundleMessageInterpolator extends
ResourceBundleMessageInterpolator {
public MyCustomResourceBundleMessageInterpolator(MessageSource messageSource)
{
// Passing false for the second argument
// in the super() constructor avoids the messages being cached.
super(new MessageSourceResourceBundleLocator(messageSource), false);
}
}
Model, Controller and properties file can be same as in the question.

Spring MVC Tiles Redirect Issue

I am using Spring MVC and Tiles.
When I try to use spring prefix "redirect:" for the redirection I get a servlet exception
- "Could not resolve view...".
Controller
RequestMapping("/SUPPORT.lz")
public String generateSupportView(HttpServletRequest request)
{
String url="http://"+request.getServerName()+":"+request.getServerPort()+"/APP";
AuthenticatedUser user = getUser();
/*
* Check if a user has the role for the page he is trying to access. If
* not redirect him to default page (home page).
*/
if (user.getRoles() != null && !user.getRoles().contains(new Role(0, Role.RoleType.SUPPORT)))
{
return "redirect:"+url;
}
return "support.tiles";
}
dispatcher-servlet.xml
<bean id="tilesViewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver"
p:order="1"
p:viewNames="*.tiles"
p:viewClass="org.springframework.web.servlet.view.tiles2.TilesView"/>
<bean id="nontilesViewResolver"
class="org.springframework.web.servlet.view.XmlViewResolver"
p:order="2"
p:location="/WEB-INF/app-nontiles-views.xml"/>
<bean id="tilesConfigurer"
class="org.springframework.web.servlet.view.tiles2.TilesConfigurer"
p:definitions="/WEB-INF/app-tiles.xml"/>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource"
p:basename="i18n"/>
Solution-
I added internal view resolver in disaptacher servlet.xml and issue got resolved.
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:order="3">
</bean>

why spring mvc not able to read URL from controller class kept in jar file

Please note that I have Existing project in struts 1.x and with the following steps I am trying to integrate Spring MVC to it.
I have a maven project which on deployment is able to read servlet and load respective Controller class from jar file on server start-up and gives following info about controller class:
[org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping] Rejected bean name 'SSOController': no URL paths identified
Looks like it is not loading URLS hence I am not able to make any restful web service call on it.
my web.xml has following entry :
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/hello.do</url-pattern>
</servlet-mapping>
Dispatcher Servlet has following entries:
<context:annotation-config />
<context:component-scan base-package="com.ga.action.controller" />
<mvc:resources location = "/resources/" mapping = "/resources/**" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- JAXB2 marshaller. Automagically turns beans into xml -->
<bean id="jaxbMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>com.ga.action.controller.PEMUtil</value>
</list>
</property>
</bean>
Controller class code follows:
#Controller
#RequestMapping("/hello.do")
public class TestController {
#RequestMapping(method = RequestMethod.GET, value = "/")
public #ResponseBody String printTokenMessage(
#RequestParam("nLiveToken") String message,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
System.out.println(message);
}
}
Use XML configuration instead of #Conteroller annotation for external jar file controllers. Because the #Controller annotation isn't available in the server class loader.
http://forum.spring.io/forum/spring-projects/web/108774-controllers-from-external-jar
Since the exception indicates the use of BeanNameUrlHandlerMapping there should be a bean named /hello.do in your context.
You do use the #RequestMapping annotation so I guess you assumed annotation driven handler mapping would be enabled by default. Which isn't the case. If the ServletDispatcher finds no handler mapping it will create a BeanNameUrlHandlerMapping for you.
If you want to use annotations in your application you should define
<mvc:annotation-driven />
in your context configuration.

internal resource view resolver with multiple subfolders under jsp

Hi I used Internal resource view resolver and my structure of jsp are like
jsp/adm, jsp/icon, jsp/iload, like
and my annotation based controller will return string value based on condition
my problem is jsp uder sub-folder is not resoled but it is under jsp folder is working
could any one please help me in this
he is my code:`
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
my controller code is
#RequestMapping("/icrl")
public String search() throws Exception
{
setMenuName(CommonConstants.ICRL);
return "pgiCRL";
}
#RequestMapping("/searchCodes")
public String searchCodes() throws Exception
{
String key=getSearchKey();
String query=getQuery();
Map<String, Object> searchKeys = new HashMap<String, Object>();
ArrayList<String> list=new ArrayList<String>();
if(query!=null||!query.isEmpty()){
searchKeys.put(CommonConstants.DIAGICD9, getDiaICD9());
searchKeys.put(CommonConstants.DIAGICD10, getDiaICD10());
searchKeys.put(CommonConstants.DIAGNOSIS, getDiagnosis());
searchKeys.put(CommonConstants.PROCEDURE, getProcedure());
searchKeys.put(CommonConstants.SURGICAL, getSurgical());
searchKeys.put(CommonConstants.SURGICAL9, getSurICD9());
searchKeys.put(CommonConstants.SURGICAL10, getSurICD10());
searchKeys.put(CommonConstants.REVENUE, getRevenue());
list= (ArrayList<String>) iCRLService.getSearchCodeList(query,searchKeys);
}
setSuggestions(list);
return CommonConstants.SUCCESS;
}
my view is depending on condition it may be success page and failure page so i need to fix the return value in controller because that is dynamic.
Thanks in advance
You need to define the subfolder name in the returning string value.
For Example, if your page "pgiCRL" is in admin subfolder then return "admin/pgiCRL".

Forward a servlet request to another server

Java Servlet API can forward requests to another path within the same server (identical host:port). But, forwarding to a different host:port — like proxy do — is another story.
I've tried to do that with Jersey Client, adapting the ServletRequest — method, headers, mediatype and body — to a Jersey ClientRequest (with a different base uri), making the call, and adapting back the Jersey ClientResponse — method, headers, mediatype and body — to the ServletResponse.
Adapting those manually seems wrong to me.
Isn't there a pure Servlet API solution?
Or an HTTP client capable of adapting requests back and forth when changing the host:port?
HTTP-Proxy-Servlet does exactly what you need.
Quick configuration
pom.xml
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.7</version>
</dependency>
web.xml
<servlet>
<servlet-name>solr</servlet-name>
<servlet-class>org.mitre.dsmiley.httpproxy.ProxyServlet</servlet-class>
<init-param>
<param-name>targetUri</param-name>
<param-value>http://solrserver:8983/solr</param-value>
</init-param>
<init-param>
<param-name>log</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>solr</servlet-name>
<url-pattern>/solr/*</url-pattern>
</servlet-mapping>
Spring Integration
see also: HTTP-Proxy-Servlet Issue #15
pom.xml
<dependency>
<groupId>org.mitre.dsmiley.httpproxy</groupId>
<artifactId>smiley-http-proxy-servlet</artifactId>
<version>1.7</version>
</dependency>
ServletWrappingControllerExt.java
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.ServletWrappingController;
public class ServletWrappingControllerExt extends ServletWrappingController
{
private String pathToStrip;
public void setPathToStrip(String pathToStrip)
{
this.pathToStrip = pathToStrip;
}
#Override
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
throws Exception
{
final HttpServletRequest wrapper = new HttpServletRequestWrapper(request)
{
#Override
public String getPathInfo()
{
//Please note that getPathInfo returns null if DispatcherServlet is configured to track url-pattern "/"
//It should be configured to track url-pattern "/*". Below is a sample DispatcherServlet configuration
/*
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
*/
String path = super.getPathInfo();
if (path.startsWith(pathToStrip))
{
final int length = pathToStrip.length();
path = path.substring(length);
}
return path;
}
#Override
public String getServletPath()
{
return super.getServletPath();
}
};
return super.handleRequestInternal(wrapper, response);
}
}
Beans configuration
<bean id="myServletWrapper" class="ServletWrappingControllerExt">
<property name="pathToStrip" value="/solr"/>
<property name="servletClass" value="org.mitre.dsmiley.httpproxy.ProxyServlet" />
<property name="servletName" value="solr" />
<property name="initParameters">
<props>
<prop key="targetUri">http://solrserver:8983/solr</prop>
<prop key="log">true</prop>
</props>
</property>
</bean>
<bean id="myServletUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="urlMap">
<map>
<entry key="/solr/**" value-ref="myServletWrapper" />
</map>
</property>
<property name="order" value="1" />
</bean>
You should use javax.net.HttpURLConnection
Here is the psuedo code for that:
URL url = new URL("http://otherserver:otherport/url");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
// set http method if required
connection.setRequestMethod("POST");
// set request header if required
connection.setRequestProperty("header1", "value1");
// check status code
if(connection.getResponseCode() == 200) {
InputStream is = connection.getInputStream();
//transfer is to the required output stream
} else {
//write error
}
As far as I understand You need to send requests from Servlet and get response from other server into yours, may be you need a HTTP Client (Overview) for that.
This question might also help you.

Resources