可以从JSP向Spring Controller发送多种类型的对象吗?

时间:2014-04-04 10:46:11

标签: java spring jsp spring-mvc

我编写了一个JSP视图,一旦提交就必须将多个对象发送到Spring @Controller。

控制器的处理程序具有以下签名:

public ModelAndView handlerX(@ModelAttribute ModelMap model){

我在JSP中尝试过类似的东西:

<form method="post" action="action">
<spring:bind path="objectX.name">
    <input type="text" name="${status.expression}" value="${status.value}" readonly="readonly" />
</spring:bind> 

但是当调试器到达控制器时,模型对象不包含任何形式的值。

有人可以就如何设计表格提出一些建议吗?我想我不能将两个不同的对象包装在Command-type-object中,因为控制器的处理程序只接受ModelMap。非常感谢你!

2 个答案:

答案 0 :(得分:1)

您可以创建一个包含与表单字段匹配的字段的表单,然后像这样获取该表单:

 @RequestMapping(method= RequestMethod.POST)
        public Response add(@RequestBody Form form, HttpServletRequest request){
    //The form element's fields must match with fields in your form. Especially the names and types.
    }

除了在add()中传递的这两个参数之外,您还可以传递更多

答案 1 :(得分:1)

您可以通过定制自己的HandlerMethodArgumentResolver来绑定从表单发送到模型参数的请求参数来解决此问题。例如:

public class RequestToModelBindingArgumentResolver implements HandlerMethodArgumentResolver, Ordered {

    @Override
    public boolean supportsParameter(final MethodParameter parameter) {
        return  parameter.hasParameterAnnotation(ModelAttribute.class) &&
                parameter.getParameterType() == ModelMap.class;
    }

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

        ModelMap model = mavContainer.getModel();
        Map<String, String[]> requestParameters = webRequest.getParameterMap();

        // Bind all request parameters to the model
        for (String param : requestParameters.keySet()) {
            String[] values = requestParameters.get(param);
            if (values.length == 1) {
                model.addAttribute(param, values[0]);
            } else {
                model.addAttribute(param, values);
            }
        }

        return model;
    }

    @Override
    public int getOrder() {
        return HIGHEST_PRECEDENCE;
    }
}

可以将此类的实例添加到参数解析程序列表中的应用程序配置。

@Override
public void addArgumentResolvers(final List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new RequestToModelBindingArgumentResolver());
}

但是有一个问题。使用@ModelAttribute注释的参数将由ModelAttributeMethodProcessor解析,由于没有HandlerMethodArgumentResolver的排序,因此它始终是第一个解析该值的。这意味着如果您要添加自定义参数解析器,则永远不会到达它。这意味着我们需要找到一种方法来对解析器集合进行排序(这就是解析器实现Ordered的原因。

对解析器集合进行排序的一种简单方法是将RequestmappingHandlerAdapter注入配置中。

@Autowired
private RequestMappingHandlerAdapter adapter;

现在我们需要在构造配置之后调用一个方法,这样我们就有机会对解析器集合进行排序。

@PostConstruct
public void orderArgumentResolvers() {
    List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(adapter.getArgumentResolvers());
    Collections.sort(resolvers, new OrderComparator());
    adapter.setArgumentResolvers(resolvers);
}

由于adapter.getArgumentResolvers()将返回一个不可修改的列表,我们需要在排序开始前跳到这里。排序后,RequestToModelBindingArgumentResolver实例将位于列表顶部,第一个实例将响应support()调用。

但是嘿!我认为改变处理程序签名要容易得多:)