I'm writing an application using Spring MVC.
I have a method that returns values from a database. And I want to display these values in the site's header (which is shown on all pages). How I can do this?
I need to call this method in every controller.
Declare a class with #ControllerAdvice annotation, then declare a method with #ModelAttribute annotation. For example:
#ControllerAdvice
public class GlobalControllerAdvice {
#ModelAttribute
public void myMethod(Model model) {
Object myValues = // obtain your data from DB here...
model.addAttribute("myDbValues", myValues);
}
}
Spring MVC will invoke this method before each method in each MVC controller. You will be able to use the myDbValues attribute in all pages.
The #ControllerAdvice class should be in the same Java namespace where all your MVC controllers are (to make sure Spring can detect it automatically).
See the Spring Reference for more details on #ControllerAdvice and #ModelAttribute annotations.
You could write your own interceptor.
Related
I am creating a small validation application using Spring MVC. I am very new to Spring MVC and would like to ensure that what I want is possible.
I have simplified my problem.
I have setup a controller that will be called when a URL is executed. localhost/validate/{SOME TEXT}
The {SOME TEXT} value with be sent to all my validation classes I created.
I currently have 4 classes which does the validation and returns another Object data about what happened during the validation
The 4 validation classes are:
CreditCardValidator
AddressValidator
ZipcodeValidator
AccountNumberValidator
I have a main controller bean that when called I want the string to be passed to each class and the object returned from each to be stored and then finally all results are sent back in a response.
Normally, I would do this without Spring by creating an interface that each validation class implements. Then iteration through the list of classes and execute a method.
The problem doing it that way is that whenever I need to add a new validation class I'll need to register it so the request can use it. This involved modifying existing classes.
Since I am using Spring quick heavily in this application I am wondering if this is possible to do via Spring and annotated classes.
I was thinking of creating a custom annotation that each validation class has and then using spring component-scan to get the classes. This would allow me to create new validations without modifying existing code.
Below is the what I am trying to do.
#Controller
public class StringValidationController {
#RequestMapping(value = "/validate/{text:.+}", method = RequestMethod.GET)
public ModelAndView index(#PathVariable("text") String text) {
ModelAndView model = new ModelAndView();
model.setViewName("index");
model.addObject("result", getListOfValidatedData());
return model;
}
public List getListOfValidatedData(){
//Scan for IValidator annotation
//call each concrete class and pass in text
// get object with has validation information in it
}
}
I have a method in my #Transaction enabled class which is getting invoked from outside class using java reflection. Unfortunately Spring Transaction is not working inside this method.
Class looks something like below:
#Transactional
public class CartServiceImpl implements CartService {
#Autowired
AnnotatedMethodInvoker annotatedMethodInvoker;
#Override
#VersionedParent
public BasicResponse addCartItem(AddCartItemRequest addCartItemRequest) throws Exception{
String currentMethodName = Thread.currentThread().getStackTrace()[1].getMethodName();
return (BasicResponse)annotatedMethodInvoker.invoke(this, currentMethodName, addCartItemRequest, AddCartItemRequest.class);
}
#VersionedMethod(parentMethod="addCartItem", minimumVersion=Constants.BUILD_VERSION_1_0_1, description="Added Epoch")
private BasicResponse addCartItemWithEpoch(AddCartItemRequest addCartItemRequest){
/***** Implementation detail goes here *****/
}
#VersionedMethod(parentMethod="addCartItem", minimumVersion=Constants.BUILD_VERSION_1_0_2, description="Added Cart filter here")
private BasicResponse addCartItemWithCartFilter(AddCartItemRequest addCartItemRequest){
/***** Implementation detail goes here *****/
}
}
In the AnnotatedMethodInvoker class's invoke() method I am invoking 1 of the two private methods addCartItemWithEpoch() & addCartItemWithCartFilter().
The problem is that when a RuntimeException is occurring, the Transaction is still getting committed, which essentially means that Spring Transaction is not working in my private method.
Surprizingly the below statement returns true if I put it inside my private method:
TransactionSynchronizationManager.isActualTransactionActive()
My application is currently using Spring AOP transaction throughout and it works seamlessly. application-config.xml snippet below:
<context:annotation-config />
<context:component-scan base-package="com.apraxalpha.dealernews" />
<tx:annotation-driven />
I have read this blog which suggests using AspectJ based Transaction over Spring AOP Transaction approach. I am not really confident about this, because my entire application is otherwise using Spring AOP based Transaction. now just for 1 single implementation change, I don't want to change everything to AspectJ transaction.
1) Is there any such middle path to have both the approaches in my application ?
2) Is there any other way to have Transaction in my private method getting invoked using java reflection?
Went through several other posts on similar problem :
1) Spring Transaction not working while calling private method of a Spring Bean class or
2) calling a method from another method in same class
Seems like either you use AspectJ instead of Spring AOP to call the bean class methods
OR
If you don't want to use AspectJ and stick to Spring AOP then a simple refatoring of the class will solve the problem as below:
In the question the method public method addCartItem and the actual implementation methods(which are actually having the implementation code) are all in the same bean class.
Consider creating a delegator class as a layer above this bean class and put the public method addCartItem in that class. Then make the both private methods as public and try to call the bean class methods from the delegator method.
Below is my controller. My program generates an output, based on a form input. Across the project, there are multiple input forms, that generate the output object. So, the essential flow is the same. So I want a single multi-action controller that does all of that.
Challenges:
1. The service classes change. Although all services implement the same interface, and controller calls the same interface method.
2. The input objects change. Although the input objects do not have any methods other than setters, and getters. So I let them all implement an empty interface.
Questions:
How do I change the qualifier, based on the path. Can I use path variables?
Suppose the path has this value -> singleton. Then my corresponding bean names would be singletonService and singletonInput. I want to make a constant class that has stores this mapping information. So, can I call that from inside the qualifier, using some Spring Expression Language? Example, instead of Qualifier(variablePathName) -> Qualifier(getQualifierName['variablePathName']) Something like that?
Please also clarify the theory behind this. From what I understand, beans are created, autowired before the Request are mapped... Does this mean that what I'm trying to achieve here is simply not possible. In that case, would you suggest making Controller-service pairs for handling each request, with basically the same code? But I feel there must be some way to achieve what I'm trying...
Code:
#Cotroller
#RequestMapping(value="/generate/{path}")
public class TestController {
#Autowired
#Qualifier(......)
private IService service;
#Autowired
#Qualifier(......)
IUserInput userInput;
#RequestMapping(method = RequestMethod.POST)
//Some handler method
}
You're right in that the autowiring is all done once up front (point 3). You wouldn't be able to achieve what you want using fields annotated #Autowired and #Qualifier - as these fields would always reference the same bean instance.
You may be better to ask Spring for the particular service bean by name - based on the path variable. You could do it within a single controller instance. For example:
#Cotroller
#RequestMapping(value="/generate/{path}")
public class TestController {
#Autowired
private ApplicationContext applicationContext;
#RequestMapping(method = RequestMethod.POST)
public String someHandlerMethod(#PathVariable String path) {
IService service = (IService) applicationContext.getBean(path + "Service");
IUserInput userInput = (IUserInput) applicationContext.getBean(path + "UserInput");
// Logic using path specific IService and IUserInput
}
}
I have some questions from a design point of view in Spring Web MVC.
Is it good practice to use Request Object in controller? If not, then what is alternative way to pass pass one text fields value to controller? Do I need to create one new from bean for this single fields?
It depends of the situation, in a few cases I used the HttpServletRequest; for example for writing a file to the output stream.
If you want to get the Request Parameters you can use the annotation #RequestParam, that it´s more easy to get the parameters from the request.
Depends that you want to handle, for example for a form you can use #ModelAttribute and this attribute can be in a session or in the request.
For example:
#Controller
public class YourController {
#RequestMapping(value = "someUrl", method = RequestMethod.GET)
public String someMethod(#RequestParam("someProperty") String myProperty)
{
// ... do some stuff
}
}
Check the documentation here:
#RequestParam
#ModelAttribute
#PathVariable
With WebForms, if I wanted to run a method on every page load, then I would call this method in the Page_Load() method of the main Master Page.
Is there an alternative, perhaps better solution, when using MVC3?
you could create a class base controller
public class BaseController : Controller
{
public BaseController()
{
// your code here
}
}
and let every new controller of yours impelement the base controller like
public class MyController: BaseController
also i have found the basecontroller very usefull to store other functions i need a lot in other controllers
I think the most appropriate way to do this in MVC is with filters
MSDN provides a good description of them, and there are dozens of articles and explanatins about them on the net, such as this one
EDIT
This sample is even better: It provides a simple action filter, which is then registered in global.asax, and executed on every request, before the actual Action in the relevan controller executes. Such concept allows you to access the request object, and modify whatever you want before the actual controller is executing.
You could put the code in the constructor of the controller.
Like this:
public class FooController : Controller
{
public FooController()
{
doThings();
}