I am trying out the HandlerInterceptors from Spring MVC 3.0.
Below is my interceptor
public class SessionInterceptor extends HandlerInterceptorAdapter {
#Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("inside preHandle");
if(request.getSession().getAttribute(SessionConsta nts.USER_SESSION_NAME) == null) {
response.sendRedirect("welcome");
return false;
}
return true;
}
}
Below is my configuration in my xml
<mvc:annotation-driven/>
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/services/*"/>
<bean class="com.ca.myca.interceptors.SessionInterceptor " />
</mvc:interceptor>
</mvc:interceptors>
But the interceptor is not getting called.
Please let me know if I am missing any thing.
In our application we are using double ** for any service sub-path match, so try changing it and check if it helps:
<mvc:mapping path="/services/**"/>
You are using <mvc:annotation-driven/> with mvc interceptor.
Please check on Spring reference:
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/web/servlet/DispatcherServlet.html
"When running in a Java 5+ environment, a default AnnotationMethodHandlerAdapter will be registered as well. HandlerAdapter objects can be added as beans in the application context, overriding the default HandlerAdapters. Like HandlerMappings, HandlerAdapters can be given any bean name (they are tested by type)."
<mvc:annotation-driven/> is supposed to be used for annotation-driven MVC controllers like #RequestMapping, #Controller etc, but I have seen there is no need to define "<mvc:annotation-driven/>" for supporting it.
Unless you are using jackson (for json support), you can try to remove <mvc:annotation-driven/> and use "<context:annotation-config>" instead for common use like autowiring etc.
try what is suggested in Configuration of Spring MVC and JSON using Jackson.
Put you interceptor in <mvc:interceptors> tag
<mvc:interceptors>
<bean class="xx.x..x..x...UserSessionInterceptor" />
</mvc:interceptors>
you can keep <mvc:annotation-driven/> and <context:annotation-config>
In reference to the post above by arviarya, <mvc:annotation-driven /> in the config XML results in a different handler Object being passed to the interceptor. In our interceptor method we had:
#Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mav) throws Exception {
if (mav != null && handler instanceof HandlerMethod) {
// something we want to have happen
}
This was being called with the #Controller-derived object without the <mvc:annotation-driven />, but was called with the HandlerMethod-derivedobject when it was present. For our if block to work, I needed the tag in our config XML.
Related
I want to find the best way to manage an inbound request with Spring Integration HTTP and Spring MVC.
I have an <int-http:inbound-gateway> configured as follows:
<!-- CHANNEL -->
<int:channel id="requestChannel">
<int:dispatcher task-executor="executor"/>
</int:channel>
<int:channel id="outputChannel" />
<!-- INBOUND GATEWAY -->
<int-http:inbound-gateway id="gateway" request-channel="requestChannel"
path="/service/**"
supported-methods="POST"
reply-channel="outputChannel"
header-mapper="headerMapper">
</int-http:inbound-gateway>
<!-- SERVICE ACTIVATOR -->
<int:service-activator id="channelServiceActivator"
ref="channelService"
input-channel="requestChannel"
output-channel="outputChannel"
method="manage"/>
<bean id="channelService"
class="test.spring.data.rest.xml.channel.ChannelService"/>
With this integration, every HTTP call made on the path URI: /service/** is handled in the "manage()" method of the ChannelService class.
This is the ChannelService class:
public class ChannelService {
public void manage(Message<?> message){
// how to get the HttpServletRequest request here ???
}
}
It works: the "manage()" method is correctly executed and the message contains the right payload.
But there is a little issue: I don't have any reference to the HttpServletRequest received in input in that ServiceChannel.
If I use a #Controller of Spring MVC, I can handle every request with the relative #RequestMapping.
If I want to read the payload contained in the request, I have to read it from the inputStream of the HttpServletRequest. Anywhere, I have no chance to get the message passed in the channel:
#Controller
#RequestMapping(value="/service")
public class ServiceController {
#RequestMapping(value="/**")
public handle(HttpServletRequest request) throws Exception{
// how to get the Message<?> message passed on the channel here ???
}
}
If I use both (#Controller and inbound-gateway), the #Controller mapping wins over the inbound-gateway: there is no chance to handle a servlet path URI with an inbound-gateway if there is
a #Controller that maps the same path URI.
So, I want to understand if there is some way to have a Message<?> message in the #Controller, or the HttpServletRequest in the ServiceActivator, or another way to manage this scenario.
Thanks in advance.
You can get access to the HttpServletRequest via MessageHeaders (http://docs.spring.io/spring-integration/reference/html/http.html#_uri_template_variables_and_expressions).
The HttpRequestHandlingEndpointSupport has a logic like:
evaluationContext.setVariable("requestAttributes", RequestContextHolder.currentRequestAttributes());
MultiValueMap<String, String> requestParams = this.convertParameterMap(servletRequest.getParameterMap());
evaluationContext.setVariable("requestParams", requestParams);
evaluationContext.setVariable("requestHeaders", new ServletServerHttpRequest(servletRequest).getHeaders());
So, you can configure your <int-http:inbound-gateway> with sub-elements like:
<int-http:header name="requestAttributes" expression="#requestAttributes"/>
<int-http:header name="requestParams" expression="#requestParams"/>
<int-http:header name="requestHeaders" expression="#requestHeaders"/>
<int-http:header name="matrixVariables" expression="#matrixVariables"/>
<int-http:header name="cookies" expression="#cookies"/>
The requestAttributes is an implementation of RequestAttributes. The standard one is ServletRequestAttributes, where you can find getRequest() method. And yeah, use it in the expression as well:
<int-http:header name="request" expression="#requestAttributes.request"/>
On the other hand you always can use RequestContextHolder.currentRequestAttributes() in your own code, because it is tied with ThreadLocal.
The Spring MVC knows nothing about Spring Integration, therefore there is no any Message deal with.
Anyway you can go that way too. For this purpose you should introduce #MessagingGateway and delegate a logic there from your #Controller.
I'm trying to convert a Spring project from XML to Java config and have run into the following issue with HandlerInterceptors:
XML Config (works):
<mvc:annotation-driven />
<mvc:interceptors>
<bean class="com.mycompany.MyHandlerInterceptor" />
</mvc:interceptors>
Java Config (interceptor is never called)
#Configuration
public class MvcConfig extends WebMvcConfigurationSupport {
#Override
protected void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyHandlerInterceptor());
}
// ...
}
According to the documentation, these two configurations should be equivalent, however in the Java config example the neither the pre or post handle methods are ever called?
What am I missing?
Thanks.
This was my own fault. I had overridden requestMappingHandlerMapping() in my MVC Java config and did not set the interceptors property on the custom HandlerMapping class.
#Bean
#Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {
CustomRequestHandlerMapping handlerMapping = new CustomRequestHandlerMapping();
handlerMapping.setOrder(0);
handlerMapping.setInterceptors(getInterceptors()); // <-- This was missing
return handlerMapping;
}
I'm starting a new project with Spring 3.1, and have been eyeball deep in all the documentation and forum opinions about how to use the #Controller annotation.
I personally dislike using annotations for MVC; I much prefer having all the URLs of a webapp available in one place, using SimpleUrlHandlerMapping.
Also, from much previous work using Spring 2.x, I'm very used to the BaseCommandController heirarchy.
I've always loved Spring because it's empowering without being restricting. Now I find Spring MVC is forcing me to put URLs into the java source, meaning (a) I can't map a controller to several URLs, and (b) to discover what URLs are in use in a webapp, I have to scan through different java source files, which I find impractical.
What is the recommended way of combining #Controller with SimpleUrlHandlerMapping, please ?
Update:
Hi Dave, are you saying you can map multiple URLs like this (altered from petclini.web.ClinicController)?
#RequestMapping({"/vets", "/another"})
public ModelMap vetsHandler() {
If this works then good.
My question still stands though:
If I don't want URLs in my java source, how best to map them with #Controller classes?
Regards,
Here is a simple set up to support annotation and non-annotated controllers.
Dispatcher servlet configuration xml
<mvc:annotation-driven/>
<bean id="testController" class="com.test.web.TestController"/>
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<value>
/test=testController
</value>
</property>
<property name="order" value="0"/>
</bean>
A simple URL mapped controller
public class TestController implements Controller {
#Override
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
PrintWriter responseWriter = response.getWriter();
responseWriter.write("test");
responseWriter.flush();
responseWriter.close();
return null;
}
}
The controller for mvc annotation-config
#Controller
#RequestMapping("/home")
public class HomeController {
#RequestMapping(method = RequestMethod.GET)
#ResponseBody
public String dashboard(Model model, HttpServletRequest request) {
return "home";
}
}
If you want to use your own handlers for #Controller annotation. you can probably look into ClassPathBeanDefinitionScanner and DefaultAnnotationHandlerMapping.determineUrlsForHandlerMethods.
I've been working on adding aspects to a Spring MVC webapp, and the aspects aren't executing. I've tried to boil it down to something dirt simple that clearly should work, but still no go. Here's where I'm at now:
// imports...
#Aspect
public class AuthCheckerAspect {
{
System.out.println("initting");
}
#Pointcut("execution(* * *(..))")
public void c() {}
#Before("c")
public void cc(JoinPoint pjp) throws Throwable {
System.out.println("test...");
}
}
As far as I can tell, the pointcut should apply to any method in any Spring-managed class (of which there are a lot in my application). I also added the following to my Spring config:
<aop:aspectj-autoproxy/>
I set a breakpoint at the System.out.println() statement in the cc() method, but it never caught (and yes, I'm positive that the debugger is attached; other breakpoints catch properly). I'm suspecting that the AuthCheckerAspect class is never getting loaded into the Spring context, because I also set a breakpoint within the initializer clause, and that never catches either; when I do the same with other Spring-managed classes, their breakpoints always catch during app startup.
Is there something else I need to be doing?
Thanks in advance.
Spring does not automatically mange #Aspects. Add <bean class="AuthCheckerAspect" /> to your context or annotate it with #Component and include in component scan path.
add this to your configuration file:
<context:annotation-config />
<context:component-scan base-package="root.package.to.be.scanned" />
<aop:aspectj-autoproxy>
<aop:include name="nameOfAspectBean" />
</aop:aspectj-autoproxy>
I'm using Spring MVC with Freemarker as view technologie. I have a TemplateDirectiveModel object which needs to access Spring's RequestContext within the execute method. Currently I do it like this:
public class MyDirective implements TemplateDirectiveModel
{
public void execute(Environment env, Map params, TemplateModel[] loopVars,
TemplateDirectiveBody body) throws TemplateException, IOException
{
StringModel model = (StringModel) env.getGlobalVariable("springMacroRequestContext");
RequestContext requestContext = (RequestContext) model.getWrappedObject();
}
}
But I can't believe that this is the right way to do it. I have the feeling I missed something important. Maybe there are special classes and annotations for handling Freemarker direcives in Spring? Maybe I can let Spring inject something into the directive class with which I can access Springs request scope?
You could subclass FreeMarkerConfigurer, overriding its postProcessConfiguration(Configuration config)method.
Your implementation would just put a request-aware dependency in the configuration, as a shared variable for example (as preconised by the FM documentation).
Should do the trick, Spring-style...
There is an easier way to do this. If you are already using spring's FreeMarkerConfigurer, you can hand it a map of variables:
<bean id="freemarkerConfig" class="org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer"
p:templateLoaderPath="/some_path_here">
<property name="freemarkerVariables">
<map>
<entry key='macroName' value-ref="templateModelRef" />
</map>
</property>
</bean>
<bean id="templateModelRef" class="...class..extends TemplateModel">
<property name="someResource" value-ref="resourceRef"/>
</bean>
Now at least in a class that extends TemplateDirectiveModel's execute method you have access to that injected property.
public class MyDirective extends TemplateDirectiveModel {
private MyResource someResource;
#Override
public void execute(Environment env, Map params, TemplateModel[] loopVars,TemplateDirectiveBody body) throws TemplateException, IOException {
StringModel sharedVariable = (StringModel)env.getConfiguration().getSharedVariable("beanName");
MyClass sweetness = (MyClass)sharedVariable.getWrappedObject();
}
}
Now in your .ftl you can use:
<#macroName />
and it will have spring dependencies auto injected.