1

我正在尝试在 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。所以在我看来,我没有正确配置我的自定义实现。

4

0 回答 0