Spring Controller覆盖@ModelAttribute请求参数映射

时间:2014-01-21 13:22:19

标签: java spring spring-mvc

假设我有一个像这样的Spring Controller:

    @Controller
    public class FooController {

        @RequestMapping(value = "/foo", method = RequestMethod.GET)
        public String update (Model model,
                          @RequestParam (value="id") String id,
                          @RequestParam (value="description") String description) {

                Foo foo = new Foo(id, description);

                fooService.create(update);

        return "foo";
    }

我想像下面那样重写它,但是定义我自己的请求参数映射,而不是让Spring的@ModelAttribute定义它:

    @Controller
    public class FooController {

        @RequestMapping(value = "/foo", method = RequestMethod.GET)
        public String update(Model model,
                          @ModelAttribute("foo") Foo foo) {

        fooService.update(foo);

        return "foo";
    }

有谁知道我会怎么做?我看过转换器,PropertyEditors和使用@RequestBody,但我不认为这些都是正确的。我需要以某种方式覆盖Spring的数据绑定。

3 个答案:

答案 0 :(得分:3)

我解决的解决方案是使用实现Spring的HandlerMethodArgumentResolver类来检测Object并从HttpServletRequest构造它。注意 - 这与@ daviooh的答案非常相似。这里的主要区别是这个解决方案是特定于Spring的,它可以“自动”检测对象类。

添加到spring context.xml

<mvc:annotation-driven>
    <mvc:argument-resolvers>
        <bean class="your.package.name.FooResolver" />   
    </mvc:argument-resolvers>
</mvc:annotation-driven>

创建FooResolver:

public class FooResolver implements HandlerMethodArgumentResolver {

public static final String ID = "id";
public static final String DESCRIPTION = "description";

@Override
public boolean supportsParameter(MethodParameter parameter) {
    return parameter.getParameterType().equals(Foo.class);
}

@Override
public Object resolveArgument(MethodParameter parameter,
                              ModelAndViewContainer mavContainer, 
                              NativeWebRequest webRequest,
                              WebDataBinderFactory binderFactory) throws Exception {

    Foo foo = null;

    if(parameter.getParameterType().equals(Foo.class)) {

        foo = new Foo();

        if (webRequest.getParameter(ID) != null) tag.setId((String) webRequest.getParameter(ID));
        if (webRequest.getParameter(DESCRIPTION) != null) tag.setDescription((String) webRequest.getParameter(DESCRIPTION));
    }

    return foo;
}

}

然后控制器方法变为:

    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public String update (Model model, Foo foo) {
        fooService.update(foo);
        return "foo";
    }

这个解决方案允许我从我的模型对象上的getter和setter方法名称中解析http请求参数名称,并将这个逻辑从我的控制器中拉出来,以使其保持整洁,更容易理解。因此,控制器逻辑位于控制器中,对对象映射逻辑的http请求位于解析器类中。

答案 1 :(得分:1)

一个选项可以是实现一个实用程序类(每个实体需要映射一个),它将请求参数解析为自定义对象。像这样:

public class FooParser{

    public static final String ID = "id";
    public static final String DESCRIPTION = "description";

    public static Foo parse(HttpServletRequest req){
        Foo foo = null;
        if (request.getParameter(ID) != null
            && request.getParameter(DESCRIPTION) != null) {
            foo = new Foo(request.getParameter(ID), request.getParameter(DESCRIPTION));
        }
        return foo;
    }
}

并将其用于您的控制器方法。

@Controller
public class FooController {

    @RequestMapping(value = "/foo", method = RequestMethod.GET)
    public String update(Model model,
                      HttpServletRequest req) {

    Foo foo = FooParser.parse(req);
    fooService.update(foo);

    return "foo";
}

答案 2 :(得分:0)

Spring应该自动为你做这件事。关键是将表单字段与“Foo”对象的属性相匹配。

以下是一些文档:http://docs.spring.io/spring/docs/4.0.0.RELEASE/spring-framework-reference/htmlsingle/#mvc-ann-modelattrib-methods

  

下一步是数据绑定。 WebDataBinder类与请求匹配   参数名称 - 包括查询字符串参数和表单    字段 - 按名称为属性字段建模。匹配字段是   在类型转换后填充(从String到目标字段类型)   已经在必要时使用。

此请求的另一方面是什么样的?提交表单的HTML是什么?

修改

我刚刚创建了一个可能有用的演示版。下面是代码,包括表单,控制器和foo类。让我知道您遇到的任何问题。

形式:

<form method="POST" action="/fooAction">
<input type="text" name="bar" id="bar"/></form>

控制器:

@Controller
public class GreetingController {

      @RequestMapping(value = "/fooAction", method = RequestMethod.POST)
      public String fooAction(Model m, Foo foo) {
        System.out.println("foo is: " + foo);
        m.addAttribute(foo);
        return "fooAction";
      }

    }

Foo Class:

public class Foo {
  private String bar;

  public String getBar() { return bar; }

  public void setBar(String bar) { this.bar = bar; }

  @Override
  public String toString() {
    return "Foo[" + bar + "]";
  }      
}