在Spring MVC中,很容易将请求参数绑定到处理请求的方法参数。我只使用@RequestParameter("name")
。但我可以对请求属性执行相同的操作吗?目前,当我想访问请求属性时,我必须执行以下操作:
MyClass obj = (MyClass) request.getAttribute("attr_name");
但我真的想用这样的东西代替:
@RequestAttribute("attr_name") MyClass obj
不幸的是,这种方式不起作用。我可以以某种方式扩展Spring功能并添加我自己的“绑定器”吗?
编辑 (我正在努力实现的目标):我将当前登录的用户存储在请求属性中。因此,每当我想访问当前登录的用户时(这几乎都在每个方法中),我必须编写这个额外的行user = (User) request.getAttribute("user");
。我想尽量缩短它,最好将它作为方法参数注入。或者如果你知道如何通过拦截器和控制器传递某些东西,我会很高兴听到它。
答案 0 :(得分:33)
好吧,我终于理解了模型的工作原理以及@ModelAttribute
的用途。这是我的解决方案。
@Controller
class MyController
{
@ModelAttribute("user")
public User getUser(HttpServletRequest request)
{
return (User) request.getAttribute("user");
}
@RequestMapping(value = "someurl", method = RequestMethod.GET)
public String HandleSomeUrl(@ModelAttribute("user") User user)
{
// ... do some stuff
}
}
标有getUser()
注释的@ModelAttribute
方法会自动填充标有User user
的所有@ModelAttribute
参数。因此,当调用HandleSomeUrl方法时,调用看起来像MyController.HandleSomeUrl(MyController.getUser(request))
。至少这是我的想象。很酷的是,用户也可以从JSP视图访问而无需任何进一步的努力。
这解决了我的问题,但我还有其他问题。有一个共同的地方,我可以把那些@ModelAttribute
方法,所以他们是我的所有控制器共同的?我可以以某种方式从拦截器的preHandle()
方法内部添加模型属性吗?
答案 1 :(得分:8)
使用(截至Spring 4.3)@RequestAttribute:
@RequestMapping(value = "someurl", method = RequestMethod.GET)
public String handleSomeUrl(@RequestAttribute User user) {
// ... do some stuff
}
或者请求属性名称与方法参数名称不匹配:
@RequestMapping(value = "someurl", method = RequestMethod.GET)
public String handleSomeUrl(@RequestAttribute(name="userAttributeName") User user) {
// ... do some stuff
}
答案 2 :(得分:3)
我认为你在寻找的是:
@ModelAttribute("attr_name") MyClass obj
您可以在控制器中方法的参数中使用它。
以下是问题的链接,其中包含详细信息What is @ModelAttribute in Spring MVC?
该问题链接到Spring文档,并提供了一些使用它的示例。您可以看到here
<强>更新强>
我不确定您是如何设置页面的,但您可以通过几种不同的方式将用户添加为模型属性。我在下面设置了一个简单的例子。
@RequestMapping(value = "/account", method = RequestMethod.GET)
public ModelAndView displayAccountPage() {
User user = new User(); //most likely you've done some kind of login step this is just for simplicity
return new ModelAndView("account", "user", user); //return view, model attribute name, model attribute
}
然后,当用户提交请求时,Spring会将user属性绑定到方法参数中的User对象。
@RequestMapping(value = "/account/delivery", method = RequestMethod.POST)
public ModelAndView updateDeliverySchedule(@ModelAttribute("user") User user) {
user = accountService.updateDeliverySchedule(user); //do something with the user
return new ModelAndView("account", "user", user);
}
答案 3 :(得分:2)
不是最优雅,但至少起作用......
@Controller
public class YourController {
@RequestMapping("/xyz")
public ModelAndView handle(
@Value("#{request.getAttribute('key')}") SomeClass obj) {
...
return new ModelAndView(...);
}
}
答案 4 :(得分:1)
从Spring 3.2开始,使用Springs ControllerAdvice注释可以更好地完成它。 然后,这将允许您有一个建议,将@ModelAttributes添加到一个单独的类中,然后将其应用于所有控制器。
为了完整性,还可以实际生成@RequestAttribute(“attr-name”)。 (以下this article修改以符合我们的要求)
首先,我们必须定义注释:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface RequestAttribute {
String value();
}
然后我们需要一个[WebArgumentResolver]来处理绑定属性时需要做的事情
public class RequestAttributeWebArgumentResolver implements WebArgumentResolver {
public Object resolveArgument(MethodParameter methodParameter, NativeWebRequest nativeWebRequest) throws Exception {
// Get the annotation
RequestAttribute requestAttributeAnnotation = methodParameter.getParameterAnnotation(RequestAttribute.class);
if(requestAttributeAnnotation != null) {
HttpServletRequest request = (HttpServletRequest) nativeWebRequest.getNativeRequest();
return request.getAttribute(requestAttributeAnnotation.value);
}
return UNRESOLVED;
}
}
现在我们只需要将这个自定义解析器添加到配置中来解决它:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="customArgumentResolver">
<bean class="com.sergialmar.customresolver.web.support.CustomWebArgumentResolver"/>
</property>
</bean>
我们已经完成了!
答案 5 :(得分:0)
是的,您可以将自己的“活页夹”添加到请求属性中 - 请参阅spring-mvc-3-showcase,或使用@Peter Szanto的解决方案。
或者,将其绑定为ModelAttribute,如其他答案中所建议的那样。
由于您要将登录用户传递到控制器,因此您可能需要考虑Spring Security。然后你可以在你的方法中注入Principle:
@RequestMapping("/xyz")
public String index(Principal principle) {
return "Hello, " + principle.getName() + "!";
}
答案 6 :(得分:0)
在Spring WebMVC 4.x中,它更喜欢实现HandlerMethodArgumentResolver
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterAnnotation(RequestAttribute.class) != null;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return webRequest.getAttribute(parameter.getParameterAnnotation(RequestAttribute.class).value(), NativeWebRequest.SCOPE_REQUEST);
}
}
然后在RequestMappingHandlerAdapter
中注册