Spring MVC Handler Interceptor does not run - java

I have following interceptor class :
package cz.coffeeexperts.feedback.server.web.interceptors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class RestAuthorizationInterceptor extends HandlerInterceptorAdapter {
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler)
throws Exception {
System.out.println("fuu");
response.setStatus( HttpServletResponse.SC_UNAUTHORIZED );
return false;
}
}
I configured it inside my spring-webmvc.xml as following :
<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"
xsi:schemaLocation="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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<mvc:annotation-driven/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/rest/api/01/status" />
<bean class="cz.coffeeexperts.feedback.server.web.interceptors.RestAuthorizationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
However when I go to http://localhost:8080/myserver/rest/api/01/status, I get regular answer with status code 200 (same as before I added interceptor). Also, message "fuu" is not printed (so the preHandle method is not called).
Any ideas? I started to do it with this example : http://javapapers.com/spring/spring-mvc-handler-interceptor/, but all other examples look the same, I cant find where I go wrong.
I am using Spring 3.2.4.RELEASE
Important edit, it works with this :
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="cz.coffeeexperts.feedback.server.web.interceptors.RestAuthorizationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
So the question is, what is wrong with my path?

Ok, I found solution, because my path is defined with following :
<servlet-mapping>
<servlet-name>rest</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
And this is how my controller looks like
#Controller
#RequestMapping(value = "/api")
public class ApiController {
#RequestMapping(value = "/01/status", method = RequestMethod.GET)
#ResponseBody
public ServerStatusJSON getStatus(HttpServletResponse response) {
...
}
}
The working configuration for this address : http://localhost:8080/myserver/rest/api/01/status is as following :
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/api/01/status" />
<bean class="cz.coffeeexperts.feedback.server.web.interceptors.RestAuthorizationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
PS : My thanks to geoand, he pushed me to the right way.

I solved this problem by changing the value of mvc:mapping. My working configuration is:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="cn.mmd.micro.common.TokenInterceptor">
<property name="excludeUrls">
<list>
<value>/app/token</value>
</list>
</property>
</bean>
</mvc:interceptor>
</mvc:interceptors>

Providing additional explanation as to why this method worked for libik. As he has mentioned his controller looks like -
#Controller
#RequestMapping(value = "/api")
public class ApiController {
#RequestMapping(value = "/01/status", method = RequestMethod.GET)
#ResponseBody
public ServerStatusJSON getStatus(HttpServletResponse response) {
...
}
}
And also remember interceptors are at HandlerMapping level. In this case it would be RequestMappingHandlerMapping (Spring 3.1+ with mvc:annotation-driven) or DefaultAnnotationHandlerMapping. and the mapping here would be for
/api/01/status which is precisely what he has done.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/api/01/status" />
<bean class="cz.coffeeexperts.feedback.server.web.interceptors.RestAuthorizationInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
If you want it to be applied for all patterns you can simply do <mvc:mapping path="/**"/> - this will match all URLs (including subpaths) or you can simply invoke interceptors for all HandlerMappings -
<mvc:interceptors>
<bean class="cz.coffeeexperts.feedback.server.web.interceptors.RestAuthorizationInterc‌​eptor" />
</mvc:interceptors>

Related

Spring controller not created

There is a small Struts application and I am trying to enable Spring-mvc on it. It's already using Spring to handle the DB transactions. I have two questions:
Component scan will not pick up my controllers if I try to add a new base package.
If I place my controllers in an existing base package, I can see them created in Spring application context. But then the request mapping still does not work.
Here are my relevant code snippets:
web.xml:
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>*.site</url-pattern>
</servlet-mapping>
Here is 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"
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/mvc http://www.springframework.org/schema/mvc/spring-mvc-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/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<mvc:annotation-driven />
<context:component-scan base-package="com.mycom.eps.test, com.mycom.epsadmin"/>
<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/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="exceptionHandler" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="defaultErrorView" value="error"/>
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">error</prop>
<prop key="org.hibernate.exception.GenericJDBCException">jdbcerror</prop>
</props>
</property>
</bean>
</beans>
Here's part of ApplicationContext.xml:
<context:annotation-config />
<context:component-scan base-package="com.mycom.eps, com.mycom.tiff" />
<tx:annotation-driven proxy-target-class="true" />
I've got two Controllers:
package com.mycom.eps.test;
// import statements
#Controller
public class TestController {
#RequestMapping(value="/test", method={RequestMethod.GET, RequestMethod.POST})
public ModelAndView test(HttpServletRequest request, HttpServletResponse response) throws EpsException {
Map<String, Object> modelMap = new HashMap<String, Object>();
return new ModelAndView("/details", modelMap);
}
}
Another controller:
//This is a new package I am trying to create
package com.mycom.epsadmin.controller;
// import statements
#Controller
public class PackageController {
#RequestMapping(value="/sendPackage", method={RequestMethod.GET, RequestMethod.POST})
public ModelAndView sendPackage(HttpServletRequest request, HttpServletResponse response) throws EpsException {
Map<String, Object> modelMap = new HashMap<String, Object>();
return new ModelAndView("/details", modelMap);
}
}
My first question is, why is the com.mycom.epsadmin.controller.PackageController never created in web application context (I inspected the spring log and couldn't find it)?
While trying to figure out about my first question, I created another controller com.mycom.eps.test.TestController (hence the name of the controller). While this one does get created in the Web application context, the request is never intercepted (404 error).
Here's how I am trying to call it:
$.ajax({
type: "POST",
url: "test.site",
cache: false
});
When I try to go to the page through browser http://http://localhost:8080/mycom/test.site, I am getting 404 error as well.
Sorry for the lengthy post! But can someone kindly point me in the right direction? Thanks a bunch!
UPDATE:
Just found out that the test controller is actually picking up the request (really sorry about that)! So my second question is moot.
Try after adding com.mycom.epsadmin in the ApplicationContext
<context:component-scan base-package="com.mycom.epsadmin, com.mycom.eps, com.mycom.tiff" />

Integrate Spring Socials (Facebook) with Spring MVC XML Based

I have a working spring mvc webapp and it is xml based so i have to use the same procedures and not "pure java configs".
I'm trying to integrate facebook sign in to my app and i have tried to follow many tutorials but couldn't manage to make them work.
Here is one of my tries: (https://spring.io/guides/gs/accessing-facebook/)
EDIT:
My XML is now this:
<?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:facebook="http://www.springframework.org/schema/social/facebook"
xmlns:twitter="http://www.springframework.org/schema/social/twitter"
xmlns:social="http://www.springframework.org/schema/social"
xmlns:linkedin="http://www.springframework.org/schema/social/linkedin"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/social/facebook http://www.springframework.org/schema/social/spring-social-facebook.xsd
http://www.springframework.org/schema/social/linkedin http://www.springframework.org/schema/social/spring-social-linkedin.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/social/twitter http://www.springframework.org/schema/social/spring-social-twitter.xsd
http://www.springframework.org/schema/social http://www.springframework.org/schema/social/spring-social.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd">
<bean id="connectionFactoryLocator"
class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
<property name="connectionFactories">
<list>
<bean class="org.springframework.social.facebook.connect.FacebookConnectionFactory">
<constructor-arg value="${facebook.clientId}" />
<constructor-arg value="${facebook.clientSecret}" />
</bean>
</list>
</property>
</bean>
<bean id="usersConnectionRepository"
class="org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository">
<constructor-arg ref="dataSource" />
<constructor-arg ref="connectionFactoryLocator" />
<constructor-arg ref="textEncryptor" />
</bean>
<bean id="connectionRepository" factory-method="createConnectionRepository"
factory-bean="usersConnectionRepository" scope="request">
<constructor-arg value="#{request.userPrincipal.name}" />
<aop:scoped-proxy proxy-target-class="false" />
</bean>
<bean class="org.springframework.social.connect.web.ConnectController">
<!-- relies on by-type autowiring for the constructor-args -->
</bean>
<bean class="org.springframework.social.connect.web.ConnectController">
<!-- relies on by-type autowiring for the constructor-args -->
<property name="applicationUrl" value="${application.url}" />
</bean>
<facebook:config app-id="962223610477458" app-secret="b7dfec28b08ac4e8c2a09cbac4662c15" app-namespace="setelog_selectandwin" />
</beans>
HomeController:
#Controller
public class HomeController {
private static final Logger logger = LoggerFactory.getLogger(HomeController.class);
private Facebook facebook;
private ConnectionRepository connectionRepository;
#Inject
public HomeController(Facebook facebook, ConnectionRepository connectionRepository) {
this.facebook = facebook;
this.connectionRepository = connectionRepository;
}
/**
* Simply selects the home view to render by returning its name.
*/
#RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
if (connectionRepository.findPrimaryConnection(Facebook.class) == null) {
return "redirect:/connect/facebook";
}
model.addAttribute("facebookProfile", facebook.userOperations().getUserProfile());
PagedList<Post> feed = facebook.feedOperations().getFeed();
model.addAttribute("feed", feed);
return "facebook/hello";
}
}
NOW the error is
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'scopedTarget.connectionFactoryLocator' is defined
If I remove th facebook:config tag it gives me the following error because there is no such bean:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [org.springframework.social.facebook.api.Facebook] found for dependency: expected at least 1 bean which
Any suggestions?
You need not add spring's facebook interface as class in your xml. Instead create FacebookConnectionFactory using your facebook client id and secret using xml or java code.
#Configuration
public class SocialConfig implements SocialConfigurer {
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer cfConfig, Environment env) {
cfConfig.addConnectionFactory(new FacebookConnectionFactory(
env.getProperty("facebook.clientId"),
env.getProperty("facebook.clientSecret")));
}
...
}
or
Using Spring Social Facebook’s XML configuration namespace:
<facebook:config app-id="${facebook.clientId}"
app-secret="${facebook.clientSecret}"
app-namespace="socialshowcase" />
Refer : Spring Social Facebook Reference
taken from spring social quickstart example. Probably you cant inject it by yourself, instead you have to use factory-like method:
#Bean
#Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
public Facebook facebook() {
return connectionRepository().getPrimaryConnection(Facebook.class).getApi();
}
it needs other dependencies, no point to copy-paste them all here. Take a look at: https://github.com/spring-projects/spring-social-samples/blob/master/spring-social-quickstart/src/main/java/org/springframework/social/quickstart/config/SocialConfig.java

Can Controllers specify which Interceptors to use

I'm moving an existing spring (3.1.1) web mvc Controller (called LoginController) to using annotations, I had
<bean id="loginHandlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="licenseInterceptor" />
<ref bean="propertyInterceptor" />
<ref bean="localeChangeInterceptor" />
</list>
</property>
<property name="urlMap">
<map>
<!-- used to include references to my LoginController -->
<entry key="error" value-ref="error" />
</map>
</property>
<property name="order">
<value>1</value>
</property>
</bean>
I changed my LoginController to be annotated. Some other classes had also been annotated previously so it will use the existing...
<bean id="requestMappingHandlerMapping"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<property name="interceptors">
<list>
<ref bean="licenseInterceptor" />
<ref bean="loginInterceptor" />
<ref bean="propertyInterceptor" />
</list>
</property>
</bean>
LoginController cannot use the loginInterceptor that others use however as it's a pre-login Controller but a post-login Interceptor.
What I want to know, is there a way to tell Spring that this specific Controller should NOT be used with a specific (loginInterceptor) Interceptor? And perhaps if it (and only it) could also use localeChangeInterceptor.
What have I tried
(works in Spring 3.2) Adding <mvc:interceptors> and their namespace to config but they don't seem to allow multiple bean references and exclude-mapping is Spring 3.2, I'm 3.1.1
Doing the processing in LoginInterceptor, handler is not of type LoginController - I can do ((HandlerMethod)handler).getBean() instanceof LoginController and that works but it's not pretty or flexible.
using the spring mvcnamespace you could do the following:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/login"/>
<ref bean="loginInterceptor"/>
</mvc:interceptor>
<!-- .. further interceptors -->
</mvc:interceptors>
this allows to add paths that should not be intercepted by a specific interceptor.
add the mvc namespaces to your configuration root element..
xmlns:mvc="http://www.springframework.org/schema/mvc"
... and the schema ...
xsi:schemaLocation=" .....
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
...."
I've done this in the past by implementing it in the preHandle method in a HandlerInterceptorAdapter.
#Override
public final boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// inspect handler object to see if it's LoginController
}
Here is what it took to get this working in the LoginController. A little like the solution of #blank but with some other nonsence, I'd still like to have a spring (annotation or config) way of fixing this though
public final boolean preHandle(HttpServletRequest request)
{
if (handler instanceof HandlerMethod &&
((HandlerMethod)handler).getBean() instanceof LoginController)
{
return true;
}
...
}

Configuring Spring MVC to map GET requests to one method in a controller and OPTIONS requests to another method

This would be pretty easy using annotations:
#Controller
public class MyController {
#RequestMapping(value="/hitmycontroller", method= RequestMethod.OPTIONS)
public static void options(HttpServletRequest req,HttpServletResponse resp){
//Do options
}
#RequestMapping(value="/hitmycontroller", method= RequestMethod.GET)
public static void get(HttpServletRequest req,HttpServletResponse resp){
//Do get
}
}
but I can't find how to do this in XML. Is there some mapping handler that will do something like this:
<bean id="handlerMapping"
class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<mapping>
<url>/hitmycontroller</url>
<httpMethod>GET</httpMethod>
<method>get</method>
<controller>MyController</controller>
</mapping>
<mapping>
<url>/hitmycontroller</url>
<httpMethod>OPTIONS</httpMethod>
<method>options</method>
<controller>MyController</controller>
</mapping>
</property>
</bean>
Any pointers would be appreciated.
With the SimpleUrlHandlerMapping it is not possible specify the http method. Probably you have to use other mapping like the MethodUrlHandlerMapping in the Spring MVC REST project (http://spring-mvc-rest.sourceforge.net/).
The way to declare the mappings using the MethodUrlHandlerMapping should be something like this:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="GET /hitmycontroller">MyController</prop>
<prop key="OPTIONS /hitmycontroller">MyController</prop>
</props>
</property>
</bean>
You can see the example in their page:
http://spring-mvc-rest.sourceforge.net/introduction.html
Look at the part 2.
Your #RequestMapping annotations should work. Just delete the handlerMapping bean from your xml configuration and enable MVC annotations.
Here is a sample configuration. Change base-package to the package that contain your controller classes
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<context:component-scan base-package="your.package" />
<mvc:annotation-driven>
</beans>

Converting XML Spring config for JMX to Java config

I have a small test app for exposing a "Bean" to JMX using Spring. It uses an XML based config and everything works fine:
<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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<context:component-scan base-package="com.dmclaughlin.spring" />
<context:property-placeholder location="classpath:test.properties"/>
<bean id="SimpleJmxController" class="com.dmclaughlin.spring.jmx.SimpleJmxBean">
<property name="activated" value="${some.activated}"/>
</bean>
<!-- Spring JMX -->
<bean id="exporter" class="org.springframework.jmx.export.MBeanExporter" lazy-init="false">
<property name="autodetect" value="true"></property>
<property name="namingStrategy" ref="namingStrategy"></property>
<property name="assembler" ref="assembler"></property>
</bean>
<bean id="attributeSource"
class="org.springframework.jmx.export.annotation.AnnotationJmxAttributeSource"/>
<bean id="assembler"
class="org.springframework.jmx.export.assembler.MetadataMBeanInfoAssembler">
<property name="attributeSource" ref="attributeSource"/>
</bean>
<bean id="namingStrategy"
class="org.springframework.jmx.export.naming.MetadataNamingStrategy">
<property name="attributeSource" ref="attributeSource"/>
</bean>
But the application I need to add this functionality to, uses #Configuration style, and I'm trying to convert the above XML to work. I added something like this:
#Bean
public MetadataNamingStrategy getNamingStrategy() {
MetadataNamingStrategy strategy = new MetadataNamingStrategy();
strategy.setAttributeSource(new AnnotationJmxAttributeSource());
return strategy;
}
#Bean
public MetadataMBeanInfoAssembler getMbeanInfoAssembler() {
return new MetadataMBeanInfoAssembler(new AnnotationJmxAttributeSource());
}
#Bean
public MBeanExporter getExporter() {
MBeanExporter exporter = new MBeanExporter();
exporter.setAutodetect(true);
exporter.setNamingStrategy(getNamingStrategy());
exporter.setAssembler(getMbeanInfoAssembler());
return exporter;
}
And everything compiles, but when I load up JConsole my Bean annotated with #ManagedResource and #ManagedAttribute isn't exposed. Am I missing something simple here?
Edit: the answer below didn't fix my problem (the problem was I was testing my XML in a Tomcat environment, but testing my non-XML config in a standalone application, which meant there was no JMXServer present.. d'oh), but it did help me simplify once I debugged what I messed up.
For me it was enough to add:
#Bean
public AnnotationMBeanExporter annotationMBeanExporter() {
return new AnnotationMBeanExporter();
}
you should configure your mbeanexporter with "eager"
#Bean
#Lazy(false)
public MBeanExporter getExporter() {
...
}
greetings
AccLess

Categories