OFBiz:处理nextRequestResponse

这里的nextRequestResponse是指RequestHandler中doRequest()函数在最后使用的一个变量,doRequest()会依据nextRequestResponse返回不同的响应给请求者。nextRequestResponse有多种不同的类型,不同的类型处理方式也不一样。

第一种类型是request,表明这是一个请求链,递归调用doRequest()处理下一个请求:

// <request-map uri="main">
//     <response name="success" type="request" value="other"/>
// </request-map>

if ("request".equals(nextRequestResponse.type)) {
    // chained request
    doRequest(request, response, nextRequestResponse.value, userLogin, delegator);
}


处理nextRequestResponse时,除了request类型,其它类型都需要执行Postprocessor。Postprocessor不会终止请求过程,如果返回的结果不是success,则以抛出异常的方式处理:

for (ConfigXMLReader.Event event: controllerConfig.getPostprocessorEventList().values()) {
    try {
        String returnString = this.runEvent(request, response, event, requestMap, "postprocessor");
        if (returnString != null && !returnString.equalsIgnoreCase("success")) {
            throw new EventHandlerException("Post-Processor event did not return 'success'.");
        }
    } catch (EventHandlerException e) {
        Debug.logError(e, module);
    }
}


第二种类型是url,表明这是一个URL重定向:

// <request-map uri="main">
//     <response name="success" type="url" value="http://www.baidu.com"/>
// </request-map>

if ("url".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a URL redirect.", module);
    callRedirect(nextRequestResponse.value, response, request);
}

callRedirect()做了两件事,一是将request中可序列化的对象保存到session(这样处理的原因是什么?),二是调用response的sendResponse()执行重定向:

private void callRedirect(String url, HttpServletResponse resp, HttpServletRequest req) throws RequestHandlerException {
    if (Debug.infoOn()) Debug.logInfo("Sending redirect to: [" + url + "], sessionId=" + UtilHttp.getSessionId(req), module);
    
    // set the attributes in the session so we can access it.
    // 将request中可序列化的属性保存到session
    Enumeration<String> attributeNameEnum = UtilGenerics.cast(req.getAttributeNames());
    Map<String, Object> reqAttrMap = FastMap.newInstance();
    while (attributeNameEnum.hasMoreElements()) {
        String name = attributeNameEnum.nextElement();
        Object obj = req.getAttribute(name);
        if (obj instanceof Serializable) {
            reqAttrMap.put(name, obj);
        }
    }
    if (reqAttrMap.size() > 0) {
        // RequestHandler is not serializable and must be removed first.
        reqAttrMap.remove("_REQUEST_HANDLER_");  
        byte[] reqAttrMapBytes = UtilObject.getBytes(reqAttrMap);
        if (reqAttrMapBytes != null) {
            req.getSession().setAttribute("_REQ_ATTR_MAP_", StringUtil.toHexString(reqAttrMapBytes));
        }
    }

    // send the redirect
    // 响应重定向
    try {
        resp.sendRedirect(url);
    } catch (IOException ioe) {
        throw new RequestHandlerException(ioe.getMessage(), ioe);
    } catch (IllegalStateException ise) {
        throw new RequestHandlerException(ise.getMessage(), ise);
    }
}


第三种类型是cross-request,表明这是一个跨应用(Cross Application)重定向。什么是跨应用重定向?例如,如果当前请求的是http://localhost:8080/practice/control/main,跨应用重定向后的地址就是http://localhost:8080/other。这里的practice就是一个应用,other是另外一个应用。

// <request-map uri="main">
//     <response name="success" type="cross-request" value="other"/>
// </request-map>

if ("cross-redirect".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a Cross-Application redirect.", module);
    String url = nextRequestResponse.value.startsWith("/") ? nextRequestResponse.value : "/" + nextRequestResponse.value;
    callRedirect(url + this.makeQueryString(request, nextRequestResponse), response, request);
}

makeQueryString()处理重定向后的请求参数。请求参数有两个来源,一是当前request对象的QueryString,二是nextRequestResponse的redirect-parameter。

public String makeQueryString(HttpServletRequest request, ConfigXMLReader.RequestResponse requestResponse) {
    if (requestResponse == null ||
            (requestResponse.redirectParameterMap.size() == 0 && requestResponse.redirectParameterValueMap.size() == 0)) {
        Map<String, Object> urlParams = UtilHttp.getUrlOnlyParameterMap(request);
        String queryString = UtilHttp.urlEncodeArgs(urlParams, false);
        if(UtilValidate.isEmpty(queryString)) {
            return queryString;
        }
        return "?" + queryString;
    } else {
        // redirect-parameter可以使用value指定具体的参数值, 也可以使用from指定参数值的来源。例如:
        // <request-map uri="main">
        //     <response name="success" type="cross-request" value="other">
        //         <request-parameter name="foo" value="xxx"/>
        //         <request-parameter name="bar" from="jsessionid"/>
        //     </response>
        // </request-map>
    
        StringBuilder queryString = new StringBuilder();
        queryString.append("?");
        for (Map.Entry<String, String> entry: requestResponse.redirectParameterMap.entrySet()) {
            String name = entry.getKey();
            String from = entry.getValue();

            Object value = request.getAttribute(from);
            if (value == null) {
                value = request.getParameter(from);
            }

            addNameValuePairToQueryString(queryString, name, (String) value);
        }
        for (Map.Entry<String, String> entry: requestResponse.redirectParameterValueMap.entrySet()) {
            String name = entry.getKey();
            String value = entry.getValue();

            addNameValuePairToQueryString(queryString, name, (String) value);
        }
        return queryString.toString();
    }
}


第四种类型是request-redirect,表明这是一个请求重定向。什么是请求重定向?例如,如果当前请求的是http://localhost:8080/practice/control/main,请求重定向后的地址就是http://localhost:8080/practice/control/other,都是在同一个应用practice里面。

// <request-map uri="main">
//     <response name="success" type="request-request" value="other"/>
// </request-map>

if ("request-redirect".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a Request redirect.", module);
    callRedirect(makeLinkWithQueryString(request, response, "/" + nextRequestResponse.value, nextRequestResponse), response, request);
}

makeLinkWithQueryString()是在makeQueryString()基础上增加了makeLink()的调用:

public String makeLinkWithQueryString(HttpServletRequest request, HttpServletResponse response, String url, ConfigXMLReader.RequestResponse requestResponse) {
    String initialLink = this.makeLink(request, response, url);
    String queryString = this.makeQueryString(request, requestResponse);
    return initialLink + queryString;
}

public String makeLink(HttpServletRequest request, HttpServletResponse response, String url) {
    return makeLink(request, response, url, false, false, true);
}

public String makeLink(HttpServletRequest request, HttpServletResponse response, String url, boolean fullPath, boolean secure, boolean encode) {
    Delegator delegator = (Delegator) request.getAttribute("delegator");
    String webSiteId = WebSiteWorker.getWebSiteId(request);

    String httpsPort = null;
    String httpsServer = null;
    String httpPort = null;
    String httpServer = null;
    Boolean enableHttps = null;

    // load the properties from the website entity
    GenericValue webSite;
    if (webSiteId != null) {
        try {
            webSite = delegator.findByPrimaryKeyCache("WebSite", UtilMisc.toMap("webSiteId", webSiteId));
            if (webSite != null) {
                httpsPort = webSite.getString("httpsPort");
                httpsServer = webSite.getString("httpsHost");
                httpPort = webSite.getString("httpPort");
                httpServer = webSite.getString("httpHost");
                enableHttps = webSite.getBoolean("enableHttps");
            }
        } catch (GenericEntityException e) {
            Debug.logWarning(e, "Problems with WebSite entity; using global defaults", module);
        }
    }

    // fill in any missing properties with fields from the global file
    if (UtilValidate.isEmpty(httpsPort)) {
        httpsPort = UtilProperties.getPropertyValue("url.properties", "port.https", "443");
    }
    if (UtilValidate.isEmpty(httpsServer)) {
        httpsServer = UtilProperties.getPropertyValue("url.properties", "force.https.host");
    }
    if (UtilValidate.isEmpty(httpPort)) {
        httpPort = UtilProperties.getPropertyValue("url.properties", "port.http", "80");
    }
    if (UtilValidate.isEmpty(httpServer)) {
        httpServer = UtilProperties.getPropertyValue("url.properties", "force.http.host");
    }
    if (enableHttps == null) {
        enableHttps = UtilProperties.propertyValueEqualsIgnoreCase("url.properties", "port.https.enabled", "Y");
    }

    // create the path the the control servlet
    String controlPath = (String) request.getAttribute("_CONTROL_PATH_");

    String requestUri = RequestHandler.getRequestUri(url);
    ConfigXMLReader.RequestMap requestMap = null;
    if (requestUri != null) {
        requestMap = getControllerConfig().getRequestMapMap().get(requestUri);
    }

    StringBuilder newURL = new StringBuilder();

    boolean didFullSecure = false;
    boolean didFullStandard = false;
    if (requestMap != null && (enableHttps || fullPath || secure)) {
        if (Debug.verboseOn()) Debug.logVerbose("In makeLink requestUri=" + requestUri, module);
        if (secure || (enableHttps && requestMap.securityHttps && !request.isSecure())) {
            String server = httpsServer;
            if (UtilValidate.isEmpty(server)) {
                server = request.getServerName();
            }

            newURL.append("https://");
            newURL.append(server);
            if (!httpsPort.equals("443")) {
                newURL.append(":").append(httpsPort);
            }

            didFullSecure = true;
        } else if (fullPath || (enableHttps && !requestMap.securityHttps && request.isSecure())) {
            String server = httpServer;
            if (UtilValidate.isEmpty(server)) {
                server = request.getServerName();
            }

            newURL.append("http://");
            newURL.append(server);
            if (!httpPort.equals("80")) {
                newURL.append(":").append(httpPort);
            }

            didFullStandard = true;
        }
    }

    newURL.append(controlPath);

    // now add the actual passed url, but if it doesn't start with a / add one first
    if (!url.startsWith("/")) {
        newURL.append("/");
    }
    newURL.append(url);

    String encodedUrl;
    if (encode) {
        boolean forceManualJsessionid = "false".equals(getServletContext().getInitParameter("cookies")) ? true : false;
        boolean isSpider = false;

        // if the current request comes from a spider, we will not add the jsessionid to the link
        if (UtilHttp.checkURLforSpiders(request)) {
            isSpider = true;
        }

        // if this isn't a secure page, but we made a secure URL, make sure we manually add the jsessionid since the response.encodeURL won't do that
        if (!request.isSecure() && didFullSecure) {
            forceManualJsessionid = true;
        }

        // if this is a secure page, but we made a standard URL, make sure we manually add the jsessionid since the response.encodeURL won't do that
        if (request.isSecure() && didFullStandard) {
            forceManualJsessionid = true;
        }

        if (response != null && !forceManualJsessionid && !isSpider) {
            encodedUrl = response.encodeURL(newURL.toString());
        } else {
            if (!isSpider) {
                String sessionId = ";jsessionid=" + request.getSession().getId();
                // this should be inserted just after the "?" for the parameters, if there is one, or at the end of the string
                int questionIndex = newURL.indexOf("?");
                if (questionIndex == -1) {
                    newURL.append(sessionId);
                } else {
                    newURL.insert(questionIndex, sessionId);
                }
            }
            if (response != null) {
                encodedUrl = response.encodeURL(newURL.toString());
            } else {
                encodedUrl = newURL.toString();    
            }
        }
    } else {
        encodedUrl = newURL.toString();
    }
    //if (encodedUrl.indexOf("null") > 0) {
        //Debug.logError("in makeLink, controlPath:" + controlPath + " url:" + url, "");
        //throw new RuntimeException("in makeLink, controlPath:" + controlPath + " url:" + url);
    //}

    //Debug.logInfo("Making URL, encode=" + encode + " for URL: " + newURL + "
 encodedUrl: " + encodedUrl, module);

    return encodedUrl;
}

 
第五种类型是request-redirect-noparam,表明这也是一个请求重定向,类似request-redirect,但是不需要带上参数。参数可能是当前请求的QueryString,也有可能是redirect-parameter。

// <request-map uri="main">
//     <response name="success" type="request-request-noparam" value="other"/>
// </request-map>

if ("request-redirect-noparam".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a Request redirect with no parameters.", module);
    callRedirect(makeLink(request, response, nextRequestResponse.value), response, request);
}


第六种类型是view,表明这是一个视图。视图需要在controller.xml中用view-map定义。

// <request-map uri="main">
//     <response name="success" type="view" value="main"/>
// </request-map>

if ("view".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a view.", module);

    // check for an override view, only used if "success" = eventReturn
    String viewName = (UtilValidate.isNotEmpty(overrideViewUri) && (eventReturn == null || "success".equals(eventReturn))) ? overrideViewUri : nextRequestResponse.value;
    renderView(viewName, requestMap.securityExternalView, request, response, saveName);
}


第七种类型是view-last。

// <request-map uri="main">
//     <response name="success" type="view-last" value="news"/>
// </request-map>

if ("view-last".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a view.", module);

    // check for an override view, only used if "success" = eventReturn
    String viewName = (UtilValidate.isNotEmpty(overrideViewUri) && (eventReturn == null || "success".equals(eventReturn))) ? overrideViewUri : nextRequestResponse.value;

    // as a further override, look for the _SAVED and then _HOME and then _LAST session attributes
    Map<String, Object> urlParams = null;
    if (session.getAttribute("_SAVED_VIEW_NAME_") != null) {
        viewName = (String) session.getAttribute("_SAVED_VIEW_NAME_");
        urlParams = UtilGenerics.<String, Object>checkMap(session.getAttribute("_SAVED_VIEW_PARAMS_"));
    } else if (session.getAttribute("_HOME_VIEW_NAME_") != null) {
        viewName = (String) session.getAttribute("_HOME_VIEW_NAME_");
        urlParams = UtilGenerics.<String, Object>checkMap(session.getAttribute("_HOME_VIEW_PARAMS_"));
    } else if (session.getAttribute("_LAST_VIEW_NAME_") != null) {
        viewName = (String) session.getAttribute("_LAST_VIEW_NAME_");
        urlParams = UtilGenerics.<String, Object>checkMap(session.getAttribute("_LAST_VIEW_PARAMS_"));
    } else if (UtilValidate.isNotEmpty(nextRequestResponse.value)) {
        viewName = nextRequestResponse.value;
    }
    if (urlParams != null) {
        for (Map.Entry<String, Object> urlParamEntry: urlParams.entrySet()) {
            String key = urlParamEntry.getKey();
            // Don't overwrite messages coming from the current event
            if (!("_EVENT_MESSAGE_".equals(key) || "_ERROR_MESSAGE_".equals(key)
                    || "_EVENT_MESSAGE_LIST_".equals(key) || "_ERROR_MESSAGE_LIST_".equals(key))) {
                request.setAttribute(key, urlParamEntry.getValue());
            }
        }
    }
    renderView(viewName, requestMap.securityExternalView, request, response, null);
}


第八种类型是view-last-noparam。

// <request-map uri="main">
//     <response name="success" type="view-last-noparam" value="news"/>
// </request-map>

if ("view-last-noparam".equals(nextRequestResponse.type)) {
     if (Debug.verboseOn()) 
         Debug.logVerbose("[RequestHandler.doRequest]: Response is a view.", module);

     // check for an override view, only used if "success" = eventReturn
     String viewName = (UtilValidate.isNotEmpty(overrideViewUri) && (eventReturn == null || "success".equals(eventReturn))) ? overrideViewUri : nextRequestResponse.value;

     // as a further override, look for the _SAVED and then _HOME and then _LAST session attributes
     if (session.getAttribute("_SAVED_VIEW_NAME_") != null) {
         viewName = (String) session.getAttribute("_SAVED_VIEW_NAME_");
     } else if (session.getAttribute("_HOME_VIEW_NAME_") != null) {
         viewName = (String) session.getAttribute("_HOME_VIEW_NAME_");
     } else if (session.getAttribute("_LAST_VIEW_NAME_") != null) {
         viewName = (String) session.getAttribute("_LAST_VIEW_NAME_");
     } else if (UtilValidate.isNotEmpty(nextRequestResponse.value)) {
         viewName = nextRequestResponse.value;
     }
     renderView(viewName, requestMap.securityExternalView, request, response, null);
}


第九种类型是view-home。

// <request-map uri="main">
//     <response name="success" type="view-home" value="news"/>
// </request-map>

if ("view-home".equals(nextRequestResponse.type)) {
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is a view.", module);

    // check for an override view, only used if "success" = eventReturn
    String viewName = (UtilValidate.isNotEmpty(overrideViewUri) && (eventReturn == null || "success".equals(eventReturn))) ? overrideViewUri : nextRequestResponse.value;

    // as a further override, look for the _HOME session attributes
    Map<String, Object> urlParams = null;
    if (session.getAttribute("_HOME_VIEW_NAME_") != null) {
        viewName = (String) session.getAttribute("_HOME_VIEW_NAME_");
        urlParams = UtilGenerics.<String, Object>checkMap(session.getAttribute("_HOME_VIEW_PARAMS_"));
    }
    if (urlParams != null) {
        for (Map.Entry<String, Object> urlParamEntry: urlParams.entrySet()) {
            request.setAttribute(urlParamEntry.getKey(), urlParamEntry.getValue());
        }
    }
    renderView(viewName, requestMap.securityExternalView, request, response, null);
}


第十种类型是none,表明不返回任何响应内容。

// <request-map uri="main">
//     <response name="success" type="none"/>
// </request-map>

if ("none".equals(nextRequestResponse.type)) {
    // no view to render (meaning the return was processed by the event)
    if (Debug.verboseOn()) 
        Debug.logVerbose("[RequestHandler.doRequest]: Response is handled by the event.", module);
}
原文地址:https://www.cnblogs.com/eastson/p/3584621.html