我正在尝试在 Spring 4.0 的不同选项卡中使用不同的模型。我在这里使用了duckranger概述的解决方案-> https://github.com/duckranger/Spring-MVC-conversation
我的控制器看起来像这样:
@Controller
@RequestMapping("/counter")
@SessionAttributes("mycounter")
public class CounterController {
@ModelAttribute("mycounter")
public MyCounter populateCounter(){
return new MyCounter(0);
}
@RequestMapping(method = RequestMethod.GET)
public String get(@ModelAttribute("mycounter") MyCounter mycntr) {
return "counter";
}
// Obtain 'mycounter' object for this user's session and increment it
@RequestMapping(method = RequestMethod.POST)
public String post(@ModelAttribute("mycounter") MyCounter myCounter) {
myCounter.increment();
return "redirect:/counter";
}
}
根上下文.xml:
<bean id="requestMappingHandlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="sessionAttributeStore">
<ref bean="conversationalSessionAttributeStore" />
</property>
</bean>
<bean id="conversationalSessionAttributeStore"
class="de.telekom.cldb.admin.security.ConversationalSessionAttributeStore">
<property name="keepAliveConversations" value="10" />
<property name="requestMappingHandlerAdapter">
<ref bean="requestMappingHandlerAdapter" />
</property>
</bean>
SessionAttributeStore 的实现与 Dukeranger 的代码完全相同:
public class ConversationalSessionAttributeStore implements SessionAttributeStore, InitializingBean {
@Inject
private RequestMappingHandlerAdapter requestMappingHandlerAdapter;
private static final Logger logger = Logger.getLogger(ConversationalSessionAttributeStore.class);
private int keepAliveConversations = 10;
public final static String CID_FIELD = "_cid";
public final static String SESSION_MAP = "sessionConversationMap";
@Override
public void storeAttribute(WebRequest request, String attributeName, Object attributeValue) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
Assert.notNull(attributeValue, "Attribute value must not be null");
String cId = getConversationId(request);
if (cId == null || cId.trim().length() == 0) {
cId = UUID.randomUUID().toString();
}
request.setAttribute(CID_FIELD, cId, WebRequest.SCOPE_REQUEST);
logger.debug("storeAttribute - storing bean reference for (" + attributeName + ").");
store(request, attributeName, attributeValue, cId);
}
@Override
public Object retrieveAttribute(WebRequest request, String attributeName) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
if (getConversationId(request) != null) {
if (logger.isDebugEnabled()) {
logger.debug("retrieveAttribute - retrieving bean reference for (" + attributeName + ") for conversation (" + getConversationId(request) + ").");
}
return getConversationStore(request, getConversationId(request)).get(attributeName);
} else {
return null;
}
}
@Override
public void cleanupAttribute(WebRequest request, String attributeName) {
Assert.notNull(request, "WebRequest must not be null");
Assert.notNull(attributeName, "Attribute name must not be null");
if (logger.isDebugEnabled()) {
logger.debug("cleanupAttribute - removing bean reference for (" + attributeName + ") from conversation (" + getConversationId(request) + ").");
}
Map<String, Object> conversationStore = getConversationStore(request, getConversationId(request));
conversationStore.remove(attributeName);
// Delete the conversation store from the session if empty
if (conversationStore.isEmpty()) {
getSessionConversationsMap(request).remove(getConversationId(request));
}
}
/**
* Retrieve a specific conversation's map of objects from the session. Will create the conversation map if it does not exist.
*
* The conversation map is stored inside a session map - which is a map of maps. If this does not exist yet- it will be created too.
*
* @param request
* - the incoming request
* @param conversationId
* - the conversation id we are dealing with
* @return - the conversation's map
*/
private Map<String, Object> getConversationStore(WebRequest request, String conversationId) {
Map<String, Object> conversationMap = getSessionConversationsMap(request).get(conversationId);
if (conversationId != null && conversationMap == null) {
conversationMap = new HashMap<String, Object>();
getSessionConversationsMap(request).put(conversationId, conversationMap);
}
return conversationMap;
}
/**
* Get the session's conversations map.
*
* @param request
* - the request
* @return - LinkedHashMap of all the conversations and their maps
*/
private LinkedHashMap<String, Map<String, Object>> getSessionConversationsMap(WebRequest request) {
@SuppressWarnings("unchecked")
LinkedHashMap<String, Map<String, Object>> sessionMap = (LinkedHashMap<String, Map<String, Object>>) request.getAttribute(SESSION_MAP, WebRequest.SCOPE_SESSION);
if (sessionMap == null) {
sessionMap = new LinkedHashMap<String, Map<String, Object>>();
request.setAttribute(SESSION_MAP, sessionMap, WebRequest.SCOPE_SESSION);
}
return sessionMap;
}
/**
* Store an object on the session. If the configured maximum number of live conversations to keep is reached - clear out the oldest conversation. (If max number is configured as 0 - no removal will happen)
*
* @param request
* - the web request
* @param attributeName
* - the name of the attribute (from @SessionAttributes)
* @param attributeValue
* - the value to store
*/
private void store(WebRequest request, String attributeName, Object attributeValue, String cId) {
LinkedHashMap<String, Map<String, Object>> sessionConversationsMap = getSessionConversationsMap(request);
if (keepAliveConversations > 0 && sessionConversationsMap.size() >= keepAliveConversations && !sessionConversationsMap.containsKey(cId)) {
// clear oldest conversation
String key = sessionConversationsMap.keySet().iterator().next();
sessionConversationsMap.remove(key);
}
getConversationStore(request, cId).put(attributeName, attributeValue);
}
public int getKeepAliveConversations() {
return keepAliveConversations;
}
public void setKeepAliveConversations(int numConversationsToKeep) {
keepAliveConversations = numConversationsToKeep;
}
/**
* Helper method to get conversation id from the web request
*
* @param request
* - Incoming request
* @return - the conversationId (note that this is a request parameter, and only gets there on form submit)
*/
private String getConversationId(WebRequest request) {
String cid = request.getParameter(CID_FIELD);
if (cid == null) {
cid = (String) request.getAttribute(CID_FIELD, WebRequest.SCOPE_REQUEST);
}
return cid;
}
@Override
public void afterPropertiesSet() throws Exception {
requestMappingHandlerAdapter.setSessionAttributeStore(this);
}
public RequestMappingHandlerAdapter getRequestMappingHandlerAdapter() {
return requestMappingHandlerAdapter;
}
public void setRequestMappingHandlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter) {
this.requestMappingHandlerAdapter = requestMappingHandlerAdapter;
}
}
counter.jsp 看起来像这样:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Counter</title>
</head>
<body>
<p>${mycounter.count}</p>
<form action="counter" method="post">
<input type="submit">
</form>
</body>
</html>
我的问题是 SessionAttributeStore 实现中的 storeAttribute 方法根本没有被调用。此外,在 POST 请求中,当我打开一个附加选项卡时,计数成员变量的值将被覆盖,但这可能是因为未调用会话映射逻辑。
我在这里想念什么?提前感谢大家的帮助。人
编辑#1 我现在已经意识到调用了 DefaultSessionAttributeStore 的方法 storeAttribute。所以在我看来,我没有正确配置我的自定义实现。