URL mapping problems using Spring MVC - spring-mvc

I have a very basic setup which I am trying to get working.
web.xml
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/site/*</url-pattern>
</servlet-mapping>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-dispatcher-servlet.xml</param-value>
</context-param>
mvc-dispatcher-servlet.xml
<context:component-scan base-package="com.blabla.controller" />
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
p:prefix="/WEB-INF/pages/" p:suffix=".jsp"
p:viewClass="org.springframework.web.servlet.view.JstlView" />
In the controller
#Controller
#RequestMapping(value = "/site")
public class SearchController {
#RequestMapping(value = "welcome", method = RequestMethod.GET)
public String test() {
return "test";
}
This is the problem that I have:
I would like to write /site/* as url-pattern in my web.xml, but when I do that I get
WARNING: No mapping found for HTTP request with URI [/site/welcome] in DispatcherServlet with name 'mvc-dispatcher'
When I write /site/welcome in full, everything works, but I dont want this because I dont want to add every page manually to the web.xml
And when I write "/*" as url-pattern i get the error message:
WARNING: No mapping found for HTTP request with URI [/WEB-INF/pages/test.jsp] in DispatcherServlet with name 'mvc-dispatcher'
which I guess makes sense because the the location of the jsp is included in the pattern.
So how do you do it: how can you be sufficiently vague in your url pattern without the problems I just had?

Related

URL pattern servlet mapping

I created hello world example using Spring MVC, but there is one thing I didn't understand in servlet URL mapping, I did the following in web.xml:
<servlet>
<servlet-name>HelloWeb</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWeb</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
now if I want to call the following controller:
#Controller
#RequestMapping("/hello")
public class HelloWorld {
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model){
model.addAttribute("message","hello world");
return "index";
}
}
it will work using the following link:
http://localhost:8080/test/hello
but when I change the servlet url-pattern to "/*" and try:
http://localhost:8080/hello
it doesn't work, shouldn't it match my servlet ? as * matches everything
When you register a servlet with "/*" then it will override all the servlet mappings if there are any. Hence it should be avoided. This overrides default servlet mapping as well hence all default url handling also overridden and hence any specific url matching fails. In your case it is /hello.
With your case, initially you registered with /test/* this registered all your URL's with /test and hence they got identified.
It doesn't work for /* because, you have not registered/created a controller for that pattern.
It worked for http://localhost:8080/hello because, you have controller #RequestMapping("/hello")
Just change the RequestMapping to #RequestMapping("/") for url-pattern /*

How to read spring-application-context.xml and AnnotationConfigWebApplicationContext both in spring mvc

In case I want to read bean definitions from spring-application-context.xml, I would do this in web.xml file.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml
</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
In case I want to read bean definitions through Java Configuration Class (AnnotationConfigWebApplicationContext), I would do this in web.xml
<servlet>
<servlet-name>appServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
org.package.MyConfigAnnotatedClass
</param-value>
</init-param>
</servlet>
How do I use both in my application. like reading beans from both configuration xml file and annotated class.
Is there a way to load spring beans in xml file while we are using AppConfigAnnotatedClass to instantiate/use rest of the beans.
This didnt work
Xml file defines bean as
<bean name="mybean" class="org.somepackage.MyBean"/>
Java Class Imports Resources as
#ImportResource(value = {"classpath:some-other-context.xml"})
#Configuration
public class MyConfigAnnotatedClass {
#Inject
MyBean mybean;
}
But mybean value is always null which ofcourse will give nullpointerexception when calling method on mybean.
You can annotate your #Configuration class with
#ImportResource(value = {"classpath:some-other-context.xml"})
#Configuration
public class MyConfigAnnotatedClass {
...
}
to have it import <beans> type xml contexts.
You can do the same thing the other way around. Your #Configuration class is also a #Component. If you have a <component-scan> that includes its package, all its declared beans will be added to the context. Alternatively, you can do
<bean name="myAdditionalConfig" class="org.somepackage.MyConfigAnnotatedClass" />
Note that package cannot be used as a name in the package structure.

spring 3 uploadify giving 404 Error

I am using Spring 3 and implementing Uploadify. The problem is, the files are updating properly but it is giving HTTP Error 404, on completion of file upload. I tried every possible solution, but none of them works.
The files are uploaded. Values are storing in DB properly, only that i am getting HTTP Error 404. Any help is appreciated and Thanks in advance.
The Solution is :
Finally i found the solution but it is lame.
I removed the return "" and changed the method as void. Thats it.
But still i don't understand why the same code is working in Spring 2.5.6 and not in 3.
The URL of the screenshot : http://imgur.com/bf3qo
The JSP Page
$(function() {
$('#file_upload').uploadify({
'swf' : 'scripts/uploadify.swf',
'fileObjName' : 'the_file',
'fileTypeExts' : '*.gif; *.jpg; *.jpeg; *.png',
'multi' : true,
'uploader' : '/photo/savePhoto',
'fileSizeLimit' : '10MB',
'uploadLimit' : 50,
'onUploadStart' : function(file) {
$('#file_upload').uploadify('settings', 'formData', {'trip_id' :'1', 'trip_name' :'Sample Trip', 'destination_trip' :'Mumbai','user_id' :'1','email' :'s#s.com','city_id' :'12'});
},
'onQueueComplete' : function(queueData) {
console.log('queueData : '+queueData);
window.location.href = "trip/details/1";
}
});
});
The Controller
#RequestMapping(value="photo/{action}", method=RequestMethod.POST)
public String postHandler(#PathVariable("action") String action, HttpServletRequest request) {
if(action.equals("savePhoto"))
{
try{
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest)request;
MultipartFile file = multipartRequest.getFile("the_file");
String trip_id = request.getParameter("trip_id");
String trip_name = request.getParameter("trip_name");
String destination_trip = request.getParameter("destination_trip");
String user_id = request.getParameter("user_id");
String email = request.getParameter("email");
String city_id = request.getParameter("city_id");
photo.savePhoto(file,trip_id,trip_name,destination_trip,user_id,email,city_id);
photo.updatetrip(photo_id,trip_id);
}catch(Exception e ){e.printStackTrace();}
}
return "";
} **Solution** : Change the method return type as void and remove the return
spring config
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
<property name="maxUploadSize" value="10000000"/>
</bean>
Web.xml is
<?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" id="WebApp_ID" version="2.5">
<display-name>project_name</display-name>
<distributable/>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/project_name-servlet.xml,/WEB-INF/applicationContext-jdbc.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>project_name</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>project_name</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<session-config>
<session-timeout>60</session-timeout>
</session-config>
</web-app>
maybe you simply haven't page trip/details/1 in your application?
EDIT:
Change window.location.href = "trip/details/1"; to
window.location.href = "<%= request.getContextPath() %>/trip/details/1";
The files are uploaded. Values are storing in DB properly, only that i
am getting HTTP Error 404.
What this tells me is that your request is properly being submitted to the URL at '/photo/*'
and is properly handled by the postHandler() method.
You're getting a 404 because your web application doesn't know what to do with the url of "" that the postHandler() method is trying to direct you to.
There is most likely (and I'm making some assumptions here, it'd be helpful if you included the web.xml) a request mapper not set up to handle the " " that your controller is returning; make your controller return some sort of meaningful view name that has a valid servlet mapping and you will not get a 404.
I had this problem too. I added "#ResponseBody" and got the right result.
I think the problem is that without the annotation "#ResponseBody", the returned string is handled by some strange resolver and javascript code gets response of unexpected form.
#RequestMapping(value="/uploadFile",method=RequestMethod.POST)
public #ResponseBody String upload(HttpServletResponse response,
HttpServletRequest request) throws IOException{

#Autowire is not working in Spring security Custom Authentication provider

We have Spring MVC application. We are trying to integrate the Spring security in it.
We have written our custom authentication provider which will do the work of authentication.
Below is the code for my custom authentication provider.
public class CustomAuthenticationProvider extends DaoAuthenticationProvider {
#Autowired
private AuthenticationService authenticationService;
#Override
public Authentication authenticate(Authentication authentication) {
CustomAuthenticationToken auth = (CustomAuthenticationToken) authentication;
String username = String.valueOf(auth.getPrincipal());
String password = String.valueOf(auth.getCredentials());
try {
Users user = new User();
user.setUsername(username);
user.setPassword(PasswordUtil.encrypt(password));
user = authenticationService.validateLogin(user);
return auth;
} catch (Exception e) {
throw new BadCredentialsException("Username/Password does not match for " + username);
}
}
#Override
public boolean supports(Class<? extends Object> authentication) {
return (CustomAuthenticationToken.class.isAssignableFrom(authentication));
}
}
Here i am getting NullpointerException on the following line
user = authenticationService.validateLogin(user);
The authenticationService is not getting autowired in the custom authentication provider. While the same service authenticationService is autowired in the same way in my MVC controller.
Is this because authentication provider is a Spring security component?
Below is a my web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring/myApp-security.xml
</param-value>
</context-param>
<servlet>
<servlet-name>myApp</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/spring/myApp-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>myApp</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<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>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
Edit 1 :-
I have added the following lines in my spring security configuration file.
<beans:bean id="customAuthenticationProvider" class="com.myApp.security.provider.CustomAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
Please help how to autowire my service classes in the Spring security components?
Are you using the <debug/> element? If so, try removing to see if it fixes your problem as SEC-1885 prevents #Autowired from working when using <debug/>.
Perhaps autowiring postprocessor is not enabled in the root application context (but enabled in the DispatcherServlet's context as a side effect of <mvc:annotation-driven> or <context:component-scan>).
You can enable it by adding <context:annotation-config> to myApp-security.xml.
I experienced this issue and came to the conclusion that while autowiring was taking place, the spring security was operating with a completely different instance of the classes. To solve this I imported the security configuration into the spring mvc configuration as below.
This allowed Spring security to share the context with my spring mvc.
<import resource="myapp-security.xml" />
I faced the same issue and fixed it.
The solution is even if u have #Autowired annotation set for Service class.
#Autowired
private AuthenticationService authenticationService;
Removed the bean definition in your dispatcher-servlet.xml and it will work.
<!--
<beans:bean id="customAuthenticationProvider" class="com.myApp.security.provider.CustomAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
-->
and add it in security context file
if you are using Spring MVC then you have to add both spring-security.xml and dispatcher-servlet.xml in contextConfigLocation.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-security.xml
/WEB-INF/dispatcher-servlet.xml
</param-value>
</context-param>
you need to define your CustomAuthenticationProvider as a spring bean (in applicationContext.xml generally or applicationContext-security.xml if you have one)
You should use
You cannot use because your myApp-security.xml is creating another ApplicationContext which doesnt see all the autowiring from your context created by myApp-servlet.xml

Rest easy and init params - how to access?

I'd like to have some init params in my web.xml and retrieve them later in the application, I know I can do this when I have a normal servlet. However with resteasy I configure HttpServletDispatcher to be my default servlet so I'm not quite sure how I can access this from my rest resource. This might be completely simple or I might need to use a different approach, either way it would be good to know what you guys think. Following is my web.xml,
<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" id="WebApp_ID" version="2.5">
<display-name>RestEasy sample Web Application</display-name>
<!-- <context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param> -->
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>
org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher
</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.pravin.sample.YoWorldApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
My question is how do I set something in the init-param and then retrieve it later in a restful resource. Any hints would be appreciated. Thanks guys!
Use the #Context annotation to inject whatever you want into your method:
#GET
public Response getWhatever(#Context ServletContext servletContext) {
String myParm = servletContext.getInitParameter("parmName");
}
With #Context you can inject HttpHeaders, UriInfo, Request, HttpServletRequest, HttpServletResponse, ServletConvig, ServletContext, SecurityContext.
Or anything else if you use this code:
public class MyApplication extends Application {
public MyApplication(#Context Dispatcher dispatcher) {
MyClass myInstance = new MyClass();
dispatcher.getDefautlContextObjects().
put(MyClass.class, myInstance);
}
}
#GET
public Response getWhatever(#Context MyClass myInstance) {
myInstance.doWhatever();
}

Resources