Looking for a way to apply aspects to spring-mvc controller method - spring

The original intention was to be able to configure filter mappings with annotations (i.e. #FilteredBy below) instead of adding filter mappings to the web.xml file. Something like:
#Controller
public class MyController {
#RequestMapping(value = "/special/page.html")
#FilteredBy("SpecialBean") // <-- *** desired ***
public String doSpecialStuff() {
return "special/page";
}
}
I see that Servlet 3.0 introduces #ServletFilter which can be applied any object method and the mappings are defined by #FilterMapping. However, I want invert the responsibility of the mapping to the controller method consuming the shared logic of my "SpecialBean".

Why not use your spring context xml. If you are using mvc:annotation you can try this.
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/filtered/page.htm" />
<bean class="com.yourinterceptor" />
</mvc:interceptor>
</mvc:interceptors>

Related

what is the usage of new keyword while using java configuration in spring

I have a question around the usage of new keyword being used when using java configuration in spring. What is the need of using new keyword
Refer below mentioned example:
Code implemented using Java Config
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
The above code will be equivalent to the following XML configuration
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
In XML config, we do not use new keyword whereas in java config we are using new keyword. can someone please explain the difference
In the XML configuration, you explain to the system what class should be instanciated (there is a "new" but it is behind the scene) but in the Java Config you actually have to return an instance so that is why we use the 'new' keyword. 'new' simply creates an instance of your class.
The two examples shown in question are not really equivalent.
What the
<beans>
<bean id="helloWorld"
class="com.test.HelloWorld" />
</beans>
really does, is it tells Spring to instantiate class com.test.HelloWorld, and name the resulting bean "helloWorld".
Then the java-config approach is not really doing this. Instead this follows the factory-method pattern, when we tell Spring, that the return value of the method is the bean, and the method name is the name of that bean.
An equivalent of that in XML would be the mentioned factory-method approach, which in this case would look something like this:
<beans>
<bean id="helloWorldConfig"
class="com.test.HelloWorldConfig" />
<bean id="helloWorld"
factory-bean="helloWorldConfig"
factory-method="helloWorld" />
</beans>
Note that there are several approaches to factory-method. In the above, we are assuming, the `helloWorldConfig" is the factory, and we're specifying the method on that bean. Theare are cases with static factory methods too. See here for more examples.
<beans>
<bean id = "helloWorld" class = "com.test.HelloWorld" />
</beans>
This XML configurations tells Spring to "create an instance of com.test.HelloWorld and put it in the bean context with bean id helloWorld".
#Configuration
public class HelloWorldConfig {
#Bean
public HelloWorld helloWorld(){
return new HelloWorld();
}
}
In this Java configuration, we are returning an instance of com.test.HelloWorld. Because of the #Bean annotation, this instance is put into the bean context. As no specific bean id is given, the bean id is derived from the method hellowWorld() and thus becomes helloWorld.
As you can see, both configurations require an instance of com.test.HelloWorld. The XML configuration implicitly creates the instance whereas in the Java configuration you have to explicitly do it yourself.

The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler

I wanted to use both annotation mapping and xml mapping in Spring MVC. My application-context.xml as follows:
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="personal/account/history">accountHistoryController</prop>
</props>
</property>
</bean>
<bean id="accountHistoryController" class="com.fg.banking.ib.controller.AccountHistoryController" />
<bean
class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>
<context:annotation-config />
<mvc:annotation-driven />
<context:component-scan base-package="com.fg.banking.ib.controller, com.fg.banking.ib.helper, com.fg.banking.corporate.controller" />
I am getting the following error when I try to access the url. I have configured the SimpleControllerHandlerAdapter as above.
javax.servlet.ServletException: No adapter for handler
[com.fg.banking.ib.controller.AccountHistoryController#218531e6]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler
org.springframework.web.servlet.DispatcherServlet.getHandlerAdapter(DispatcherServlet.java:1128)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:903)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:936)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:827)
What to do?
This error also occurs when you define a restController but forget to define the requestMapping.
#RestController
#RequestMapping("/api/orders") // <---- dont't forget the requestMapping
This problem occurred for me when I tried to define RestController path by using in this way:
#RestController("/test")
public class TestController {}
In the above section, the meaning of this declaration is different. Here actually "/test" is defined as bean name rather than path for the controller.
After defining the path in this way it worked for me:
#RestController
#RequestMapping("/test")
public class TestController {}
I resolved the issue. I forgot to add the #Controller annotation in controller class. There are fore we can use the both methods(annotation mapping & XML mapping) together in an application.
Try adding the following as a handler mapper(Worked for me):
<bean id="HandlerMapping" class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
Make sure you have implemented Controller in your controller classes and overrided handleRequest method.
Here our controller class should extends
import org.springframework.web.servlet.mvc.AbstractController;
public class AppController extends AbstractController{ }
Here we need to implement the abstract method as :
protected modelandview handleRequestInternal(HttpServletRequest arg0, HttpServletResponse arg1) throws Exception { return null; }

Can I combine #controller and XML bean mapping in spring?

I currently have a #Controller declared in spring and have a bunch of mappings done like so:
#RequestMapping(value = "foo", method = RequestMethod.GET)
public ModelAndView foo() {
ModelAndView mav = new ModelAndView(
"myjsp");
return mav;
}
However every time I want to add a simple JSP mapping I need to recompile and build a new war and deploy.
This isnt so bad except sometimes other members of the team have requests and it would be easier if they can just go into the test env and create the mapping themselves without having to recompile.
I know that you can do similar mapping using xml but can I do this at the same time that I have the #Controller defined?
Like in the example above how could I define that mapping in XML rather than in java?
or say I needed foo2 to map to myjsp2.jsp
I am using spring MVC 3.2
Look into BeanNameUrlHandlerMapping which allows you specify url patterns for controllers in your configuration. Documentation
Example
<beans>
<bean id="handlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
<bean name="/editaccount.form" class="org.springframework.web.servlet.mvc.SimpleFormController">
<property name="formView" value="account"/>
<property name="successView" value="account-created"/>
<property name="commandName" value="account"/>
<property name="commandClass" value="samples.Account"/>
</bean>
<beans>

how to load spring properties without injection or inject a bundle or something?

I currently load my properties file like so in spring
<context:property-placeholder location="test-esb-project-config.properties"/>
<context:property-placeholder location="esb-project-config.properties"/>
This seems to work great for properties use inside the xml files. How do I load a property from inside my java code now though? OR how do I inject some kind of Bundle or Config object so I don't have to inject 10 properties in one bean?
thanks,
Dean
using annotations #Value(${property}) worked much better and it injected the property into my bean without all the work of xml typing and adding a setter...way too much work going that route.
You can either have setters for each property and wire them with the property reference.
public class MyBean{
public void setFoo(String foo){ /* etc */}
public void setBar(String bar){ /* etc */}
}
<bean class="foo.bar.MyBean">
<property name="foo" value="${my.properties.foo}" />
<property name="bar" value="${my.properties.bar}" />
</bean>
Or you can inject a Properties Object into your Spring Bean.
public class MyBean{
public void setProperties(Properties properties){
// init your properties here
}
}
<bean class="foo.bar.MyBean">
<property name="properties" value="classpath:/path.to.properties" />
</bean>
Both of these would also work without XML when using the #Value annotation.
(see Expression Language > Annotation-based Configuration)

Spring mvc:mapping path rules

I need to map interceptor for all methods in annotated controller with #RequestMapping(value = "/client")
In mapping I have
<mvc:interceptor>
<mvc:mapping path="/app/client/*"/>
<bean class="com.cci.isa.web.CIPClientHandleInterceptor" />
</mvc:interceptor>
This interceptor called perfectly for urls like:
1. http://host/app/client/clientUpdateForm?clientId=305
But doesn't called for urls like:
2. http://host/app/client/clientUpdateForm/clientId_305 (with slash after method name)
How get it called for second variant?
Thanks a lot.
This question is too old, but maybe this helps somebody.
You should try removing /app, I think it's not necessary and perhaps this is causing the problem.
<mvc:mapping path="/client/**"/>
I think this will achieve what you would like:
<mvc:mapping path="/app/client/**/*"/>
The '/**' suggests any number of directories. When this is used in conjunction with '/*', you have something that looks at an arbitrary folder depth, with an arbitrary file name.
If your controller with
#RequestMapping(value = "/client")
Try
<mvc:mapping path="/client**"/>
Try the above suggestion but change the annotation to
#RequestMapping(value = "/client*")
Although I would use two methods for each of the two URI patterns and pass them to the one common method to do the "stuff"...
#RequestMapping(value = "/app/client/clientUpdateFormat/{clientId}", method = RequestMethod.GET)
public String doItOne(#PathVariable("clientId") String clientId) {
doItCommon(clientId);
and
#RequestMapping(value = "/app/client/clientUpdateFormat", method = RequestMethod.GET)
public String doItTwo(#RequestParam("clientId") String clientId) {
doItCommon(clientId);
My problem was, that we used custom RequestMappingHandlerMapping
<bean name="handlerMapping"
class="utils.web.versioning.MobileVersionRewritingMappingHandler">
<property name="order" value="0"/>
<property name="interceptors">
<list>
...
</list>
</property>
</bean>
XML or code config for CORS or any other MVC properties doesn't affect custom handler mappings.
I could specify cors config for custom handler mapping, but I prefer to remove legacy config and use this to configure interceptors:
<mvc:interceptors>
...
</mvc:interceptors>
Now cors is working and I'm using XML global cors configuration.

Resources