Implementing Spring MVC 3.0 controller - spring-mvc

Trying to implement clean URLs (without .form, .do, etc.) with Spring MVC 3.0 (actually it's a basic example from Spring reference).
The problem that it just don't work: http://localhost:8080/ct/helloWorld gives a 404 page.
Below are my sources, plese help to find an error.
HelloWorldController.java
package controllers;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
#Controller()
public class HelloWorldController {
#RequestMapping("/helloWorld")
public ModelAndView helloWorld() {
ModelAndView mav = new ModelAndView();
mav.setViewName("helloWorld");
mav.addObject("message", "Hello World!");
return mav;
}
}
ct-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:component-scan base-package="controllers" />
<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/" />
<property name="suffix" value=".jsp" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
</beans>
web.xml
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>
ct</display-name>
<servlet>
<servlet-name>ct</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ct</servlet-name>
<url-pattern>/ct/*</url-pattern>
</servlet-mapping>
</web-app>
console output
12.11.2009 0:49:25 org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.j2ee.server:ct' did not find a matching property.
12.11.2009 0:49:25 org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: C:\Program Files\Java\jre6\bin;.;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:/Program Files/Java/jre6/bin/client;C:/Program Files/Java/jre6/bin;C:\Program Files\PC Connectivity Solution\;C:\PROGRA~1\RATIONAL\RATION~1\NUTCROOT\bin;C:\PROGRA~1\RATIONAL\RATION~1\NUTCROOT\bin\x11;C:\PROGRA~1\RATIONAL\RATION~1\NUTCROOT\mksnt;C:\Program Files\Borland\Delphi7\Bin;C:\Program Files\Borland\Delphi7\Projects\Bpl\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Microsoft SQL Server\80\Tools\Binn\;C:\Program Files\Microsoft SQL Server\90\DTS\Binn\;C:\Program Files\Microsoft SQL Server\90\Tools\binn\;C:\Program Files\Microsoft SQL Server\90\Tools\Binn\VSShell\Common7\IDE\;C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies\;C:\Program Files\TortoiseSVN\bin;C:\Program Files\QuickTime\QTSystem\;e:\my downloads\develop tools\nant-0.86-beta1\bin\;C:\Program Files\Rational\common;C:\Program Files\Rational\ClearQuest;C:\Program Files\Rational\Rose\TopLink\;C:\Program Files\Rational\Rational Test;C:\Program Files\CodeGear\Delphi Prism\bin
12.11.2009 0:49:25 org.apache.coyote.http11.Http11Protocol init
INFO: Initializing Coyote HTTP/1.1 on http-8080
12.11.2009 0:49:25 org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 769 ms
12.11.2009 0:49:25 org.apache.catalina.core.StandardService start
INFO: Starting service Catalina
12.11.2009 0:49:25 org.apache.catalina.core.StandardEngine start
INFO: Starting Servlet Engine: Apache Tomcat/6.0.20
12.11.2009 0:49:26 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'ct'
12.11.2009 0:49:26 org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet 'ct': initialization started
12.11.2009 0:49:26 org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing WebApplicationContext for namespace 'ct-servlet': startup date [Thu Nov 12 00:49:26 MSK 2009]; root of context hierarchy
12.11.2009 0:49:26 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
INFO: Loading XML bean definitions from ServletContext resource [/WEB-INF/ct-servlet.xml]
12.11.2009 0:49:27 org.springframework.beans.factory.support.DefaultListableBeanFactory preInstantiateSingletons
INFO: Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory#197507c: defining beans [helloWorldController,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,viewResolver,org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping#0,org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#0]; root of factory hierarchy
12.11.2009 0:49:27 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/helloWorld] onto handler [controllers.HelloWorldController#1c2fff0]
12.11.2009 0:49:27 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/helloWorld.*] onto handler [controllers.HelloWorldController#1c2fff0]
12.11.2009 0:49:27 org.springframework.web.servlet.handler.AbstractUrlHandlerMapping registerHandler
INFO: Mapped URL path [/helloWorld/] onto handler [controllers.HelloWorldController#1c2fff0]
12.11.2009 0:49:28 org.springframework.web.servlet.FrameworkServlet initServletBean
INFO: FrameworkServlet 'ct': initialization completed in 2641 ms
12.11.2009 0:49:28 org.apache.coyote.http11.Http11Protocol start
INFO: Starting Coyote HTTP/1.1 on http-8080
12.11.2009 0:49:28 org.apache.jk.common.ChannelSocket init
INFO: JK: ajp13 listening on /0.0.0.0:8009
12.11.2009 0:49:28 org.apache.jk.server.JkMain start
INFO: Jk running ID=0 time=0/79 config=null
12.11.2009 0:49:28 org.apache.catalina.startup.Catalina start
INFO: Server startup in 3451 ms

Your web.xml is mapping the Spring DispatcherServlet to the url pattern /ct/* on top of the location your web application is being deployed to.
So if your web application is being deployed to /ct try going to http://localhost:8080/ct/ct/helloWorld
Chances are that you want the Spring DispatcherServlet to be mapped to all urls for your web application. Change the servlet-mapping to:
<servlet-mapping>
<servlet-name>ct</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
and your original url should work as expected.

OK, for now solution is:
web.xml
<servlet-mapping>
<servlet-name>ct</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
HelloWorldController.java
#Controller
public class HelloWorldController {
#RequestMapping("/helloWorld")
public String list() {
return "helloWorld";
}
}
ct-servlet.xml
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />

The path in your RequestMapping should be the full path, not just the pathInfo (the stuff after the matched string in the web.xml). So your RequestMapping should specify #RequestMapping("/ct/HelloWorld")
Alternatively, your problem may be that you aren't running your app as the root app and is actually running at the path /ct. In that case, your web.xml isn't matching anything because the /ct which designates the application context is not used when comparing the url-patterns in order to determine the servlet context. In that case, you need to access the url /ct/ct/HelloWorld in order to send the request to your servlet. But you'll still need #RequestMapping("/ct/HelloWorld") in order for the controller to be mapped to that request (but it doesn't care about the initial /ct which designates the app).
Personally, I actually think it is clear to map based on a suffix, but to use a generic suffix. I map *.html to my servlet and controllers which respond to those requests send back html. Similarly, I use *.json and *.xml for json and xml requests. I handle static html and other static content at the load balancer, so tomcat never sees them.

Have you created your helloWorld.jsp page?
I tried out your code (NB: using 2.5.6), and saw a 404 on the browser, and the following error message in the server log:
File "/path/to/my/WEB-INF/helloWorld.jsp" not found
Where /path/to/my will be different for your env.
Without helloWorld.jsp, the view resolver will fail. Adding this jsp, and all is well.

Related

Spring not find controller when run application

I've read so many topics that had same issue with my case from here but found nothing to solve my problem. This is my servlet configuration using namespace
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util"
xmlns:sec="http://www.springframework.org/schema/security"
xmlns:mail="http://www.springframework.org/schema/integration/mail"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/mail
http://www.springframework.org/schema/integration/mail/spring-integration-mail-1.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- Configures the #Controller programming model -->
<mvc:annotation-driven />
<!-- Scans the classpath of this application for #Components to deploy as beans -->
<context:component-scan base-package="fi.vietjob" />
<!-- Resolves view names to protected .jsp resources within the /WEB-INF/views
directory -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<!-- Forwards requests to the "/" resource to the "welcome" view -->
<mvc:view-controller path="/" view-name="index" />
<!-- location of static content (images, js and css files) -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:lang" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="defaultLocale" value="vn" />
</bean>
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
</mvc:interceptors>
<!--config for upload image -->
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />
</beans>
Here is my stackstrace when restarting server
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version: Apache Tomcat/8.0.14
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server built: Sep 24 2014 09:01:51
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server number: 8.0.14.0
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Name: Mac OS X
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Version: 10.10.5
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Architecture: x86_64
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Version: 1.8.0_11-b12
Jan 11, 2017 9:34:17 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Vendor: Oracle Corporation
Jan 11, 2017 9:34:17 AM org.apache.catalina.core.AprLifecycleListener init
INFO: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: /Users/dinhthinh/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.
Jan 11, 2017 9:34:17 AM org.apache.tomcat.util.digester.SetPropertiesRule begin
WARNING: [SetPropertiesRule]{Server/Service/Engine/Host/Context} Setting property 'source' to 'org.eclipse.jst.jee.server:vietduuni' did not find a matching property.
Jan 11, 2017 9:34:18 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8001"]
Jan 11, 2017 9:34:18 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Jan 11, 2017 9:34:18 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["ajp-nio-8009"]
Jan 11, 2017 9:34:18 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFO: Using a shared selector for servlet write/read
Jan 11, 2017 9:34:18 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 1064 ms
Jan 11, 2017 9:34:18 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service Catalina
Jan 11, 2017 9:34:18 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/8.0.14
Jan 11, 2017 9:34:18 AM org.apache.jasper.servlet.TldScanner scanJars
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jan 11, 2017 9:34:20 AM org.apache.catalina.core.ApplicationContext log
INFO: No Spring WebApplicationInitializer types detected on classpath
Jan 11, 2017 9:34:21 AM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring root WebApplicationContext
log4j:WARN No appenders could be found for logger (org.springframework.web.context.ContextLoader).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Jan 11, 2017 9:34:23 AM org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring FrameworkServlet 'vietjob'
Jan 11, 2017 9:34:25 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8001"]
Jan 11, 2017 9:34:25 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-nio-8009"]
Jan 11, 2017 9:34:25 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 7262 ms
web.xml configuration
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!-- Servlet config begin -->
<servlet>
<servlet-name>vietjob</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>vietjob</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- end-->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Begin load Spring Filter Chain config from servlet vietjob -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/vietjob-security.xml
</param-value>
</context-param>
<!-- end load -->
<!-- Begin Spring security config-->
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
When i run my application, nothing errors found but in stacktrace it not showing text row that inform controllers were loaded. So when i hit the link, i got 404 error. Anyone can help me?!
Removing log4j12 dependency in pom.xml file resolved my problem.
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.5</version>
</dependency>
You didn't shared how you started your application.
For any spring web application you have to provide the configuration for DispatcherServlet in your application.
Method 1
You could put below mapping in your web.xml file
<servlet>
<servlet-name>myWebApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myWebApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Method 2
You could register a bean implementing interface WebApplicationInitializer and could register DispatcherServlet programmatically
Now bean configuration file name should be {servlet-name}-servlet.xml
So for above servlet, bean configuration file name should be myWebApp-servlet.xml
Or if you want to customize the name of your bean configuration file, then you can mention it inside the web.xml as below
<servlet>
<servlet-name>myWebApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring-mvc-config.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>myWebApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>

Is it possible to configure OpenSessionInViewFilter in Spring application context so that context:property-placeholder is useable?

Initial situation
My web application consists of the Maven modules myapp-persistence(.jar), myapp-model(.jar), myapp-service(.jar) and myapp-web(.war) to get a conventional, loosely coupled, multi-tiered architecture. All modules are joined together by a parent Maven module, which only contains the parent POM with general definitions for all sub modules.
Especially myapp-service(.jar) and myapp-persistence(.jar) hold their own configurable (!) application context parts with the needed objects. Both jars must be deployable with the containing variable definitions, in other words the jars must not have concrete values for the variables.
myapp-service-context.xml declares a solrServer bean with the variable of the server URL:
<bean id="solrServer" class="org.apache.solr.client.solrj.impl.HttpSolrServer">
<constructor-arg value="${solr.serverUrl}" />
<property name="connectionTimeout" value="60000"/>
<property name="defaultMaxConnectionsPerHost" value="40"/>
<property name="maxTotalConnections" value="40"/>
</bean>
myapp-persistence-context.xml defines a dataSource with connection variables:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
</bean>
...
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
...
</bean>
myapp-web(.war) references myapp-service(.jar) and myapp-persistence(.jar). In myapp-servlet.xml it includes their application context parts and provides the property values for configuration of the declared beans by a property file. By context:property-placeholder Spring initializes all the variables with the concrete values when it creates the application context in memory.
<context:property-placeholder location="classpath*:myapp-configuration.properties" />
<import resource="classpath*:myapp-persistence-context.xml"/>
<import resource="classpath*:myapp-service-context.xml"/>
For the development profile the concrete myapp-configuration.properties may look like:
solr.serverUrl=http://localhost:8983/solr
jdbc.dialect=org.hibernate.dialect.HSQLDialect
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:mem:myapp
jdbc.username=sa
jdbc.password=
This configuration is imo straight forward and works - without view. The problem arises when org.springframework.orm.hibernate3.support.OpenSessionInViewFilter comes into play.
Problem description
OpenSessionInViewFilter ensures that instances in the object graph which are not loaded within an open transaction during the controller processing can be lazily loaded, if the view tries to display these objects´ content (see [1]). As often described this filter is declared in the delpoyment descriptor web.xml (see [2]):
<filter>
<filter-name>OpenSessionInViewFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OpenSessionInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
If myapp-persistence-context.xml is included in myapp-servlet.xml like above so that context:property-placeholder works, OpenSessionInViewFilter does not find the necessary sessionFactory. The reason seems to be that Spring first processes web.xml and then myapp-servlet.xml, which imports myapp-persistence-context.xml. Unfourtunately I can´t proof this guess by a reference. Following exception is thrown:
GRAVE: Servlet.service() for servlet [myapp] in context with path [/myapp] threw exception
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'sessionFactory' is defined
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:529)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1095)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:277)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1097)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:242)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.lookupSessionFactory(OpenSessionInViewFilter.java:227)
at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:171)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:662)
Different application context parts are usually included by the deployment descriptor with a ContextLoaderListener and not by myapp-servlet.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
classpath*:myapp-service-context.xml,
classpath*:myapp-persistence-context.xml
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<listener>
<listener-class>
org.springframework.web.context.request.RequestContextListener
</listener-class>
</listener>
With this configuration unfourtunately, Spring´ s context:property-placeholder mechanism seems not to work any more.
Objective and Question
Modules like myapp-persistence(.jar) and myapp-service(.jar) must be configurable at run-time with a property file by the referencing context, e.g. the application context of myapp-web(.war).
The question is: Is it possible to configure OpenSessionInViewFilter in Spring application context so that context:property-placeholder is still useable?
Or alternatively: How can variables in applicaton contexts be initialized by Spring at run-time, if application context parts are included in the deployment descriptor web.xml?
Fundamentally: Why is actually OpenSessionInViewFilter necessary to be configured, why Spring MVC does not transparently support view lazy loading out-of-the-box?
Anticipating Remarks
Property replacement at compile-time is not the point here. The profile dependent property file is already created with Maven Filtering.
Moving dataSource and solrServer declarations into myapp-servlet.xml as already proposed (see [3], [4]) is not an acceptable solution, because it destroyes modularity and independent testability of myapp-persistence(.jar) and myapp-service(.jar) - actually the spirit of dependency injection!
Talking to a colleague brought the solution: context:property-placeholder remains useable if I use Spring´s interceptor instead of the Servlet-API´s filter mechanism. I removed the reference of myapp-persistence-context.xml in contextConfigLocation and the OpenSessionInViewFilter from web.xml and declared an OpenSessionInViewInterceptor in myapp-persistence-context.xml:
<mvc:interceptors>
<bean id="openSessionInViewInterceptor" class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</mvc:interceptors>
With myapp-persistence-context.xml in the classpath of myapp-persistence(.jar) and the import statement in myapp-servlet.xml as described above, Spring replaces all property variables with the values in myapp-configuration.properties at run-time as intended. Modularity is saved at its best! Will Keeling´s externalization of the property file completes the project setup.
See also the discussion Spring HandlerInterceptor vs Servlet Filters and the Spring doc.
You should certainly keep the sessionFactory and non-web related beans in the root application context as defined by the contextConfigLocation in the web.xml. Apart from the modularity aspect (as you mention), the OpenSessionInViewFilter needs it this way because it looks for the sessionFactory in the root web application context and it will error if it can't find it there - as you discovered. So your contextConfigLocation setup is the correct way to go.
PropertyPlaceholderConfigurer is a BeanFactoryPostProcessor which means it works within the context of the bean factory in which it is defined. In this case, it is defined in myapp-servlet.xml which means it will work within the web context but it won't resolve the placeholders in the root application context (where the dataSource and solrServer are defined).
My suggestion would be to move the <context:property-placeholder> from the web to the root application context - but parameterize the location allowing this to be set by the enclosing app. For example, you could add this to your myapp-service-context.xml
<context:property-placeholder location="${props.file}"/>
And then you can leave it to the myapp-web.war (or whatever the parent app happens to be) to set the location of the file. For example, this could be done as a system property:
-Dprops.file=file:C:/myapp-configuration.properties

What is causing the mapping failure in this Spring MVC app?

I'm trying to get a very simple Spring #mvc app to work and I'm running into what appears to be a mapping error.
From web.xml:
<servlet>
<servlet-name>works</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>works</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
The controller:
#Controller
#RequestMapping("/test")
public class TESTController {
private static Logger appLogger = Logger.getLogger("AppLogFile");
public String serviceRequest( Model model)
{
appLogger.info("======================= TESTController GET ===============================");
model.addAttribute("returnString","TESTController handled the request") ;
return "SingleStringView";
}
works-servlet.xml:
<context:component-scan base-package="com.ami.dbconnect.controller" />
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"/>
<bean id="TESTController" class="com.ami.dbconnect.controller.TESTController"></bean>
<!-- view resolver not shown -->
The app is deployed to Tomcat 7 at /webapps/works. The Tomcat file structure is:
webapps
/works
/WEB-INF
/classes
/lib
I'm trying to invoke the controller with the url: localhost:8080/works/test
In tomcat7-stdout I see:
1106 [pool-2-thread-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Published WebApplicationContext of servlet 'works' as ServletContext attribute with name [org.springframework.web.servlet.FrameworkServlet.CONTEXT.works]
1106 [pool-2-thread-1] INFO org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'works': initialization completed in 728 ms
1106 [pool-2-thread-1] DEBUG org.springframework.web.servlet.DispatcherServlet - Servlet 'works' configured successfully
14068 [http-apr-8080-exec-2] DEBUG org.springframework.web.servlet.DispatcherServlet - DispatcherServlet with name 'works' processing GET request for [/works/test]
14071 [http-apr-8080-exec-2] WARN org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/works/test] in DispatcherServlet with name 'works'
So my question (finally!):
Is Spring not recognizing the annotations in the controller? If not, what could be wrong in this simple set up?
Thanks for any help or advice,
beeky
You need to move #RequestMapping annotation to your serviceRequest method.
#RequestMapping at class level may be used to specify common path prefix for all #RequestMapping-annotated of that class, but it doesn't take any effect without annotations at method level.
Maybe problem is in the servlet mapping section?
Try to change:
<servlet-mapping>
<servlet-name>works</servlet-name>
<url-pattern>/works/*</url-pattern>
</servlet-mapping>
And try again.

Spring MVC: Why do I need to (and how do I?) provide a mapping for a JSP view?

I'm attempting to have a controller method return a ModelAndView object which uses a JSP as the view. The application context configuration for the ViewResolver:
<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>
The JSP I'm using for the view is located as /WEB-INF/jsp/error.jsp:
<%# page language="java"
contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<html>
<body>
<h1>Unexpected Error</h1>
${message}
</body>
</html>
In my controller I resolve the View and return the ModelAndView:
ModelAndView modelAndView = new ModelAndView("error");
modelAndView.addObject("message", errorMessage);
return modelAndView;
I can step through the code and all looks good until the ModelAndView is returned, at which point I see this in the log:
DEBUG 2011-11-03 15:33:52,262 (org.springframework.web.servlet.view.JstlView:236) - Forwarding to resource [/WEB-INF/jsp/error.jsp] in InternalResourceView 'error'
DEBUG 2011-11-03 15:33:52,262 (org.springframework.web.servlet.DispatcherServlet:845) - DispatcherServlet with name 'dispatcherServlet' determining Last-Modified value for [/nacem-rest/WEB-INF/jsp/error.jsp]
DEBUG 2011-11-03 15:33:52,263 (org.springframework.web.servlet.DispatcherServlet:853) - No handler found in getLastModified
DEBUG 2011-11-03 15:33:52,263 (org.springframework.web.servlet.DispatcherServlet:693) - DispatcherServlet with name 'dispatcherServlet' processing GET request for [/nacem-rest/WEB-INF/jsp/error.jsp]
WARN 2011-11-03 15:33:52,263 (org.springframework.web.servlet.PageNotFound:965) - No mapping found for HTTP request with URI [/nacem-rest/WEB-INF/jsp/error.jsp] in DispatcherServlet with name 'dispatcherServlet'
DEBUG 2011-11-03 15:33:52,264 (org.springframework.web.servlet.DispatcherServlet:674) - Successfully completed request
So it looks like I also need to have some sort of mapping for JSP files, even though the web.xml specifies all URLs should be handled by the DispatcherServlet:
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/application-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Apparently I need to add a request mapping for this JSP file into the controller, although I'm not sure why or how. The View backed by the JSP is a JstlView and I assumed that Spring knows how to deal with that and see to it that it's rendered in the browser. But maybe not, and I need to add some code to make this happen? It looks like there's a redirection going on and I need to catch the request again by another mapped controller method, and within that method go about rendering the JSP. Is this the case? I don't see anything at all in the reference documents which explain how to do this, maybe someone can point me in the right direction?
Thanks in advance for your comments, suggestions, etc.
I'm not sure what the difference is, but looking at the equivalent in one of my (working) apps, I use InternalResourceViewResolver instead of UrlBasedViewResolver. For example:
<bean 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>
Also, less likely, my web.xml has a different pattern (/ instead of /*):
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/spring/*.spring.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Everything else you have looks pretty much the same.

Glassfish 3 - Loading images from a static server

I'm trying to load images (and other static content) from a server outside of my web application which is deployed to Glassfish v3. I have the following configs in the web.xml but it does not work on Glassfish (but it works on Tomcat):
<servlet>
<servlet-name>ExternalImagesServlet</servlet-name>
<servlet-class>com.example.servlet.HttpProxyServlet</servlet-class>
<init-param>
<param-name>RemoteURI</param-name>
<param-value>http://ip.of.second.server/website-files</param-value>
</init-param>
<init-param>
<param-name>AllowedContentTypes</param-name>
<param-value>image/gif,image/jpeg,image/png</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ExternalImagesServlet</servlet-name>
<url-pattern>/images/*</url-pattern>
</servlet-mapping>
Where ip.of.second.server is an actual IP address of the server. I have the file called website-files.xml defined as follow:
<?xml version="1.0" encoding="UTF-8"?>
<Context docBase="d:/internet/website/images" />
And website-files.xml is saved to glassfish\domains\domain1\config directory. But Glassfish does not pick up this config file.
I have looked at Oracle Glassfish configuration doco but there's no mention on how you can reference images from a different server.
Please help.
I have solved it based on an old thread relating to Glassfish version 2 that I found on Google after two days of search.
In case anyone is interested in the solution, here it is:
1) Create a file called sun-web.xml directly under Webcontent\WEB-INF directory and add the following configuration to this file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sun-web-app PUBLIC "-//Sun Microsystems, Inc.//DTD GlassFish Application Server 3.0 Servlet 3.0//EN" "http://www.sun.com/software/appserver/dtds/sun-web-app_3_0-0.dtd">
<sun-web-app>
<property name="alternatedocroot_1" value="from=/images/* dir=d:/internet/website" />
<property name="alternatedocroot_2" value="from=/files/* dir=d:/internet/website" />
</sun-web-app>
2) Remove the servlet and servlet-mapping configurations from web.xml file (like I did above). Note: The above would work if you were to use Tomcat.
3) Delete the website-files.xml from glassfish\domains\domain1\config directory as this file is not needed by Glassfish: Note: This file is needed by Tomcat.

Resources