刨根问底-struts-http请求的预处理

刨根问底-struts-http请求的预处理_第1张图片

FilterDispatcher是struts2的核心控制器,每个请求都会进入FilterDispatcher对象的doFilter()方法。然后再struts.xml文件中根据action的name属性进行匹配,找到要执行的action类和方法,执行完方法返回结果。

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        ServletContext servletContext = getServletContext();

        String timerKey = "FilterDispatcher_doFilter: ";
        try {

            // FIXME: this should be refactored better to not duplicate work with the action invocation
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            ActionContext ctx = new ActionContext(stack.getContext());
            ActionContext.setContext(ctx);

            UtilTimerStack.push(timerKey);
            request = prepareDispatcherAndWrapRequest(request, response);
            ActionMapping mapping;
            try {//根据url取得对应的Action的配置信息      //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存储在 ActionMapping对象中                                            mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
            } catch (Exception ex) {
                log.error("error getting ActionMapping", ex);
                dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
                return;
            } //如果找不到对应的action配置,则直接返回。比如你输入***.jsp等 if (mapping == null) {
                // there is no action in this request, should we look for a static resource?
                String resourcePath = RequestUtils.getServletPath(request);

                if ("".equals(resourcePath) && null != request.getPathInfo()) {
                    resourcePath = request.getPathInfo();
                }

                if (staticResourceLoader.canHandle(resourcePath)) {
                    staticResourceLoader.findStaticResource(resourcePath, request, response);
                } else {
                    // this is a normal request, let it pass through
                    chain.doFilter(request, response);
                }
                // The framework did its job here
                return;
            } //正式开始Action的方法           后面详细解释                                                 dispatcher.serviceAction(request, response, servletContext, mapping);

        } finally {
            dispatcher.cleanUpRequest(request);
            try {
                ActionContextCleanUp.cleanUp(req);
            } finally {
                UtilTimerStack.pop(timerKey);
            }
            devModeOverride.remove();
        }
    }

由于这个doFilter()是重点,主要是3个功能:

(1)encoding和Local是web页面上的重要属性,也是web程序进行国际化il8n处理的核心参数。prepareDispatcherAndWrapRequest()设置encoding和Local参数。并对httpServletRequest进行一定的封装

(2)ActionContext的创建总是伴随着valueStack的创建。valueStackFactory负责创建valueStack,并为valueStack设置上下文环境;紧接着valueStack创建的就是ActionContext,并且ActionContext的创建以valueStack的上下文环境作为参数。

valueStack的上下文环境与ActionContext的数据存储空间是等同的。代码证明:  ctx = new ActionContext(stack.getContext());

(3)解析请求url,并且把值赋值给ActionMapping对象

(4)serviceAction执行action

现在我们就重点分析解析url,serviceAction执行action后面再详细分析

2、getMapping()方法:ActionMapper接口的实现类 DefaultActionMapper的getMapping()

  /*
     * (non-Javadoc)
     *
     * @see org.apache.struts2.dispatcher.mapper.ActionMapper#getMapping(javax.servlet.http.HttpServletRequest)
     */

    public ActionMapping getMapping(HttpServletRequest request,
                                    ConfigurationManager configManager) {
        ActionMapping mapping = new ActionMapping();//创建一个ActionMapping
        String uri = getUri(request);//得到请求路径的URI,如:login.action                         int indexOfSemicolon = uri.indexOf(";");//修正url的带;jsessionid                          uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;

        uri = dropExtension(uri, mapping);//删除扩展名,默认扩展名为action                         if (uri == null) {
            return null;
        }

        parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace     handleSpecialParameters(request, mapping);//去掉特殊参数                                      //如果Action的name没有解析出来,直接返回                                                     if (mapping.getName() == null) {
            return null;
        }

        parseActionName(mapping);//主要是处理name!add 格式的解析

        return mapping;
    }

    protected ActionMapping parseActionName(ActionMapping mapping) {
        if (mapping.getName() == null) {
            return mapping;
        }
        if (allowDynamicMethodCalls) {
            // handle "name!method" convention.
            String name = mapping.getName();
            int exclamation = name.lastIndexOf("!");
            if (exclamation != -1) {
                mapping.setName(name.substring(0, exclamation));//提取左边为name  mapping.setMethod(name.substring(exclamation + 1));//提取右边的method }
        }
        return mapping;
    }

注释:getMapping()方法返回ActionMapping类型的对象,该对象包含三个参数:Action的name、namespace和要调用的方法method

2.1查看ActionMapping对象:里面有name等等属性

public class ActionMapping {

    private String name;
    private String namespace;
    private String method;
    private String extension;
    private Map<String, Object> params;
    private Result result;

}
2.2getUri(request)获取请求路径:


  /**
     * Gets the uri from the request
     *
     * @param request The request
     * @return The uri
     */
    protected String getUri(HttpServletRequest request) {
        // handle http dispatcher includes.
        String uri = (String) request
                .getAttribute("javax.servlet.include.servlet_path");
        if (uri != null) {
            return uri;
        }

        uri = RequestUtils.getServletPath(request);
        if (uri != null && !"".equals(uri)) {
            return uri;
        }

        uri = request.getRequestURI();
        return uri.substring(request.getContextPath().length());
    }
注释:request.getContextPath() 其作用是获取当前的系统路径


我做了一个测试,先看看打印结果:

uRequestUtils.getServletPath(request) = /skip.action
request.getRequestURI()  = /gaokao/skip.action
request.getContextPath() = /gaokao

不难看出getUri(request)是为了获得请求路径 /skip.action

2.3、dropExtension(uri, mapping)删除扩展名

  protected List<String> extensions = new ArrayList<String>() {{
        add("action");
        add("");
    }};
protected String dropExtension(String name, ActionMapping mapping) {
        if (extensions == null) {
            return name;
        }
        for (String ext : extensions) {
            if ("".equals(ext)) {  int index = name.lastIndexOf('.');
                if (index == -1 || name.indexOf('/', index) >= 0) {
                    return name;
                }
            } else {//删除扩展名.action
                String extension = "." + ext;
                if (name.endsWith(extension)) {
                    name = name.substring(0, name.length() - extension.length());
                    mapping.setExtension(ext);
                    return name;
                }
            }
        }
        return null;
    }

extensions中默认的保存了action,其他事怎么加入的呢?

@Inject(StrutsConstants.STRUTS_ACTION_EXTENSION)
    public void setExtensions(String extensions) {
        if (extensions != null && !"".equals(extensions)) {
            List<String> list = new ArrayList<String>();
            String[] tokens = extensions.split(",");
            for (String token : tokens) {
                list.add(token);
            }
            if (extensions.endsWith(",")) {
                list.add("");
            }
            this.extensions = Collections.unmodifiableList(list);
        } else {
            this.extensions = null;
        }
    }
原来是预处理, 通过注解在初始化的时候赋值,STRUTS_ACTION_EXTENSION = "struts.action.extension"

想想以前在struts.properties文件中设置struts.action.extension=action,原来是这的道理啊,哈哈。

2.4 parseNameAndNamespace(uri, mapping, configManager)从uri中解析出来name和namespace,并且把name和names赋值给mapping。

2.5 handleSpecialParameters(request, mapping)去除特殊参数:

 public void handleSpecialParameters(HttpServletRequest request,
                                        ActionMapping mapping) {
        // handle special parameter prefixes.
        Set<String> uniqueParameters = new HashSet<String>();
        Map parameterMap = request.getParameterMap();
        for (Iterator iterator = parameterMap.keySet().iterator(); iterator
                .hasNext();) {
            String key = (String) iterator.next();

            // Strip off the image button location info, if found
            if (key.endsWith(".x") || key.endsWith(".y")) {
                key = key.substring(0, key.length() - 2);
            }

            // Ensure a parameter doesn't get processed twice
            if (!uniqueParameters.contains(key)) {
                ParameterAction parameterAction = (ParameterAction) prefixTrie
                        .get(key);
                if (parameterAction != null) {
                    parameterAction.execute(key, mapping);
                    uniqueParameters.add(key);
                    break;
                }
            }
        }
    }
注释;主要是去除鼠标参数,横竖坐标。









你可能感兴趣的:(刨根问底-struts-http请求的预处理)