I have a very simple problem. When in my .jsp files I have a link to **/registration the method viewRegistration is executed and everything is working fine. If I have a link to **/registration/getTags?tagName=blahblah page is not found. I have no idea why, because I think my requestMapping annotation looks correct... I would be very grateful for your help!
CONTROLLER:
#Controller
#RequestMapping(value = "/registration")
public class HelloController {
final static Logger logger = Logger.getLogger(HelloController.class);
#RequestMapping(method = RequestMethod.GET)
public String viewRegistration(Map<String, Object> model, HttpSession session) {
...
}
#RequestMapping(value = "/getTags", method = RequestMethod.GET)
public #ResponseBody
List<Tag> getTags(#RequestParam String tagName) {
....
}
}
WEB.XML:
<?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" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" version="3.0">
<display-name>aa</display-name>
<servlet>
<servlet-name>xxx</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>xxx</servlet-name>
<url-pattern>/registration/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/xxx-servlet.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
xxx-servlet.xml :
<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"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
<context:component-scan base-package="movies.controller" />
<context:property-placeholder location="/WEB-INF/properties/website.properties" />
<context:component-scan base-package="com" />
<context:annotation-config />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.tiles3.TilesConfigurer"
id="tilesConfigurer">
<property name="definitions">
<list>
<value>/WEB-INF/tile/tilesJsp.xml</value>
</list>
</property>
</bean>
<mvc:resources mapping="/resources/**" location="/resources/" />
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver"
id="viewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.tiles3.TilesView" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="website" />
</bean>
</beans>
EDIT EDIT EDIT:
I even tried sth more simple:
#RequestMapping(value = "/getTags")
#ResponseBody
public List<Tag> getTags() {
String tagName="";
return simulateSearchResult(tagName);
}
but still /registration/getTags does not work..., page not found.
the servlet url mapping is as follows :
<servlet-mapping>
<servlet-name>xxx</servlet-name>
<url-pattern>/registration/*</url-pattern>
</servlet-mapping>
which means that all urls that begin with /registration/* will be handled by the servlet, what comes after it , it will be handled by the controller.
So if you configure your controller with a #RequestMapping(value="/otherURL") it will serve the following Url :
http://localhost:xxxx/<appname>/registration/otherURL
And in this case in order to access the right method you should either:
#RequestMapping("/registration) from the controller, cause it is already mapped on the servlet level, and calling :
http://localhost:xxxx/<appname>/registration/getTags?tagName=blahblah will work correctly.
OR:
Call this URL : http://localhost:xxxx/<appname>/registration/registration/getTags?tagName=blahblah
If you want to handle requests to **/registration/getTags, change your controller method mapping to
#RequestMapping(value = "**/registration/getTags", method = RequestMethod.GET)
Your mapping should be fine. However, I believe you're running into this because you're requesting "/registration/getTags?name=blahblah" and yet your handler's parameter is "tagName". Try changing your request to "/registration/getTags?tagName=blahblah".
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-requestparam
As Nick Cromwell mentioned the issue with your mapping is the mismatch between the name of the parameter in your request and in your mapping. So either change in the request as he mentions, rename the argument in the handler method, or use the value attribute of the #RequestParam annotation, e.g.
List<Tag> getTags(#RequestParam(value="name") String tagName)
Use the requestParam as following:
List<Tag> getTags(#RequestParam("tagName") String tagName)
Update your url to
/registration/getTags/{blahblah}
and in controller -
#RequestMapping(value = "/getTags/{blahBlah}")
public #ResponseBody List<Tag> getTags(#PathVariable String blahBlah) {
String tagName="";
return simulateSearchResult(tagName);
}
I'm suspecting this is related to the view resolver configuration, you are using
org.springframework.web.servlet.view.UrlBasedViewResolver
You only have one view resolver which returns jsp pages. And in your method you are trying to return a List object which I believe you want to be serialized as JSON in http body.
To return a json response you can try to use #JSONView
Spring #JsonView
and add another viewResolver like org.springframework.web.servlet.view.json.MappingJacksonJsonView on the xml config, such as illustrated by this blog
multiple view resolvers
You have servlet url mapping at /registration/*
In class you have mapping at /registration
In method you have mapping at /getTags
So, your url is /registration/registration/getTags?name=blahblah
Related
I have the following error when I try to acces into main page
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userJpaRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'net.codejava.spring.repository.UserRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true), #org.springframework.beans.factory.annotation.Qualifier(value=userJpaRepository)}
In my UserController I have the following code
#Controller
public class UserController {
private UserService employeeServiceImpl;
#RequestMapping("/")
public String employee() {
this.employeeServiceImpl.listAlUsers();
return "employee";
}
#Autowired(required = true)
public void setEmployeeService(UserService employeeServiceImpl) {
this.employeeServiceImpl = employeeServiceImpl;
}
}
My UserService
public interface UserService {
public abstract List<User> listAlUsers();
public abstract User addUser(User user);
public abstract int removeUser(int id);
public abstract User updateUser(User user);
}
My UserServiceImpl
#Service("userService")
public class UserServiceImpl implements UserService {
#Autowired
#Qualifier("userJpaRepository")
private UserRepository userJpaRepository;
#Override
public List<User> listAlUsers() {
return userJpaRepository.findAll();
}
#Override
public User addUser(User user) {
return userJpaRepository.save(user);
}
#Override
public int removeUser(int id) {
userJpaRepository.delete(id);
return 0;
}
#Override
public User updateUser(User user) {
return userJpaRepository.save(user);
}
}
My JpaRepository
#Repository("userJpaRepository")
public interface UserRepository extends JpaRepository<User,Serializable> {
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
My servlet-context
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<!--The <context:component-scan...> tag will be use to activate Spring MVC annotation scanning capability which allows to make use of annotations like #Controller and #RequestMapping etc.-->
<!--Step 1 : HandlerMapping -->
<context:component-scan base-package="com.loiane.controller" />
<!--JPA Repository-->
<jpa:repositories base-package="com.loiane.repository.EmployeeJpaRepository"/>
<mvc:annotation-driven />
<!--Step 3 : View Resolver-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!--Bundles-->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename">
<value>messages</value>
</property>
</bean>
<!--Declaramos el interceptor para permitir el cambio de idioa en tiempo de ejecucion-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean id="localeChangeInterceptor"
class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
</mvc:interceptor>
</mvc:interceptors>
<!--Si el idioma no existe cargamos el en-->
<bean id="localeResolver"
class="org.springframework.web.servlet.i18n.CookieLocaleResolver">
<property name="cookieName" value="lang" />
<property name="defaultLocale" value="en" />
</bean>
</beans>
The root-context is empty.
I don't know where is the possible cause of error I try to find differents options , but If I use the DAO pattern I receive the same error , so I would to know which is to problem to try to solve it.
The configuration of the project is with xml but I think there is not important to solve this situation.
Regards !
You are using bean qualifier name on repository interface #Repository("userJpaRepository"). Qualifier names are useful if more than 1 class is implementing the common interface. It helps to resolve the specific bean, which is to be autowired to other bean's interface variable. Declaring it on an interface will defeat its purpose. Removing the qualifier name should work if no other class (other than spring created proxy bean whose name would be userRepositoryImpl) is implementing UserRepository interface.
#Autowired
private UserRepository userJpaRepository;
And replace the Serializable with the Datatype of the ID column like Integer or Idclass.
#Repository
public interface UserRepository extends JpaRepository<User,Integer> {
}
Now to enable spring to scan for the interface that extent its predefined repository interfaces, add package to scan for in your spring context
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<jpa:repositories base-package="net.codejava.spring.repository"/>
In my case it was a problem with incorrect User import (instead of import a User entity that I've created manually - I've imported another User).
I've changed import org.springframework.security.core.userdetails.User;
to import org.springframework.data.jpa.repository.JpaRepository;
Sample code I have:
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="3.0">
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
springDispatcher-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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
<bean id="myController" class="biz.tugay.springWebOne.MyController"/>
</beans>
MyController.java
package biz.tugay.springWebOne;
/* User: koray#tugay.biz Date: 08/07/15 Time: 15:25 */
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
#Controller
public class MyController {
#RequestMapping(value = "/hello")
public String helloWorld(){
return "index.jsp";
}
}
Well, everything works fine with this code. However when I remove the
#Controller
from MyController class I will get:
HTTP ERROR 404
Problem accessing /hello. Reason:
Not Found
I am not using component-scan, I am using an xml based configuration. Why do I need the #Controller annotation?
from spring reference documentation here
The #Controller annotation acts as a stereotype for the annotated
class, indicating its role. The dispatcher scans such annotated
classes for mapped methods and detects #RequestMapping annotations
so #Controller is required to tell dispatcher to scan mapping in this class not only for component scan.
If you are using component scanning, Spring will not know where to scan for #RequestMapping without the #Controller annotation. If you would like to configure your requestmappings with XML, that should be able to be done similar to one of the answers here: #RequestMapping with XML
Your example will not work because the #Controller annotation is essentially the "entry point" telling the component scanner to scan this class, without #Controller all other spring controller annotations (eg. #RequestMapping) will be ignored.
I noticed that you pointed out that you are not using component-scan and you are using xml-based configuration, but in reality you are attempting to mix xml-based and annotation-based configuration for a single class, which will lead to very sloppy code. I would recommend removing your xml bean definition and using only the #Controller annotation and adding the component-scan tag in your xml to clean up your code.
If you decide you still want to do xml only configuration you should remove the #RequestMapping annotation and replace it with the following xml.
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/hello" value-ref="myController"/>
</map>
</property>
</bean>
If you want to use Spring without annotations, so you can use a BeanNameUrlHandlerMapping to indicate the controller class to the Dispatcher. So, just add the following bean to your XML and you do not have to include the #Controller anymore:
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
I have user service that treat user entity, and #Autowired in user controller class before use user service. so, I got the error:
Unsatisfied 'required' dependency of type [class com.yes.service.UserService]. Expected at least 1 matching bean
here the codes:
userService
package com.yes.service;
import java.util.List;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yes.domain.User;
import com.yes.repository.RoleRepository;
import com.yes.repository.UserRepository;
#Service
public class UserService {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
public User create(User user) {
user.setId(UUID.randomUUID().toString());
user.getRole().setId(UUID.randomUUID().toString());
// We must save both separately since there is no cascading feature
// in Spring Data MongoDB (for now)
roleRepository.save(user.getRole());
return userRepository.save(user);
}
public User read(User user) {
return user;
}
public List<User> readAll() {
return userRepository.findAll();
}
public User update(User user) {
User existingUser = userRepository.findByUsername(user.getUserName());
if (existingUser == null) {
return null;
}
existingUser.setFirstName(user.getFirstName());
existingUser.setLastName(user.getLastName());
existingUser.getRole().setRole(user.getRole().getRole());
// We must save both separately since there is no cascading feature
// in Spring Data MongoDB (for now)
roleRepository.save(existingUser.getRole());
return userRepository.save(existingUser);
}
public Boolean delete(User user) {
User existingUser = userRepository.findByUsername(user.getUserName());
if (existingUser == null) {
return false;
}
// We must delete both separately since there is no cascading feature
// in Spring Data MongoDB (for now)
roleRepository.delete(existingUser.getRole());
userRepository.delete(existingUser);
return true;
}
}
userController (where i use the userService, and the problem is)
#Controller
#RequestMapping("/users")
public class UserController {
#Autowired
private UserService service;
#RequestMapping
public String getUsersPage() {
return "users";
}
#RequestMapping(value="/records")
public #ResponseBody UserListDto getUsers() {
UserListDto userListDto = new UserListDto();
userListDto.setUsers(service.readAll());
return userListDto;
}
#RequestMapping(value="/get")
public #ResponseBody User get(#RequestBody User user) {
return service.read(user);
}
#RequestMapping(value="/create", method=RequestMethod.POST)
public #ResponseBody User create(
#RequestParam String username,
#RequestParam String password,
#RequestParam String firstName,
#RequestParam String lastName,
#RequestParam Integer role) {
Role newRole = new Role();
newRole.setRole(role);
User newUser = new User();
newUser.setUserName(username);
newUser.setPassword(password);
newUser.setFirstName(firstName);
newUser.setLastName(lastName);
newUser.setRole(newRole);
return service.create(newUser);
}
#RequestMapping(value="/update", method=RequestMethod.POST)
public #ResponseBody User update(
#RequestParam String username,
#RequestParam String firstName,
#RequestParam String lastName,
#RequestParam Integer role) {
Role existingRole = new Role();
existingRole.setRole(role);
User existingUser = new User();
existingUser.setUserName(username);
existingUser.setFirstName(firstName);
existingUser.setLastName(lastName);
existingUser.setRole(existingRole);
return service.update(existingUser);
}
#RequestMapping(value="/delete", method=RequestMethod.POST)
public #ResponseBody Boolean delete(
#RequestParam String username) {
User existingUser = new User();
existingUser.setUserName(username);
return service.delete(existingUser);
}
}
spring-data.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:c="http://www.springframework.org/schema/c" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo-1.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.1.xsd">
<context:property-placeholder
properties-ref="deployProperties" />
<!-- MongoDB host -->
<mongo:mongo host="${mongo.host.name}" port="${mongo.host.port}" />
<!-- Template for performing MongoDB operations -->
<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate"
c:mongo-ref="mongo" c:databaseName="${mongo.db.name}" />
<!-- Activate Spring Data MongoDB repository support -->
<mongo:repositories base-package="com.yes.repository" mongo-template-ref="mongoTemplate"/>
<!-- Service for initializing MongoDB with sample data using MongoTemplate -->
<bean id="initMongoService" class="com.yes.service.InitMongoService" init-method="init"/>
</beans>
servlet-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
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">
<!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
<!-- Enables the Spring MVC #Controller programming model -->
<annotation-driven />
<context:component-scan base-package="com.yes.controller"/>
<!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
<resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<beans:property name="prefix" value="WEB-INF/views/" />
<beans:property name="suffix" value=".jsp" />
</beans:bean>
applicationContext.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:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<context:property-placeholder
properties-ref="deployProperties" />
<!-- Activates various annotations to be detected in bean classes -->
<context:annotation-config />
<!-- Scans the classpath for annotated components that will be auto-registered
as Spring beans. For example #Controller and #Service. Make sure to set the
correct base-package -->
<context:component-scan base-package="com.yes.domain"/>
<context:component-scan base-package="com.yes.dto"/>
<context:component-scan base-package="com.yes.service"/>
<!-- Configures the annotation-driven Spring MVC Controller programming
model. Note that, with Spring 3.0, this tag works in Servlet MVC only! -->
<mvc:annotation-driven />
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- Imports datasource configuration -->
<import resource="spring-data.xml" />
<bean id="deployProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean"
p:location="/WEB-INF/spring/spring.properties" />
the error stack:
ERROR: org.springframework.web.servlet.DispatcherServlet - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.yes.service.UserService com.yes.controller.UserController.service; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.yes.service.UserService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/applicationContext.xml</param-value>
</context-param>
<!-- Creates the Spring Container shared by all Servlets and Filters -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Processes application requests -->
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/appServlet/servlet-context.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>appServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
EDIT: the question is after fix the errors written in Sotirios Delimanolis answer and comment.
What is the problem cause the error?
Answer: The problem was what was described in Sotirios Delimanolis answer. The Exact solution described in comments on his answer
thank you
Your application context and servlet context are component scanning over the same packages.
Your application context
<context:component-scan base-package="com.yes" />
Versus everything in servlet context
<context:component-scan base-package="com.yes.service"/>
<context:component-scan base-package="com.yes.controller"/>
<context:component-scan base-package="com.yes.domain"/>
<context:component-scan base-package="com.yes.repository"/>
<context:component-scan base-package="com.yes.dto"/>
So some beans will be overriden. You don't want this. Your servlet context should scan for #Controller beans. Your application context should scan for everything else, but don't make your application context scan for things already scanned by your child (imported) data context. Fix your package declarations so all of these are disjoint.
This question already has answers here:
Why does Spring MVC respond with a 404 and report "No mapping found for HTTP request with URI [...] in DispatcherServlet"?
(13 answers)
Closed 5 years ago.
I'm going crazy and can't understand what the problem is:
I have the following structure:
SpringMVC
+WebContent
-web-inf
-web.xml
-springMVC-servlet.xml
-index.jsp
-security
-login.jsp
web.xml
<display-name>springMVC</display-name>
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/index.html</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
springMVC-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans 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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans">
<context:annotation-config/>
<context:component-scan base-package="com.vanilla.springMVC"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="prefix">
<value>/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
My Controller:
package com.vanilla.springMVC;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.portlet.ModelAndView;
#Controller
public class DefaultController {
#RequestMapping(value="/index.html", method=RequestMethod.GET)
public ModelAndView index(){
ModelAndView mv = new ModelAndView("index");
return mv;
}
#RequestMapping(value="/login.html", method=RequestMethod.GET)
public ModelAndView loginPage(){
ModelAndView mv = new ModelAndView("/security/login");
return mv;
}
}
I have no problem to navigate to /index.html
http://localhost:8080/SpringMVC/index.html
works perfect.
however when I'm navigating to
http://localhost:8080/SpringMVC/login.html
i have 404 error.
HTTP Status 404 - /SpringMVC/login.jsp
type Status report
message /SpringMVC/login.jsp
description The requested resource (/SpringMVC/login.jsp) is not available.
I don't want to move login.jsp on the same level as index.jsp, but why do I have this problem?
I'll just add this in here, because it solved my 404 issue. It turned out my problem was the url-mapping value in web.xml. Using Spring WebMVC version org.springframework:spring-webmvc:4.1.6.RELEASE
I was using the following (which didn't work):
<url-pattern>/rest</url-pattern>
I should've been using the following value (which works):
<url-pattern>/rest/*</url-pattern>
or
<url-pattern>/</url-pattern>
Reference: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html
HTTP 404 means that the resource is not found.
This means the controller or a direct accessed resource (like a CSS file) is not found
It does NOT mean that the JSP referred in the controller is not found (this would be a 500 Internal Server Error)
HTTP Status 404 - /SpringMVC/login.jsp
It looks like that you send a HTTP request /SpringMVC/login.jsp but your controller method is bound to .html, so you need to change your HTTP request to /SpringMVC/login.html
Because of the name (login) may your Spring Security configuration is not correct.
create a folder under WEB-INF "jsps" for all your views, and under "jsps" a "security" folder for your case.
NOTICE: Moving the JSP files into WEB-INF, you can prevent direct access on these files. It is needed for application security. Think about a situation, in which your JSPs gives personal informations about your customer and the access has to be granted/checked by your controller. If your JSPs are existing out of WEB-INF, they are accessible with a request directly on them.
configure your view resolver like this:
<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/jsps"/>
<property name="suffix" value=".jsp"/>
</bean>
next, put your login JSPs into the "WEB-INF/jsps/security"
and return "security/login" from your loginPage.
Now, the view resolver searchs for the views under "WEB-INF/jsps". Because your method return "security/login", the view resolver expects a directory under jsps called "security" and a JSP file under this, which is called "login.jsp" (suffix = jsp)
I suspect that ModelAndView mv = new ModelAndView("/security/login"); is where the problem is. Make sure you have a directory 'security' folder in your root directory and it contains a login.jsp file. Or try moving the security folder inside WebContent
Provide the contextConfigLocation init parameter of your DispatcherServlet
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/springMVC-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
I am using Spring MVC with eclipse and a MacOS X system and encountered a 404 error when controller returning the correct jsp name. I later figured out that the problematic jsp file has no x(execution) right on the file system. I then `chmod +x some.jsp' and the issue is resolved.
Adding this ans here just in case someone else faces the same issue.
My app was working fine earlier, then I upgraded Spring version and in the process also upgraded spring-security version. When I tried to access my login html page I was facing this issue. I had made all the necessary configurations changes because of the change of spring-security version from 3 to 4. I referred to this link and it was very helpful.
I was facing this problem because of the below configuration in my web-servlet.xml file
<mvc:resources mapping="/app/*.html" location="/app/*.html" cache-period="0"/>
<mvc:resources mapping="/app/**/*.html" location="/app/**/*.html" cache-period="0"/>
It worked after I modified both location values to "/app/". It seems like newer version of spring matches either the whole string or checks if the requested location starts with the location value configured above.
I found the below code in org.springframework.web.servlet.resource.PathResourceResolver:
if (locationPath.equals(resourcePath)) {
return true;
}
locationPath = (locationPath.endsWith("/") || locationPath.isEmpty() ? locationPath : locationPath + "/");
if (!resourcePath.startsWith(locationPath)) {
return false;
}
The second if condition was evaluating to false in my case and hence the 404 HTTP response
Another tip, if you face such error try enabling highest level of springframework logging. You might get to know the error reason from there.
This answer may be outdated for the above question, but it will help others who are just starting with spring.
I was also struggling with 404 WEB-INF/welcome.jsp page not found error.
Here issue is with ModelAndView import
Replace
import org.springframework.web.servlet.ModelAndView;
With
import org.springframework.web.portlet.ModelAndView;
If we develop REST using Spring MVC, it will support XML and JSON data. I have wrote ContentNegotiationViewResorver in my spring config bean app-servlet.xml
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver"
p:order="1">
<property name="mediaTypes">
<map>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller">
<bean class="org.springframework.oxm.xstream.XStreamMarshaller"
p:autodetectAnnotations="true" />
</property>
</bean>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
</list>
</property>
</bean>
And my spring REST Controller is:
#Controller
#RequestMapping("/rest/customers")
class CustomerRestController {
protected Log log = LogFactory.getLog(CustomerRestController.class);
#RequestMapping(method = POST)
#ResponseStatus(CREATED)
public void createCustomer(#RequestBody Customer customer,
HttpServletResponse response) {
log.info(">>>" + customer.getName());
response.setHeader("Location", String.format("/rest/customers/%s",
customer.getNumber()));
}
#RequestMapping(value = "/{id}", method = GET)
#ResponseBody
public Customer showCustomer(#PathVariable String id) {
Customer c = new Customer("0001", "teddy", "bean");
return c;
}
#RequestMapping(value = "/{id}", method = PUT)
#ResponseStatus(OK)
public void updateCustomer(#RequestBody Customer customer) {
log.info("customer: " + customer.getName());
}
I set #XStreamAlias("customer") annotation in my customer domain class.
But when I try access http://localhost:8080/rest/customers/teddy.xml it always response JSON data.
I set #XmlRootElement(name="customer") annotation in my customer domain class.
But when I try access http://localhost:8080/rest/customers/teddy.json it always response XML data.
Is there some thing wrong ?
I think "xml" content type should be mapped to "text/xml" not to "application/xml". Also, to force content type resolvers based on extension, you can try to set the "favorPathExtension" property of "ContentNegotiatingViewResolver" to true(though it should have been true by default!)
EDIT: I have now added a working sample at this GIT location - git://github.com/bijukunjummen/mvc-samples.git, if you bring up the endpoint, using mvn tomcat:run, the json is served at http://localhost:8080/mvc-samples/rest/customers/teddy.json and xml at http://localhost:8080/mvc-samples/rest/customers/teddy.xml. This uses JAXB2 not XStream, as I am familiar with JAXB. One thing I noticed was that when my JAXB annotations were not correct in Customer class, Spring was serving out JSON and not XML the way you saw it(You can replicate it by removing the XMLRootElement annotation from Customer class), once I fixed up my annotations, I got back XML as expected. So it could be that there is something wrong with your XStream configuration.
EDIT 2: You are right!! I did not notice, once I got back xml, I assumed that json is working now. I see the problem, in AnnotationMethodHandlerAdapter, the handling for #ResponseBody is a little strange, it completely ignores the ViewResolvers, and uses the registered MessageConverters instead completely bypassing the ContentNegotiatingViewResolver, one workaround for now is to use #ModelAttribute annotation for response, instead of #ResponseBody, this way the view Resolvers are getting called. Try now using the project at git#github.com:bijukunjummen/mvc-samples.git and see if it works for you. This could be a Spring bug, you may try and bring it up in the Spring forum and see what they recommend.
What Accept headers are sent to your server?
Make sure the content type you would like to request is in this list.
Spring 3.1 solves the problem you mention using the new produces element on the #RequestMapping annotation. This allows you to control the HttpMessageConverter that Spring applies to your object.
I wrote a blog post about it:
http://springinpractice.com/2012/02/22/supporting-xml-and-json-web-service-endpoints-in-spring-3-1-using-responsebody/
I had the same problem. I assume you're using Spring 3 and you've used <mvc:annotation-driven/>. I'm not entirely sure, but I think this creates some conflict based on the message converters that the mvc namespace configures.
Using the oxm namespace worked for me:
#XmlRootElement(name="person")
class Person {
private String firstName;
private String lastName;
}
#Controller
#RequestMapping("person")
class PersonController {
#RequestMapping("list")
public #ResponseBody Person getPerson() {
Person p = new Person();
p.setFirstName("hello");
p.setLastName("world");
return p;
}
}
Content Configuration (mvc and internal view resolver are in another context):
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<oxm:jaxb2-marshaller id="jaxbMarshaller">
<oxm:class-to-be-bound name="package.Person" />
</oxm:jaxb2-marshaller>
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="defaultContentType" value="text/html" />
<property name="ignoreAcceptHeader" value="true" />
<property name="favorPathExtension" value="true" />
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
<property name="marshaller" ref="jaxbMarshaller" />
</bean>
</list>
</property>
</bean>
</beans>
This example uses JAXB, so you'd need jaxb-api and jaxb-impl on the classpath.
Also, just a tip, you don't need the app-servlet.xml. In your web.xml, set the config to null and let the Context Listener load them for you:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/mvc-context.xml, /WEB-INF/spring/content-negotiation-context.xml</param-value>
</context-param>
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value/>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
Well I got a solution but I don't know if it's the right way in your method show customer:
#RequestMapping(value = "/{id}", method = GET)
#ResponseBody
public Customer showCustomer(#PathVariable String id) {
Customer c = new Customer("0001", "teddy", "bean");
return c;
}
In this part, we are using MVC of spring and in the controller we should be return a view, so I removed the annotation #ResponseBody and I return a String with the name of the view because in our XML we added a ContentNegotiatingViewResolver and when we have ResponseBody the contentnegociationviewresolver is ignored because is waiting for a view but we returned the object so the method should be like that:
#RequestMapping(value = "/{id}", method = GET)
public String showCustomer(#PathVariable String id, ModelMap model) {
Customer c = new Customer("0001", "teddy", "bean");
model.addAttribute("customer",c);
return "myView";
}
well that works for me, if you have problems you can add to your app-servlet.xml
this bean, but I don't think that you have to add this.
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
I got the answers from mkyong.com
Accessing the controller using a browswer will send a typical browser Accept header. It will not match any view resolver and default to the first one (application/xml) or it matches because application/xml is in the Accept list.
I can recommend using RestClient http://code.google.com/p/rest-client/ to have complete control over what Accept header (if one at all) you want to send.
I don't recommend using text/xml as the default character set is US-ASCII and not UTF-8. This might create funky encoding problems down the road. You can always specify the encoding but appliation/xml has a UTF-8 default encoding.