简体   繁体   English

Spring MVC定制scope豆

[英]Spring MVC custom scope bean

I would like to create my own custom scope bean which will use HTTP session (kind of Flash scope).我想创建自己的自定义 scope bean,它将使用 HTTP session(ZBF2C44E16FC095EC15648 范围)

According to Spring Manual I need to implement org.springframework.beans.factory.config.Scope interface根据 Spring Manual 我需要实现 org.springframework.beans.factory.config.Scope 接口

public class CustomScope implements Scope {

    @Override
    public Object get(String arg0, ObjectFactory<?> arg1) {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public String getConversationId() {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public void registerDestructionCallback(String arg0, Runnable arg1) {
        // TODO Auto-generated method stub
    }
    @Override
    public Object remove(String arg0) {
        // TODO Auto-generated method stub
        return null;
    }
    @Override
    public Object resolveContextualObject(String arg0) {
        // TODO Auto-generated method stub
        return null;
    }
}

My question is how can I obtain HTTP session inside of this bean?我的问题是如何在这个 bean 中获得 HTTP session ? I understand that if I was creating bean in ServletContext scope I would implement ServletContextAware interface.我知道如果我在 ServletContext scope 中创建 bean,我将实现 ServletContextAware 接口。

Please help:)请帮忙:)

I hope it will be useful for someone in the future, so I would like to share it.我希望它对将来的某人有用,所以我想分享它。

I made some reserch on it and have found that unfortunately, it is impossible to get HTTP Session for Spring MVC.我对其进行了一些研究,发现不幸的是,对于 Spring MVC,不可能获得 HTTP Session。

My purpose was Flash Scope implementation for my Spring MVC Controller using PRG pattern.我的目的是使用 Flash Scope 实现我的 Spring MVC Z9BBF373797BF7CF7252C8002Z8 模式。

Making more research in Spring Forum I've found the way to do it using HandlerInterceptor.在 Spring 论坛中进行更多研究,我找到了使用 HandlerInterceptor 的方法。

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import java.util.*;
import java.util.Map.Entry;

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

public class FlashScopeInterceptor implements HandlerInterceptor {

    public static final String DEFAULT_ATTRIBUTE_NAME = "flashScope";
    public static final String DEFAULT_SESSION_ATTRIBUTE_NAME = FlashScopeInterceptor.class.getName();
    public static final int DEFAULT_RETENTION_COUNT = 2;

    private String sessionAttributeName = DEFAULT_SESSION_ATTRIBUTE_NAME;
    private String attributeName = DEFAULT_ATTRIBUTE_NAME;
    private int retentionCount = DEFAULT_RETENTION_COUNT;

    /**
     * Unbinds current flashScope from session. Rolls request's flashScope to
     * the next scope. Binds request's flashScope, if not empty, to the session.
     * 
     */

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        if (request.getSession( false ) != null)
        {
            request.getSession().removeAttribute( this.sessionAttributeName );
        }
        Object requestAttribute = request.getAttribute( this.attributeName );
        if (requestAttribute instanceof MultiScopeModelMap)
        {
            MultiScopeModelMap attributes = (MultiScopeModelMap) requestAttribute;
            if (!attributes.isEmpty())
            {
                attributes.next();
                if (!attributes.isEmpty())
                {
                    request.getSession( true ).setAttribute( this.sessionAttributeName, attributes );
                }
            }
        }
    }

    /**
     * merge modelAndView.model['flashScope'] to current flashScope
     */
    @Override
    public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        if (modelAndView != null)
        {
            Map<String, Object> modelFlashScopeMap = null;
            for (Iterator<Entry<String, Object>> iterator = ((Map<String, Object>) modelAndView.getModel()).entrySet()
                    .iterator(); iterator.hasNext();)
            {
                Entry<String, Object> entry = iterator.next();
                if (this.attributeName.equals( entry.getKey() ) && entry.getValue() instanceof Map)
                {
                    if (modelFlashScopeMap == null)
                    {
                        modelFlashScopeMap = (Map) entry.getValue();
                    }
                    else
                    {
                        modelFlashScopeMap.putAll( (Map) entry.getValue() );
                    }
                    iterator.remove();
                }
                else if (entry.getKey().startsWith( this.attributeName + "." ))
                {
                    String key = entry.getKey().substring( this.attributeName.length() + 1 );
                    if (modelFlashScopeMap == null)
                    {
                        modelFlashScopeMap = new HashMap<String, Object>();
                    }
                    modelFlashScopeMap.put( key, entry.getValue() );
                    iterator.remove();
                }
            }
            if (modelFlashScopeMap != null)
            {
                MultiScopeModelMap flashScopeMap;
                if (request.getAttribute( this.attributeName ) instanceof MultiScopeModelMap)
                {
                    flashScopeMap = (MultiScopeModelMap) request.getAttribute( this.attributeName );
                }
                else
                {
                    flashScopeMap = new MultiScopeModelMap( this.retentionCount );
                }
                flashScopeMap.putAll( modelFlashScopeMap );
                request.setAttribute( this.attributeName, flashScopeMap );
            }
        }
    }

    /**
     * binds session flashScope to current session, if not empty. Otherwise cleans up empty
     * flashScope
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        HttpSession session = request.getSession( false );
        if (session != null)
        {
            Object sessionAttribute = session.getAttribute( this.sessionAttributeName );
            if (sessionAttribute instanceof MultiScopeModelMap)
            {
                MultiScopeModelMap flashScope = (MultiScopeModelMap) sessionAttribute;
                if (flashScope.isEmpty())
                {
                    session.removeAttribute( this.sessionAttributeName );
                }
                else
                {
                    request.setAttribute( this.attributeName, flashScope );
                }
            }
        }
        return true;
    }
}

Now MultiScopeModelMap.java现在 MultiScopeModelMap.java

import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.map.CompositeMap;
import org.apache.commons.collections.map.CompositeMap.MapMutator;

public class MultiScopeModelMap extends CompositeMap implements Serializable, MapMutator
{
    public MultiScopeModelMap(int num)
    {
        super();
        setMutator( this );
        for(int i = 0; i < num; ++i)
        {
            addComposited( new HashMap() );
        }
    }

    /** Shadows composite map. */
    private final LinkedList<Map> maps = new LinkedList<Map>();

    @Override
    public synchronized void addComposited( Map map ) throws IllegalArgumentException
    {
        super.addComposited( map );
        this.maps.addLast( map );
    }



    @Override
    public synchronized Map removeComposited( Map map )
    {
        Map removed = super.removeComposited( map );
        this.maps.remove( map );
        return removed;
    }



    /** 
     * Starts a new scope. 
     * All items added in the session before the previous session are removed.
     * All items added in the previous scope are still retrievable and removable.
     */ 
    public void next()
    {
        removeComposited( this.maps.getFirst() );
        addComposited( new HashMap() );
    }

    public Object put( CompositeMap map, Map[] composited, Object key, Object value )
    {
        if(composited.length < 1)
        {
            throw new UnsupportedOperationException("No composites to add elements to");
        }
        Object result = map.get( key );
        if(result != null)
        {
            map.remove( key );
        }
        composited[composited.length-1].put( key, value );
        return result;
    }

    public void putAll( CompositeMap map, Map[] composited, Map mapToAdd )
    {
        for(Entry entry: (Set<Entry>)mapToAdd.entrySet())
        {
            put(map, composited, entry.getKey(), entry.getValue());
        }
    }

    public void resolveCollision( CompositeMap composite, Map existing, Map added, Collection intersect )
    {
        existing.keySet().removeAll( intersect );       
    }

    @Override
    public String toString()
    {
        return new HashMap(this).toString();
    }


}

Usage:用法:

@RequestMapping(value="/login.do", method=RequestMethod.POST)
    public ModelAndView login(@Valid User user){
        ModelAndView mv = new ModelAndView("redirect:result.html");
        if (authService.authenticate(user.getUserName(), user.getPassword()))
            mv.addObject("flashScope.message", "Success");
        //else
            mv.addObject("flashScope.message", "Login Failed");
        return mv;
    }

@RequestMapping(value ="/result.html", method=RequestMethod.GET)
    public ModelAndView result(){
        ModelAndView mv = new ModelAndView("login/loginAction");
        return mv;
    }

In JSP the usage is very simple:在 JSP 中,用法很简单:

${flashScope.message}

In addition you need to configure FlashScopeInterceptor class as interceptor.另外需要配置 FlashScopeInterceptor class 作为拦截器。

<bean id="flashScopeInterceptor" class="x.y.z.FlashScopeInterceptor" />
<bean id="handlerMapping" class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping">
  <property name="interceptors">
    <list><ref bean="flashScopeInterceptor"/></list>
  </property>
</bean> 

I recommend to have a look at the source code of org.springframework.web.context.request.SessionScope .我建议看一下org.springframework.web.context.request.SessionScope的源代码。 This scope must have solved the same problem some how.这个 scope 一定已经解决了同样的问题。

It looks like that they use: RequestContextHolder.currentRequestAttributes().getSessionId()看起来他们使用: RequestContextHolder.currentRequestAttributes().getSessionId()

You can get access to session attributes using the next code within your scope class methods in Spring MVC (works in 3.2):您可以使用 scope class 中的 Z38008DD81C03F4D7985ECFworks.

RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();
attributes.getAttribute("some key", NativeWebRequest.SCOPE_SESSION);
attributes.setAttribute("some key", YouObject, NativeWebRequest.SCOPE_SESSION);

RequestAttributes implementation (ServletRequestAttributes) internally will call set/getAttribute() methods on current session object. RequestAttributes 实现 (ServletRequestAttributes) 在内部将在当前 session object 上调用 set/getAttribute() 方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM