问题
I have many controllers in my Spring MVC web application and there is a param mandatoryParam
let's say which has to be present in all the requests to the web application.
Now I want to make that param-value available to all the methods in my web-layer and service-layer. How can I handle this scenario effectively?
Currently I am handling it in this way:
回答1:
@ControllerAdvice("net.myproject.mypackage")
public class MyControllerAdvice {
@ModelAttribute
public void myMethod(@RequestParam String mandatoryParam) {
// Use your mandatoryParam
}
}
myMethod()
will be called for every request to any controller in the net.myproject.mypackage
package. (Before Spring 4.0, you could not define a package. @ControllerAdvice
applied to all controllers).
See the Spring Reference for more details on @ModelAttribute
methods.
回答2:
Thanks Alexey for leading the way.
His solution is:
- Add a @ControllerAdvice triggering for all controllers, or selected ones
- This @ControllerAdvice has a @PathVariable (for a "/path/{variable}" URL) or a @RequestParam (for a "?variable=..." in URL) to get the ID from the request (worth mentioning both annotations to avoid blind-"copy/past bug", true story ;-) )
- This @ControllerAdvice then populates a model attribute with the data fetched from database (for instance)
- The controllers with uses @ModelAttribute as method parameters to retrieve the data from the current request's model
I'd like to add a warning and a more complete example:
Warning: see JavaDoc for ModelAttribute.name() if no name is provided to the @ModelAttribute annotation (better to not clutter the code):
The default model attribute name is inferred from the declared attribute type (i.e. the method parameter type or method return type), based on the non-qualified class name: e.g. "orderAddress" for class "mypackage.OrderAddress", or "orderAddressList" for "List<mypackage.OrderAddress>".
The complete example:
@ControllerAdvice
public class ParentInjector {
@ModelAttribute
public void injectParent(@PathVariable long parentId, Model model) {
model.addAttribute("parentDTO", new ParentDTO(parentId, "A faked parent"));
}
}
@RestController
@RequestMapping("/api/parents/{parentId:[0-9]+}/childs")
public class ChildResource {
@GetMapping("/{childId:[0-9]+}")
public ChildDTO getOne(@ModelAttribute ParentDTO parent, long childId) {
return new ChildDTO(parent, childId, "A faked child");
}
}
To continue about the warning, requests are declaring the parameter "@ModelAttribute ParentDTO parent": the name of the model attribute is not the variable name ("parent"), nor the original "parentId", but the classname with first letter lowerified: "parentDTO", so we have to be careful to use model.addAttribute("parentDTO"...)
Edit: a simpler, less-error-prone, and more complete example:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RestController
public @interface ProjectDependantRestController {
/**
* The value may indicate a suggestion for a logical component name,
* to be turned into a Spring bean in case of an autodetected component.
*
* @return the suggested component name, if any
*/
String value() default "";
}
@ControllerAdvice(annotations = ParentDependantRestController.class)
public class ParentInjector {
@ModelAttribute
public ParentDTO injectParent(@PathVariable long parentId) {
return new ParentDTO(parentId, "A faked parent");
}
}
@ParentDependantRestController
@RequestMapping("/api/parents/{parentId:[0-9]+}/childs")
public class ChildResource {
@GetMapping("/{childId:[0-9]+}")
public ChildDTO getOne(@ModelAttribute ParentDTO parent, long childId) {
return new ChildDTO(parent, childId, "A faked child");
}
}
来源:https://stackoverflow.com/questions/24758969/spring-mvc-common-param-in-all-requests