Spring MVC Interceptor Mapping Problems - java

I have this segment of XML:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/statics/**" />
<bean class="com.company.website.servlet.StaticsHandlerInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/data/**" />
<bean class="com.company.website.servlet.AJAXHandlerInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**" />
<bean class="com.company.website.servlet.PageHandlerInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
I have three different interceptors for a reason, though the StaticsHandlerInterceptor is just the preHandle method returning true (for all of my static content (js, css, etc)). The second one is for AJAX requests. The third one is for actual pages. What I see happening is the statics and the AJAX interceptors being called when they are supposed to be; however, with them, the page interceptor is always being called. I only want the page interceptor to be called for pages. How do I make that happen?

Assuming you use a consistent naming scheme for your pages, use that - e.g. if your externally-visible page URLs end with .html, specify:
<mvc:mapping path="/**/*.html" />
It's not very RESTful to have "extensions" like that though - you might prefer to use a scheme like:
GET of /user/{id} = returns User object for user {id}, JSON format
POST to /user/{id} = updates User object from JSON object
GET to /user/page/{id} = returns HTML page for user {id}
etc etc
Then you can use a nice readable, semantic mapping like:
<mvc:mapping path="/**/page/**" />
which will work to any "depth" of URL structure.
Edit: OK so it seems that using the mvc:interceptors style of bean declaration isn't going to give you the expressiveness you need to specify exclusion by pattern rather than inclusion.
From what I can make out in this blog, using the more-verbose HandlerMapping approach will allow you to invert the match logic - you can specify what not to match on to get what you need:
<bean id="nonStaticNonDataMapper" class="org.springplugins.web.IgnoreSelectedAnnotationHandlerMapping">
<property name="order">
<value>0</value>
</property>
<property name="urls">
<list>
<value>/statics/**</value>
<value>/data/**</value>
</list>
</property>
<property name="interceptors">
<list>
<bean class="com.company.website.servlet.PageHandlerInterceptor" />
</list>
</property>
(Apologies for the formatting of the above snippet, Markdown thinks the /** is a comment :-)

mvc:interceptors now supports excluding a particular mapping. Currently it's only available in Spring 3.2.0.M2. You can find more about it at the JIRA item (that is now resolved): https://jira.springsource.org/browse/SPR-6570

Related

Save Spring XML Configuration

Forgive me if this has been answered before ...
I want to load a spring configuration xml file from disk, have the user modify settings, then save the modifications back to the xml file, for initialization during a subsequent run of the application.
For instance, say a class has a collection of classes, each with their own bean configurations. Through the UI, the user may reconfigure any of the sub-classes and/or add/remove any sub-classes from the collection.
Example application-context.xml:
<beans>
<bean id="mainClass" class="...">
<property name="subClassList">
<list>
<ref bean="subClassA" />
<ref bean="subClassB" />
</list>
</property>
</bean>
<bean id="subClassA" class="...">
<property name="var1" value="1" />
</bean>
<bean id="subClassB" class="...">
<property name="var2" value="100" />
</bean>
</beans>
So, not only do I want to allow the user to modify var1 & var2 in the application and save the configuration, but the user could remove subClassB from the list or add subClassC to the list, within the application, then save the configuration.
Also, the application is a desktop app, not web-based. In addition, "mainClass" is not the class that contains the application entry point, "main()". Think of "mainClass" as a container, with a collection of other classes, each of which has a "process()". So, the parent class, mainClass, iterates through each subClass, runs process(), then evaluates what the overall result will be. Adding subclasses and modifying subClass parameters, then saving the configuration is the goal.
Thanks in advance,
Eric

Spring 4.3.3 - ParameterizableViewController POST method not more supported

After upgrading to Spring 4.3.3.RELEASE i get the error:
Request method 'POST' not supported
My application is a basic template and the home view is rendered via
<mvc:view-controller path="/" view-name="home.view"/>
It works fine on Spring 4.2.8.
Any hint to solve the problem?
We ran into the same problem. It turns out that, at some point, the ParameterizableViewController was changed to only support GET and HEAD requests.
We resolved this by replacing the definition with something like this:
<bean id="homeController" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="supportedMethods" value="GET,POST,PUT,DELETE" />
<property name="viewName" value="home.view" />
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<map>
<entry key="/" value-ref="homeController"/>
</map>
</property>
</bean>
Essentially, this allows you to create a ParameterizableViewController with whatever supported HTTP methods you wish. The second bean creates the mapping so that the path "/" resolves to the defined controller.
ParameterizableViewController default supported methods are GET,HEAD we are check it with the following code snippet.
ParameterizableViewController pvc=new ParameterizableViewController();
String[] str=pvc.getSupportedMethods();
for(String x:str) {
System.out.println(x);
}
in order to add POST or any HTTP method, we need to add this XML tag in our bean tag.
<bean id="testUrl"
class="org.springframework.web.servlet.mvc.ParameterizableViewController">
<property name="supportedMethods" value="GET,POST,PUT,DELETE" />
<property name="viewName" value="success" />
</bean>

Building custom Spring config tags for a framework

I have a framework which currently requires pretty verbose setup in Spring:
<bean id="dpHibernateRemotingAdapter"
class="org.springframework.flex.core.ManageableComponentFactoryBean">
<constructor-arg value="org.dphibernate.adapters.RemotingAdapter" />
<property name="properties">
<value>
{"dpHibernate" :
{
"serializerFactory" : "org.dphibernate.serialization.SpringContextSerializerFactory"
}
}
</value>
</property>
</bean>
<bean id="dataAccessService" class="org.dphibernate.services.SpringLazyLoadService"
autowire="constructor">
<flex:remoting-destination />
</bean>
<bean id="dpHibernateSerializer" class="org.dphibernate.serialization.HibernateSerializer"
scope="prototype">
<property name="pageSize" value="10" />
</bean>
<bean id="dpHibernateDeserializer" class="org.dphibernate.serialization.HibernateDeserializer"
scope="prototype" />
I'd like to look at providing a more elegant configuration tag, similar to user-friendly tags used elsewhere in spring:
<context:annotation-config />
<mvc:annotation-driven />
<tx:annotation-driven />
<flex:message-broker/>
etc.,
However, I don't really know where to start.
How does this approach work? What are these tags called? What's their base class?
If someone could point me to the class names in the source (ideally, the <flex:message-broker />, as that's the closest problem set to my project), then I can go from there. I just don't really know where to start!
Custom XML namespaces are certainly possible (see Appendix D), but in my experience a royal pain to get working properly.
I strongly recommend that instead you use #Bean-style configuration. This lets you use Java to compose your bean graphs, instead of XML. Not only can it be much more concise in certain situations, it's properly type-safe, and more easily re-used.
Either way, you'll end up writing some Java that wires objects together. It's a question of how you want to expose that.
See Appendix D. Extensible XML authoring.

Spring won't intercept locale parameter + security [Java, i18n]

I am using both Spring security and Spring i18n. This is my security config:
<security:http access-denied-page="/denied.htm">
<security:form-login login-page="/login.htm"
authentication-failure-url="/login.htm?login_error=true" />
<security:intercept-url pattern="/denied.htm" filters="none"/>
<security:intercept-url pattern="/login.htm*" filters="none"/>
<security:intercept-url pattern="/*" access="IS_AUTHENTICATED_FULLY" />
<security:logout/>
</security:http>
Besides that, I have set authenticationManager for database with MD5 encoding for password. Security work just fine. My i18n config is:
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="messages" />
</bean>
It works fine with reading locales from web browser's HTTP request, but I want it to change locale if I click on the link on the page (adds ?lang=hr parameter to current page). So when I add this, locale doesn't change at all:
<bean id="localeChangeInterceptor" class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang" />
</bean>
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.SessionLocaleResolver">
<property name="defaultLocale" value="en"/>
</bean>
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping">
<property name="interceptors">
<ref bean="localeChangeInterceptor" />
</property>
</bean>
So I have few questions.
Why the locale interception suddenly doesn't work and how to fix it?
How to read the current chosen locale for user's session from java class? I have java class where I need to fetch spring's message from message_en.properties or message_hr.properties file. Jasper report.
I need to add some interceptor (or something like that) to restrain user with default password only to work with /changePassword.htm page. What is the simplest solution?
Many thanks
Why the locale interception suddenly doesn't work and how to fix
it?
I guess: To "fix" you local interceptor, you should check, that the local interceptor can be invoked even if the user is not logged in.
_2. How to read the current chosen locale for user's session from java
class?
Use the RequestContext.getLocale() method.
#see http://static.springsource.org/spring/docs/2.0.x/reference/mvc.html#mvc-localeresolver
added
The best place (in design/architecure) to obtain the local form the request is the web controller. If you are using Spring 3.0 you can obtain the HttpServletRequest directly if you put an parameter of this type to your Controller Request Handler Method. But you have an better choise: just add a Local parameter to your controller handler method
#see http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-arguments
_3. I need to add some interceptor (or something like that) to restrain user
with default password only to work
with /changePassword.htm page. What is
the simplest solution?
One way (may not the simplest, and a one that needs documentation) is to give a user with the default passwort not the full set of priveleges (ony the privileges that he need to set the new password), after chaning tha password, give the user the full set of privileges, which allow him to do all the other stuff.
Try registering localeChangeInterceptor this way. It worked for me.
<mvc:interceptors>
<bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor">
<property name="paramName" value="lang"></property>
</bean>
</mvc:interceptors>

Spring MVC - Form Mapping

Probably missing something completely obvious here, but here goes. I'm starting out with Spring MVC. I have a form controller to process inbound requests to /share/edit.html. When I hit this url from my browser, I get the following error:
The requested resource (/inbox/share/share/edit) is not available.
Here is my applicationContext-mvc.xml:
<bean id="publicUrlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping" >
<property name="mappings" >
<value>
/share/edit.html=shareFormController
/share/list.html=shareController
/share/view.html=shareController
/folders.json=foldersController
/studies.json=studiesController
</value>
</property>
</bean>
<bean id="internalPathMethodNameResolver" class="org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver" />
<bean id="shareFormController" class="com.lifeimage.lila.controller.ShareFormController" />
<bean id="shareController" class="com.lifeimage.lila.controller.ShareController" >
<property name="methodNameResolver" ref="internalPathMethodNameResolver" />
</bean>
and my form Controller:
public class ShareFormController extends SimpleFormController {
public ShareFormController() {
setCommandClass( Share.class );
}
#Override
protected ModelAndView onSubmit(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors)
throws Exception {
//controller impl...
}
}
You should look at your view resolver. Make sure that it is resolving the logical name in your controller as you think it should. Looks like the name it is resolving it to does not exist currently
I think I've resolved this issue. There were two problems:
1) Implementations of SimpleFormController require a form and success view; which I had not configured here. As this is a server method for an AJAX client, I added a Spring-JSON view as follows:
<?xml version="1.0" encoding="UTF-8"?>
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"
default-lazy-init="false" default-autowire="no"
default-dependency-check="none">
<bean name="jsonView" class="org.springframework.web.servlet.view.json.JsonView">
<property name="jsonErrors">
<list>
<ref bean="statusError" />
<ref bean="modelflagError" />
</list>
</property>
</bean>
<bean name="statusError"
class="org.springframework.web.servlet.view.json.error.HttpStatusError">
<property name="errorCode"><value>311</value></property>
</bean>
<bean name="modelflagError"
class="org.springframework.web.servlet.view.json.error.ModelFlagError">
<property name="name"><value>failure</value></property>
<property name="value"><value>true</value></property>
</bean>
which can be used for all controllers that return JSON.
2) I switched from a SimpleURLHandlerMapping to ControllerClassNameHandlerMapping and relied on Spring naming conventions ( controllerClassName/method.html ), which fixed the routing issue. Might not be a long term solution, but got me through the task.
Did you check your log output? Spring MVC is generally pretty verbose in what it outputs.
Also, the URL you've posted (/inbox/share/share/edit) does not seem to match what you are configuring (/share/edit.html).
#jordan002 when I see all the hoops you had to jump to accomplish your task, I feel obliged to share a very powerful Java MVC framework that requires much less configuration. The framework is called Induction, check out the article Induction vs. Spring MVC, http://www.inductionframework.org/induction-vs-spring-mvc.html

Categories

Resources