控制器中的请求范围属性

时间:2012-05-17 09:16:22

标签: spring servlets spring-mvc controller

我对Spring很陌生,所以对我来说有一个不太明显的事情。即,控制器是单例的事实。我同意这是一个很好的方法,但这不允许我实现我曾经用其他框架实现的东西。

我构建了一个遍布使用AJAX请求的Web应用程序。我有控制器层次结构BaseController作为父级,所有其他控制器扩展它。

应该返回对客户端的响应的控制器操作使用@ResponseBody注释进行注释,并将序列化的JSON字符串返回给客户端。

执行此序列化的方法createJSONResponse()BaseController中实现,这里的主要思想是每个子控制器的操作都使用客户端数据所需的地图Map<String, Object> responseMap填充然后在BaseController中访问此地图并序列化。

我不想在每个操作中创建responseMap的新实例,我不想每次都将其作为createJSONResponse()的参数传递。

我通过将responseMap中的BaseController声明为protected属性来实现其他框架。

我不能用Spring做到这一点,因为所有控制器都是单例,而且每次请求都不会有responseMap的新实例。

我不确定BaseController请求作用域是个好主意。

我创建了一个帮助器类作为请求范围bean,并在此帮助器中声明了responseMap。然后我在@Autowired中将此bean注入BaseController。我还在这个助手中移出了createJSONResponse()方法。然后从控制器我将此地图填充为helper.responseMap.add(<somedata>)并调用helper.createResponseMap()

在这种情况下responseMapcreateResponseMap()中变空,它不包含控制器操作中填充的数据。它以某种方式表明responseMAp不是线程安全的,并且它随着每个异步请求从一个线程移动到另一个线程。

有没有办法实现我需要的功能?


通过变通办法解决: 通过在每个请求之前实例化responseMap并添加到请求拦截器中的HttpServletRequest对象来解决问题。然后createJSONResponse()方法和responseMap填充方法引用getRequestMap()方法,该方法从HttpServletRequest获取responseMap。

P.S。仍然很高兴知道更好的解决方案。

1 个答案:

答案 0 :(得分:0)

为了做到这一点(线程安全),你将被迫在某个时刻为每个请求提供一个该映射的实例(如果你真的想在单例中注入它,你可以使用范围代理 - - 但你最终会得到完全相同的结果,只会更复杂。

我的建议是使用模板方法并摆脱受保护的属性;只需定义一个抽象方法,它将返回每个子类中的填充映射。

如果你只想摆脱在所有具体控制器中编写Map<String, Object> responseMap = new HashMap<String, Object>(),你可以在基本控制器中执行该操作(对于每个请求),然后仅使用抽象方法填充该映射(但是每次都是一个新鲜的实例。)

以下是它在基本控制器中的外观:

public String handleRequest() {
    Map<String, Object> model = new HashMap<String, Object>();
    populateModel(model);
    model.put("success", true);  // as a response to your comment
    return serializeModel(model);
}

protected abstract void populateModel(Map<String, Object> model);

P.S。 作为旁注(尽管这可能是您问题的实际答案),如果您只是将它们作为类型安全对象返回,Spring能够以多种格式序列化您的响应。只需在类路径中包含jackson映射器(以启用JSON格式),在模型类上添加一些JAXB注释,并将模型作为MyBean实例返回。如果您提供正确的Accept:标头或在请求映射中定义正确的produces,Spring会将其编组为XML / JSON。