Spring MVC:将请求属性绑定到控制器方法参数

时间:2013-02-22 19:46:05

标签: java spring spring-mvc

在Spring MVC中,很容易将请求参数绑定到处理请求的方法参数。我只使用@RequestParameter("name")。但我可以对请求属性执行相同的操作吗?目前,当我想访问请求属性时,我必须执行以下操作:

MyClass obj = (MyClass) request.getAttribute("attr_name");

但我真的想用这样的东西代替:

@RequestAttribute("attr_name") MyClass obj

不幸的是,这种方式不起作用。我可以以某种方式扩展Spring功能并添加我自己的“绑定器”吗?

编辑 (我正在努力实现的目标):我将当前登录的用户存储在请求属性中。因此,每当我想访问当前登录的用户时(这几乎都在每个方法中),我必须编写这个额外的行user = (User) request.getAttribute("user");。我想尽量缩短它,最好将它作为方法参数注入。或者如果你知道如何通过拦截器和控制器传递某些东西,我会很高兴听到它。

7 个答案:

答案 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(...);
    }

}

来源:http://blog.crisp.se/tag/requestattribute

答案 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

中注册