struts2 type="redirect"源码解析
cookqq ›博客列表 ›struts

struts2 type="redirect"源码解析

2012-06-01 17:37:51.0|分类: struts|浏览量: 1915

摘要: 首先解释一下几个名词: request.getRequestDispatcher()是请求转发,前后页面共享一个request ;  response.sendRedirect()是重新定向,前后页面不是一个request。 RequestDispatcher.forward()是在服务器端运行;&...

首先解释一下几个名词:

request.getRequestDispatcher()是请求转发,前后页面共享一个request ; 

response.sendRedirect()是重新定向,前后页面不是一个request。

RequestDispatcher.forward()是在服务器端运行; 

HttpServletResponse.sendRedirect()是通过向客户浏览器发送命令来完成. 

所以RequestDispatcher.forward()对于浏览器来说是“透明的”; 

而HttpServletResponse.sendRedirect()则不是。

这么光说,一定很难理解,看一个例子。

情景:qq登录上,你直接点击邮箱他就会直接登录邮箱。

假如请求路径:http://localhost:8080/test/web/skiplogin.action?url=/mail/productManage.action&sessionid=1000111&&phoneId=100000

action中会把url,sessionid,phoneId解析出来,然后跳转到url,假如你是用的是

RequestDispatcher dispatcher = request.getRequestDispatcher(url_pa);
//			dispatcher.forward(request, response);
//			使用这个方法转发,地址不变,这是在服务器端完成的

浏览器上的地址栏里的路径是不会变的。

假如使用response.sendRedirect(basePath+finalLocation);

浏览器上的路径就会变成:http://localhost:8080/test/mail/productManage.action。

struts2 result返回类型type="redirect"时,查看它的源代码其实就是做了一次重新跳转。

 * $Id: ServletRedirectResult.java 1188965 2011-10-25 23:19:48Z mcucchiara $

package org.apache.struts2.dispatcher;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.opensymphony.xwork2.util.reflection.ReflectionException;
import com.opensymphony.xwork2.util.reflection.ReflectionExceptionHandler;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.mapper.ActionMapper;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import org.apache.struts2.views.util.UrlHelper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

import static javax.servlet.http.HttpServletResponse.SC_FOUND;

/**
 * <!-- START SNIPPET: description -->
 * 
 * Calls the {@link  HttpServletResponse#sendRedirect(String) sendRedirect}
 * method to the location specified. The response is told to redirect the
 * browser to the specified location (a new request from the client). The
 * consequence of doing this means that the action (action instance, action
 * errors, field errors, etc) that was just executed is lost and no longer
 * available. This is because actions are built on a single-thread model. The
 * only way to pass data is through the session or with web parameters
 * (url?name=value) which can be OGNL expressions.
 * 
 * <!-- END SNIPPET: description -->
 * <p/>
 * <b>This result type takes the following parameters:</b>
 * 
 * <!-- START SNIPPET: params -->
 * 
 * <ul>
 * 
 * <li><b>location (default)</b> - the location to go to after execution.</li>
 * 
 * <li><b>parse</b> - true by default. If set to false, the location param will
 * not be parsed for Ognl expressions.</li>
 * 
 * <li><b>anchor</b> - Optional.  Also known as "fragment" or colloquially as 
 * "hash".  You can specify an anchor for a result.</li>
 * </ul>
 * 
 * <p>
 * This result follows the same rules from {@link  StrutsResultSupport}.
 * </p>
 * 
 * <!-- END SNIPPET: params -->
 * 
 * <b>Example:</b>
 * 
 * <pre>
 * <!-- START SNIPPET: example -->
 * &lt;!--
 *   The redirect URL generated will be:
 *   /foo.jsp#FRAGMENT
 * --&gt;
 * &lt;result name="success" type="redirect"&gt;
 *   &lt;param name="location"&gt;foo.jsp&lt;/param&gt;
 *   &lt;param name="parse"&gt;false&lt;/param&gt;
 *   &lt;param name="anchor"&gt;FRAGMENT&lt;/param&gt;
 * &lt;/result&gt;
 * <!-- END SNIPPET: example -->
 * </pre>
 * 
 */
public class ServletRedirectResult extends StrutsResultSupport implements ReflectionExceptionHandler {

    private static final long serialVersionUID = 6316947346435301270L;

    private static final Logger LOG = LoggerFactory.getLogger(ServletRedirectResult.class);

    protected boolean prependServletContext = true;

    protected ActionMapper actionMapper;

    protected int statusCode = SC_FOUND;

    protected boolean suppressEmptyParameters = false;

    protected Map<String, String> requestParameters = new LinkedHashMap<String, String>();

    protected String anchor;

    public ServletRedirectResult() {
        super();
    }

    public ServletRedirectResult(String location) {
        this(location, null);
    }

    public ServletRedirectResult(String location, String anchor) {
        super(location);
        this.anchor = anchor;
    }

    @Inject
    public void setActionMapper(ActionMapper mapper)
    {
        this.actionMapper = mapper;
    }

    public void setStatusCode(int code)
    {
        this.statusCode = code;
    }

    /**
     * Set the optional anchor value.
     * 
     * @param anchor
     */
    public void setAnchor(String anchor)
    {
        this.anchor = anchor;
    }

    /**
     * Sets whether or not to prepend the servlet context path to the redirected
     * URL.
     * 
     * @param prependServletContext
     *            <tt>true</tt> to prepend the location with the servlet context
     *            path, <tt>false</tt> otherwise.
     */
    public void setPrependServletContext(boolean prependServletContext)
    {
        this.prependServletContext = prependServletContext;
    }

    public void execute(ActionInvocation invocation) throws Exception
    {
        if (anchor != null)
        {
            anchor = conditionalParse(anchor, invocation);
        }

        super.execute(invocation);
    }

    /**
     * Redirects to the location specified by calling
     * {@link  HttpServletResponse#sendRedirect(String)}.
     * 
     * @param finalLocation
     *            the location to redirect to.
     * @param invocation
     *            an encapsulation of the action execution state.
     * @throws Exception
     *             if an error occurs when redirecting.
     */
    protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception
    {
        ActionContext ctx = invocation.getInvocationContext();
        HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);

        if (isPathUrl(finalLocation))
        {
            if (!finalLocation.startsWith("/"))
            {
                ActionMapping mapping = actionMapper.getMapping(request, Dispatcher.getInstance().getConfigurationManager());
                String namespace = null;
                if (mapping != null)
                {
                    namespace = mapping.getNamespace();
                }

                if ((namespace != null) && (namespace.length() > 0) && (!"/".equals(namespace)))
                {
                    finalLocation = namespace + "/" + finalLocation;
                }
                else
                {
                    finalLocation = "/" + finalLocation;
                }
            }

            // if the URL's are relative to the servlet context, append the servlet context path
            if (prependServletContext && (request.getContextPath() != null) && (request.getContextPath().length() > 0))
            {
                finalLocation = request.getContextPath() + finalLocation;
            }

            ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(invocation.getResultCode());
            if (resultConfig != null)
            {
                Map<String, String> resultConfigParams = resultConfig.getParams();

                for (Map.Entry<String, String> e : resultConfigParams.entrySet())
                {
                    if (!getProhibitedResultParams().contains(e.getKey()))
                    {
                        String potentialValue = e.getValue() == null ? "" : conditionalParse(e.getValue(), invocation);
                        if (!suppressEmptyParameters || ((potentialValue != null) && (potentialValue.length() > 0)))
                        {
                            requestParameters.put(e.getKey(), potentialValue);
                        }
                    }
                }
            }

            StringBuilder tmpLocation = new StringBuilder(finalLocation);
            UrlHelper.buildParametersString(requestParameters, tmpLocation, "&");

            // add the anchor
            if (anchor != null)
            {
                tmpLocation.append('#').append(anchor);
            }

            finalLocation = response.encodeRedirectURL(tmpLocation.toString());
        }

        if (LOG.isDebugEnabled())
        {
            LOG.debug("Redirecting to finalLocation " + finalLocation);
        }

        sendRedirect(response, finalLocation);//////看这个方法
    }

    protected List<String> getProhibitedResultParams()
    {
        return Arrays.asList(DEFAULT_PARAM, "namespace", "method", "encode", "parse", "location", "prependServletContext", "suppressEmptyParameters", "anchor");
    }

    /**
     * Sends the redirection. Can be overridden to customize how the redirect is
     * handled (i.e. to use a different status code)
     * 
     * @param response
     *            The response
     * @param finalLocation
     *            The location URI
     * @throws IOException
     */
    protected void sendRedirect(HttpServletResponse response, String finalLocation) throws IOException
    {
        if (SC_FOUND == statusCode)
        {
            response.sendRedirect(finalLocation);//就是做了一个这样的事情
        }
        else
        {
            response.setStatus(statusCode);
            response.setHeader("Location", finalLocation);
            response.getWriter().write(finalLocation);
            response.getWriter().close();
        }

    }

    private static boolean isPathUrl(String url)
    {
        // filter out "http:", "https:", "mailto:", "file:", "ftp:"
        // since the only valid places for : in URL's is before the path specification
        // either before the port, or after the protocol
        return (url.indexOf(':') == -1);
    }

    /**
     * Sets the suppressEmptyParameters option
     * 
     * @param suppressEmptyParameters
     *            The new value for this option
     */
    public void setSuppressEmptyParameters(boolean suppressEmptyParameters)
    {
        this.suppressEmptyParameters = suppressEmptyParameters;
    }

    /**
     * Adds a request parameter to be added to the redirect url
     * 
     * @param key
     *            The parameter name
     * @param value
     *            The parameter value
     */
    public ServletRedirectResult addParameter(String key, Object value)
    {
        requestParameters.put(key, String.valueOf(value));
        return this;
    }

    public void handle(ReflectionException ex)
    {
        // Only log as debug as they are probably parameters to be appended to the url
        LOG.debug(ex.getMessage(), ex);
    }
}

 我action中写的代码:

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


@SuppressWarnings("serial")
public class SkipLoginAction extends Action {
	
	@Inject
	private PhoneService phoneService;
	/**
	 * @return 
	 * @throws ActionException
	 */
	public void index() throws ActionException {
		try {
			HttpServletRequest request =getRequest();
			HttpServletResponse response =  getResponse();
			AuthBean authBean = null;
//			RequestDispatcher dispatcher = request.getRequestDispatcher(url_pa);
//			dispatcher.forward(request, response);
//			使用这个方法转发,地址不变,这是在服务器端完成的
			
			//客户端传来的参数
			String sessionid =  request.getParameter("sessionid");
			String finalLocation = request.getParameter("url");
			String phoneId =  request.getParameter("phoneId");
			
			String contextpath = request.getContextPath();
			String basePath = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + contextpath;

			if(!StringUtils.isBlank(finalLocation) && !StringUtils.isBlank(sessionid) ){
				
				if(!finalLocation.startsWith("/")){
					finalLocation = "/" + finalLocation;
				}
				
				HttpSession session = request.getSession();
				authBean = getAuthBean();
				if(authBean!=null){
					if(phoneId.equals(authBean.getPhoneId())){
						response.sendRedirect(basePath+finalLocation);
						return;
					}
				}
				////获得数据库中的user中的sessionid字段
				Phone phone = phoneService.findPhoneByPhoneId(phoneId);
				if(phone!=null){
					if( sessionid.equals(phone.getSessionid())){
						// 用户登陆成功
						authBean = null;
						authBean = new AuthBean();
						。。。。
						response.sendRedirect(basePath+finalLocation);
						return;
					}
				}
			}
			//最后不符合条件统一跳到登陆界面
			finalLocation = "/web/login.index";
			response.sendRedirect(basePath+finalLocation);
		} catch (Exception e) {
			throw new ActionException("失败");
		}
	}
}

 

 

 

 

 

 

 

 

一键分享文章

分类列表

  • • struts源码分析
  • • flink
  • • struts
  • • redis
  • • kafka
  • • ubuntu
  • • zookeeper
  • • hadoop
  • • activiti
  • • linux
  • • 成长
  • • NIO
  • • 关键词提取
  • • mysql
  • • android studio
  • • zabbix
  • • 云计算
  • • mahout
  • • jmeter
  • • hive
  • • ActiveMQ
  • • lucene
  • • MongoDB
  • • netty
  • • flume
  • • 我遇到的问题
  • • GRUB
  • • nginx
  • • 大家好的文章
  • • android
  • • tomcat
  • • Python
  • • luke
  • • android源码编译
  • • 安全
  • • MPAndroidChart
  • • swing
  • • POI
  • • powerdesigner
  • • jquery
  • • html
  • • java
  • • eclipse
  • • shell
  • • jvm
  • • highcharts
  • • 设计模式
  • • 列式数据库
  • • spring cloud
  • • docker+node.js+zookeeper构建微服务
版权所有 cookqq 感谢访问 支持开源 京ICP备15030920号
CopyRight 2015-2018 cookqq.com All Right Reserved.