【仅供内部供应商使用,不提供对外解答和培训】

Page tree

【仅供内部供应商使用,不提供对外解答和培训】

Skip to end of metadata
Go to start of metadata

You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 2 Next »

一、特殊名词介绍

二、接口/方法/对象源码——【FineReport V10 2020-07-18】

WebUtils.java
package com.fr.web.utils;

...

/**
 * 处理web页面事务的工具类
 */
public class WebUtils {

    private WebUtils() {

    }


    /**
     * 获取HTTP请求中指定名字的参数值
     *
     * @param req      HTTP请求
     * @param paraName 参数名
     * @return 参数值
     */
    public static String getHTTPRequestParameter(HttpServletRequest req, String paraName) {
        return NetworkHelper.getHTTPRequestParameter(req, paraName);
    }

    /**
     * 获取第一个不为空的参数
     *
     * @param req       HTTP请求
     * @param paraNames 参数列表
     * @return 参数值
     */
    public static String getHTTPRequestParameter(HttpServletRequest req, String... paraNames) {
        return NetworkHelper.getHTTPRequestParameter(req, paraNames);
    }

    /**
     * 把HTTP请求中指定名字的参数值转化为布尔值
     *
     * @param req      HTTP请求
     * @param paraName 参数名
     * @return
     */
    public static boolean getHTTPRequestBoolParameter(HttpServletRequest req, String paraName) {
        return NetworkHelper.getHTTPRequestBoolParameter(req, paraName);
    }

    /**
     * 把HTTP请求中指定名字的参数值转化为整数,参数为空或不是整数则返回-1
     *
     * @param req      HTTP请求
     * @param paraName 参数名
     * @return
     */
    public static int getHTTPRequestIntParameter(HttpServletRequest req, String paraName) {
        return getHTTPRequestIntParameter(req, paraName, -1);
    }

    /**
     * 把HTTP请求中指定名字的参数值转化为整数
     *
     * @param req          HTTP请求
     * @param paraName     参数名
     * @param defaultValue 默认值
     * @return 返回req中参数的整数值。参数为空或不是整数则返回defaultValue
     */
    public static int getHTTPRequestIntParameter(HttpServletRequest req, String paraName, int defaultValue) {
        return NetworkHelper.getHTTPRequestIntParameter(req, paraName, defaultValue);
    }

    /**
     * 获取模板的显示标题
     *
     * @param req HTTP请求
     * @return 模板在浏览器上显示的标题
     */
    public static String getReportTitleFromRequest(HttpServletRequest req) {
        String title = WebUtils.getHTTPRequestParameter(req, ParameterConstants.VIEWLET);

        if (title == null) {
            title = WebUtils.getHTTPRequestParameter(req, ParameterConstants.VIEWLETS);
        }

        if (title == null) {
            title = WebUtils.getHTTPRequestParameter(req, ParameterConstants.REPORTLET);
        }

        if (title == null) {
            title = WebUtils.getHTTPRequestParameter(req, ParameterConstants.REPORTLETS);
        }

        if (title == null) {
            title = WebUtils.getHTTPRequestParameter(req, ParameterConstants.RESULTLET);
        }

        return title;
    }

    /**
     * 生成一个访问Servelt的相对路径
     *
     * @param req HTTP请求
     * @return URL路径
     */
    public static String createServletURL(HttpServletRequest req) {
        return NetworkHelper.createServletURL(req);
    }

    /**
     * 生成一个打印输出器
     *
     * @param res HTTP响应
     * @return 打印输出器
     * @throws IOException
     */
    public static PrintWriter createPrintWriter(HttpServletResponse res) throws IOException {
        return NetworkHelper.createPrintWriter(res);
    }

    /**
     * 输出到前端的JSON格式的信息
     *
     * @param req  HTTP请求
     * @param res  HTTP响应
     * @param data 输出到前端的信息
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushSuccessMessageAutoClose(HttpServletRequest req, HttpServletResponse res, JSONObject data) throws Exception {
        WebUtils.printAsJSON(res, data);
    }

    /**
     * 输出到前端的JSON数组格式的信息
     *
     * @param req  HTTP请求
     * @param res  HTTP响应
     * @param data 输出到前端的信息
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushSuccessMessageAutoClose(HttpServletRequest req, HttpServletResponse res, JSONArray data) throws Exception {
        WebUtils.printAsJSON(res, data);
    }

    /**
     * 输出到前端的JSON数组格式的信息,需要手动关闭writer
     *
     * @param req    HTTP请求
     * @param res    HTTP响应
     * @param writer 输出字符流
     * @param data   输出到前端的信息
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushSuccessMessage(HttpServletRequest req, HttpServletResponse res, PrintWriter writer, JSONArray data) throws Exception {
        writer.print(data.toString());
    }

    /**
     * 输出到前端的JSON格式的信息,需要手动关闭writer
     *
     * @param req    HTTP请求
     * @param res    HTTP响应
     * @param writer 输出字符流
     * @param data   输出到前端的信息
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushSuccessMessage(HttpServletRequest req, HttpServletResponse res, PrintWriter writer, JSONObject data) throws Exception {
        writer.print(data.toString());
    }

    /**
     * 输出标志失败的信息
     *
     * @param req         HTTP请求
     * @param res         HTTP响应
     * @param errorCode   错误码
     * @param description 错误码描述
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushFailureMessageAutoClose(HttpServletRequest req, HttpServletResponse res, int errorCode, String description) throws Exception {
        flushFailureMessageAutoClose(req, res, errorCode, description, null);
    }

    /**
     * 输出标志失败的信息
     *
     * @param req            HTTP请求
     * @param res            HTTP响应
     * @param errorCode      错误码
     * @param description    错误码描述
     * @param compatibleData 兼容信息
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushFailureMessageAutoClose(HttpServletRequest req, HttpServletResponse res, int errorCode, String description, JSONObject compatibleData) throws Exception {
        if (StringUtils.isEmpty(description)) {
            throw new IllegalArgumentException("The description of error code cannot be empty!");
        }
        WebUtils.printAsJSON(res, generateErrorCodeObject(errorCode, description, compatibleData));
    }

    /**
     * 输出标志失败的信息
     *
     * @param req            HTTP请求
     * @param writer         输出字符流
     * @param errorCode      错误码
     * @param description    错误码描述
     * @param compatibleData 兼容信息
     * @throws Exception 如果输出信息失败则抛出此异常
     */
    public static void flushFailureMessage(HttpServletRequest req, PrintWriter writer, int errorCode, String description, JSONObject compatibleData) throws Exception {
        if (StringUtils.isEmpty(description)) {
            throw new IllegalArgumentException("The description of error code cannot be empty!");
        }
        writer.print(generateErrorCodeObject(errorCode, description, compatibleData).toString());
    }

    private static JSONObject generateErrorCodeObject(int errorCode, String description, JSONObject compatibleData) throws Exception {
        JSONObject data = JSONObject.create().put("errorCode", errorCode).put("errorMsg", description);
        if (compatibleData != null) {
            Iterator it = compatibleData.keys();
            while (it.hasNext()) {
                String key = GeneralUtils.objectToString(it.next());
                data.put(key, compatibleData.get(key));
            }
        }
        return data;
    }

    /**
     * 按指定编码生成打印输出器
     *
     * @param res         HTTP响应
     * @param charsetName 编码
     * @return 打印输出器
     * @throws IOException
     */
    public static PrintWriter createPrintWriter(HttpServletResponse res, String charsetName) throws IOException {
        return NetworkHelper.createPrintWriter(res, charsetName);
    }

    /**
     * 输出JSON类型的字符串
     *
     * @param res HTTP响应
     * @param jo  JSON对象
     * @throws Exception
     */
    public static void printAsJSON(HttpServletResponse res, JSONObject jo) throws Exception {
        printAsString(res, jo.toString());
    }

    /**
     * 输出JSON类型的字符串
     *
     * @param res HTTP响应
     * @param ja  JSON数组对象
     * @throws Exception
     */
    public static void printAsJSON(HttpServletResponse res, JSONArray ja) throws Exception {
        printAsString(res, ja.toString());
    }

    /**
     * 输出字符串,一般来说是JSON格式
     *
     * @param res HTTP响应
     * @param jo  JSON样式的字符串
     * @throws Exception
     */
    public static void printAsString(HttpServletResponse res, String jo) throws Exception {
        PrintWriter pw = WebUtils.createPrintWriter(res);
        pw.print(jo);
        pw.flush();
        pw.close();
    }


    /**
     * 把一个对象变成可转变为JSON对象的值
     *
     * @param object 原对象
     * @return 可转化成JSON对象的值
     * @throws JSONException 异常
     */
    public static Object object2JSONable(Object object) throws JSONException {
        // alex:如果是Date和Image类型的,特别用JSON方式表示一下
        return object2JSONable(object, -1, -1);
    }

    /**
     * 把一个对象变成可转变为JSON对象的值
     *
     * @param object     原对象
     * @param cellwidth  宽度k
     * @param cellheight 高度g
     * @return 可转化成JSON对象的值
     * @throws JSONException 异常
     */
    public static Object object2JSONable(Object object, int cellwidth, int cellheight) throws JSONException {
        if (object instanceof Date) {
            return new JSONObject().put("date_milliseconds", new Long(((Date) object).getTime()));
        } else if (object instanceof Image) {
            if (cellheight > 0 && cellwidth > 0) {
                return AttachmentHelper.addAttachment((Image) object, AttachmentHelper.DEFAULT_IMAGE_FORMAT,
                        cellwidth, cellheight, AttachmentScope.DEFAULT).toConfig();
            } else {
                return AttachmentHelper.addAttachment((Image) object, AttachmentScope.DEFAULT).toConfig();
            }
        } else if (object instanceof Double) {
            if (((Double) object).isInfinite() || ((Double) object).isNaN()) {
                return GeneralUtils.objectToString(object);
            }
        } else if (object instanceof Float) {
            if (((Float) object).isInfinite() || ((Float) object).isNaN()) {
                return GeneralUtils.objectToString(object);
            }
        } else if (object instanceof FArray) {
            return object;
        }
        return JSONHolder.hold(object);
    }

    /**
     * 处理一些指定的模板,主要用于替换一个参数等
     *
     * @param resource 模板的路径
     * @param response HTTP响应
     * @throws IOException
     */
    public static void dealWithTemplate(String resource, HttpServletResponse response) throws IOException {
        writeOutTemplate(resource, response, java.util.Collections.EMPTY_MAP);
    }

    /**
     * 写出指定的模板
     *
     * @param resource 模板路径
     * @param response HTTP响应
     * @param map      用于替换模板中参数的的参数集
     * @throws IOException
     */
    public static void writeOutTemplate(String resource, HttpServletResponse response, Map map) throws IOException {

        //debug模式每次都刷新js和css,便于调试
        if (StableUtils.isDebug()) {
            StableFactory.refreshTypeStyleFiles();
            StableFactory.refreshJavaScriptFiles();
        }
        PrintWriter writer = WebUtils.createPrintWriter(response);
        //bug45146,如果因为weblogic/resin服务器没有获取contentType,会把contentType为text/html,这里先再根据resource重新设置下。
        WebUtils.setResourceContentType(resource, response);
        TemplateUtils.dealWithTemplate(resource, writer, map);
        writer.flush();
        writer.close();
    }

    /**
     * @deprecated use {@link BaseWebUtils#invalidResourcePath} instead.
     * */
    @Deprecated
    public static boolean invalidResourcePath(String resourcePath) {
        return BaseWebUtils.invalidResourcePath(resourcePath);
    }

    /**
     * 获取资源文件类型
     *
     * @param resourceName 资源文件路径
     * @param res          http响应
     * @return 返回资源文件类型
     */
    public static ResourceType setResourceContentType(String resourceName, HttpServletResponse res) {
        if (StringUtils.isBlank(resourceName)) {
            return ResourceType.NONE;
        }
        return getResourceType(res, resourceName.toLowerCase());
    }

    private static ResourceType getResourceType(HttpServletResponse res, String lowerName) {

        String charset = ServerConfig.getInstance().getServerCharset();
        if (lowerName.endsWith(".png")) {
            res.setContentType("image/png");
        } else if (lowerName.endsWith(".gif")) {
            res.setContentType("image/gif");
        } else if (lowerName.endsWith(".jpg")) {
            res.setContentType("image/jpeg");
        } else if (lowerName.endsWith(".js")) {
            res.setContentType("text/javascript;charset=" + charset);
            return ResourceType.FILE;
        } else if (lowerName.endsWith(".json")) {
            res.setContentType("text/plain;charset=" + charset);
            return ResourceType.FILE;
        } else if (lowerName.endsWith(".map")) {
            return ResourceType.FILE;
        } else if (lowerName.endsWith(".css")) {
            res.setContentType("text/css;charset=" + charset);
            return ResourceType.FILE;
        } else if (lowerName.endsWith(".xml")) {
            res.setContentType("text/xml;charset=" + charset);
            return ResourceType.NONE;
        } else if (lowerName.endsWith(".swf")) {
            res.setContentType("application/x-shockwave-flash");
        } else if (lowerName.endsWith(".jnlp")) {
            res.setContentType("application/x-java-jnlp-file");
        } else if (lowerName.endsWith(".xls")) {
            res.setContentType("application/vnd.ms-excel");
        } else if (lowerName.endsWith(".exe")) {
            res.setContentType("application/x-msdownload");
            res.setHeader("extension", "exe");
            res.setHeader("Content-disposition", "attachment; filename=AcrobatReader.exe");
        } else if (lowerName.endsWith(".ttf")) {
            res.setContentType(".ttf");
        } else if (lowerName.endsWith(".eot")) {
            res.setContentType(".eot");
        } else if (lowerName.endsWith(".woff")) {
            res.setContentType(".woff");
        } else if (lowerName.endsWith(".cur")) {
            res.setContentType(".cur");
        } else if (lowerName.endsWith(".htc")) {
            res.setContentType("text/x-component");
        } else if (lowerName.endsWith(".html")) {
            res.setContentType("text/html;charset=" + charset);
            return ResourceType.FILE;
        } else {
            res.setContentType("text/html;charset=" + charset);
            return ResourceType.NONE;
        }
        return ResourceType.OTHER;
    }

    /**
     * 生成保存参数的map
     *
     * @param req HTTP请求
     * @return 参数map
     * @throws Exception 异常
     */
    public static Map createSessionIDParameterMap(HttpServletRequest req) throws Exception {
        HashMap parameterMap = new HashMap();

        Enumeration parameterNames = req.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String parameterName = (String) parameterNames.nextElement();
            // 去掉"reportlet",不保存.
            if (StringUtils.isBlank(parameterName)) {
                continue;
            }

            // 因为这个方法会在第一次访问的时候调用,需要去掉几个内置的参数.
            if (isSpecificParameters(parameterName)) {
                continue;
            }

            // Encoding text.
            parameterMap.put(parameterName, WebUtils.getHTTPRequestParameter(req, parameterName));
        }

        return parameterMap;
    }

    private static boolean isSpecificParameters(String parameterName) {
        return "reportlet".equalsIgnoreCase(parameterName) || "format".equalsIgnoreCase(parameterName) || "op".equalsIgnoreCase(parameterName);
    }

    /**
     * carl:将传进来的参数Map进行处理
     * 将一些json参数分解出来
     * 过滤掉一些内置参数
     * <p/>
     * 传进来的参数Map不变
     *
     * @param paramMap 待处理的map
     * @return 新的Map
     */
    public static Map<String, Object> dealWithExecuteParamMap(Map<String, Object> paramMap) {
        // alex:execute时用的Map,先取初始化的Map,再取sessionIDInfor中的Map,先后次序不能颠倒了
        Map<String, Object> map4Execute = new HashMap<String, Object>();
        if (paramMap != null) {
            for (String key : paramMap.keySet()) {
                Object ob = paramMap.get(key);
                // richer:参数为JSONObject主要是表单提交上来的参数
                if (ob instanceof JSONObject) {
                    for (Map.Entry<String, Object> entry : (JSONObject)ob) {
                        String name = entry.getKey();
                        map4Execute.put(name, ((JSONObject) ob).getValue(name));
                    }
                }
            }
            map4Execute.putAll(paramMap);
        }

        // remove server parameters
        for (int i = 0; i < ParameterConstants.ALL.length; i++) {
            map4Execute.remove(ParameterConstants.ALL[i]);
        }

        return map4Execute;
    }


    /**
     * 兼容各个web服务器getRealPath方法
     *
     * @param servletContext the servletContext
     * @return return the WEB-INF Path
     */
    public static String getWebINFPath(ServletContext servletContext) {
        return BaseWebUtils.getWebINFPath(servletContext);
    }

    /**
     * 生成包括移动参数的map
     *
     * @param req 请求
     * @return 参数map
     */
    public static Map<String, Object> parameters4SessionIDInforContainMPCache(HttpServletRequest req) {
        Map<String, Object> map = parameters4SessionIDInfor(req);
        HttpSession session = req.getSession(false);
        if (session != null) {
            Object info = session.getAttribute(ParameterConstants.__MPCACHEID__);
            if (info != null) {
                Map<String, Object> tMap = (Map<String, Object>) info;
                map.putAll(tMap);
                session.removeAttribute(ParameterConstants.__MPCACHEID__);
            }
        }

        return map;
    }

    /**
     * 将HTTPServletRequest中的所有参数都读取出来,存储在一个Map中,返回出去,主要是为了传给SessionIDInfor
     *
     * @param req 请求 q
     * @return 参数map  c
     */
    public static Map<String, Object> parameters4SessionIDInfor(HttpServletRequest req) {
        Map<String, Object> parameterMap = new HashMap<String, Object>();
        if (req == null) {
            return parameterMap;
        }
        ExtraClassManagerProvider pluginProvider = PluginModule.getAgent(PluginModule.ExtraCore);
        RequestParameterCollector collector = null;
        if (pluginProvider != null) {
            collector = pluginProvider.getSingle(RequestParameterCollector.XML_TAG);
        }
        if (collector == null) {
            collector = DefaultRequestParameterCollector.getInstance();
        }
        parameterMap.putAll(collector.getParametersFromSession(req));
        parameterMap.putAll(collector.getParametersFromAttribute(req));
        parameterMap.putAll(collector.getParametersFromParameter(req));
        parameterMap.putAll(collector.getParametersFromJSON(req, parameterMap));
        parameterMap.putAll(collector.getParametersFromReqInputStream(req));

        // denny: 浏览器国际化
        parameterMap.put(Constants.__LOCALE__, WebUtils.getLocale(req));

        // carl:设置权限参数,先移除相应的参数,防止url传参等,然后再从session中取再设置
        // 原来想就用底层的那套权限控制来处理一下,再设置的,但说不准要做什么变动,暂时就独立出来
        if (parameterMap.get(ParameterConstants.REDIRECT_FROM) == null) {
            String[] FILTER_PARAMS = BaseSessionFilterParameterManager.getFilterParameters();
            for (int i = 0; i < FILTER_PARAMS.length; i++) {
                parameterMap.remove(FILTER_PARAMS[i]);
            }
        }
        SimpleUser user = getCurrentSimpleUserFromRequest(req);
        if (user == null) {
            return parameterMap;
        } else {
            dealWithDetailUserInfo(user, UserInfoHandleFactory.getUserDetailInfo(), parameterMap);
        }
        return parameterMap;
    }

    /**
     * 获取用户对应的详细信息,加入到map中
     */
    private static void dealWithDetailUserInfo(SimpleUser user, UserDetailInfo userDetailInfoHandler, Map<String, Object> parameterMap) {
        String username = user.getUsername();
        String displayName = user.getDisplayName();
        parameterMap.put(ParameterConstants.FINE_USERNAME, username);
        parameterMap.put(ParameterConstants.FINE_OLD_USERNAME, username);
        parameterMap.put(ParameterConstants.FINE_DISPLAY_NAME, displayName);
        if (userDetailInfoHandler != null) {
            FArray depAndPost = userDetailInfoHandler.getDepartmentAndPost(username);
            FArray customRole = userDetailInfoHandler.getCustomRole(username);
            if (depAndPost != null) {
                parameterMap.put(ParameterConstants.FINE_POSITION, depAndPost);
                parameterMap.put(ParameterConstants.FINE_OLD_POSITION, depAndPost);
            }
            if (customRole != null) {
                parameterMap.put(ParameterConstants.FINE_ROLE, customRole);
                parameterMap.put(ParameterConstants.FINE_OLD_ROLE, customRole);
            }
        }
    }

    /**
     * 当{@link ServerConfig#isTokenFromCookie()}为true时,优先从cookie取
     * 否则先Parameter(REPORT-15581 与TokenResource.HEADER相反) -> Header -> Cookie
     * @param req request
     * @return token
     */
    private static String getToken(HttpServletRequest req) {
        String token;
        if (ServerConfig.getInstance().isTokenFromCookie()) {
            token = NetworkHelper.getTokenFromCookie(req);
            if (!StringUtils.isEmpty(token)) {
                return token;
            }
        }
        token = NetworkHelper.getTokenFromParameter(req);
        if (!StringUtils.isEmpty(token)) {
            return token;
        }
        token = NetworkHelper.getTokenFromHeader(req);
        return StringUtils.isEmpty(token) ? NetworkHelper.getTokenFromCookie(req) : token;
    }

    /**
     * 获取用户名以及显示名字
     *
     * @param request http请求
     * @return 用户名和显示名组合对象
     */
    private static SimpleUser getCurrentSimpleUserFromRequest(HttpServletRequest request) {
        try {
            String token = getToken(request);
            if (StringUtils.isNotBlank(token)) {
                Claims claims = JwtUtils.parseJWT(token);
                return SimpleUser.create(claims.getSubject(), claims.getDescription());
            }
        } catch (Exception e) {
            FineLoggerFactory.getLogger().info("can't find username from request: {}", e.getMessage());
        }
        return null;
    }


    /**
     * 返回发起指定HTTP请求的URL地址
     *
     * @param req HTTP请求
     * @return URL地址
     */
    public static String getOriginalURL(HttpServletRequest req) {
        return NetworkHelper.getOriginalURL(req);
    }

    /**
     * 获取发起请求的客户端的IP地址
     *
     * @param req HTTP请求
     * @return 客户端IP地址
     */
    public static String getIpAddr(HttpServletRequest req) {
        String ip = req.getHeader("x-forwarded-for");
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = req.getHeader("Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = req.getHeader("WL-Proxy-Client-IP");
        }
        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
            ip = req.getRemoteAddr();
        }
        //null还是不return回去了, Apache,Squid等反向代理软件不能获取到客户端的真实IP地址。
        return StringUtils.isEmpty(ip) ? "unknown" : ip;
    }

    /**
     * 判断访问模板的IP是否为服务器本机
     *
     * @param ip IP地址
     * @return 是服务器本机则返回true,否则返回false
     */
    public static boolean isLocalHost(String ip) {
        return "127.0.0.1".equals(ip) || "localhost".equals(ip) || (ip != null && ip.startsWith("0:0:0:0:0:0:0:1"));
    }

    /**
     * 从HTTP请求中获取页码信息
     *
     * @param req 请求q
     * @return 页码y
     */
    public static int receivePageNumber(HttpServletRequest req) {
        int pn = 0;
        String pnValue = WebUtils.getHTTPRequestParameter(req, "pn");
        if (pnValue != null) {
            Number num = Utils.string2Number(pnValue);
            // alex:如果num为null或者intValue小于,有一种可能性是长度过长,所以设置pn为Integer.MAX_VALUE
            if (num == null || (pn = num.intValue()) < 0) {
                pn = Integer.MAX_VALUE;
            }
        }
        return pn;
    }

    /**
     * 根据网络请求判定发起请求的设备
     *
     * @param req HTTP请求
     * @return 设备类型
     */
    public static Device getDevice(HttpServletRequest req) {
        return NetworkHelper.getDevice(req);
    }

    public static Format getResponseContentFormat(HttpServletRequest req) {
        return NetworkHelper.getResponseContentFormat(req);
    }

    /**
     * 获取req中的国际化信息
     *
     * @param req HTTP请求
     * @return 国际化语言
     * @date 2014-12-1-下午4:39:44
     */
    public static Locale getLocale(HttpServletRequest req) {
        if (req == null) {
            return GeneralContext.getLocale();
        }

        //开放给客户的是fr_locale, 我们内部代码里js还有__fr__locale__
        String localeStr = WebUtils.getHTTPRequestParameter(req, Constants.__FR_LOCALE__);
        localeStr = localeStr == null ? WebUtils.getHTTPRequestParameter(req, "__fr_locale__") : localeStr;

        //性能, 优先处理并发最常规的.
        if (StringUtils.isEmpty(localeStr) && "zh_CN".equals(String.valueOf(req.getLocale()))) {
            return Locale.CHINA;
        }

        return GeneralUtils.createLocale(replaceScript4Xss(localeStr), req.getLocale());
    }

    /**
     * 获取需要Import的css, 并返回html标签
     *
     * @param ca 算子
     * @return html标签
     * @date 2014-12-3-下午7:45:14
     */
    public static String getCSSLinks(Calculator ca) {
        return getCSSLinks(ca, null);
    }

    /**
     * 获取需要Import的css, 并返回html标签
     *
     * @param ca   算子
     * @param attr 当前拥有对象
     * @return html标签
     * @date 2014-12-3-下午7:45:14
     */
    public static String getCSSLinks(Calculator ca, ImportJsCssProvider attr) {
        String[] csses = getImportedCSS(attr);
        StringBuilder cssBuffer = new StringBuilder();
        for (String importString : csses) {
            try {
                // 替换
                importString = TemplateUtils.render(importString, ca);
                cssBuffer.append("<link rel=\"stylesheet\" type=\"text/css\" href=\"");
                if (IOUtils.isOnlineUrl(importString)) {
                    cssBuffer.append(importString);
                } else {
                    cssBuffer.append(SateVariableManager.get(WebServerConstants.FINE_CONTEXT_PATH))
                            .append(importString.startsWith(CoreConstants.SEPARATOR)
                                    ? importString : CoreConstants.SEPARATOR + importString);
                }
                cssBuffer.append("\"></link>").append('\n');
            } catch (Exception e) {
                // 模板转换异常 doNothing
            }
        }
        return cssBuffer.toString();
    }

    /**
     * 获取需要Import的js, 并返回javascript转义字符串
     *
     * @param ca 算子
     * @return javascript转义字符串
     * @date 2014-12-3-下午7:45:14
     */
    public static String getJSLinks(Calculator ca) {
        return getJSLinks(ca, null);
    }

    /**
     * 获取需要Import的js, 并返回javascript转义字符串
     *
     * @param ca   算子
     * @param attr 当前拥有对象
     * @return javascript转义字符串
     * @date 2014-12-3-下午7:45:14
     */
    public static String getJSLinks(Calculator ca, ImportJsCssProvider attr) {
        return getJSLinks(ca, attr, false);
    }

    /**
     * 获取需要Import的js, 并返回html标签或者javascript转义字符串
     *
     * @param ca        算子
     * @param attr      当前拥有对象
     * @param isHtmlTag 是否是html标签
     * @return html标签或者javascript转义字符串
     * @date 2014-12-3-下午7:45:14
     */
    public static String getJSLinks(Calculator ca, ImportJsCssProvider attr, boolean isHtmlTag) {
        String[] jses = getImportedJS(attr);
        StringBuilder jsBuffer = new StringBuilder();
        for (String importString : jses) {
            try {
                // 替换
                importString = TemplateUtils.render(importString, ca);
                jsBuffer.append("<script type=\"text/javascript\" src=\"");
                if (IOUtils.isOnlineUrl(importString)) {
                    jsBuffer.append(importString);
                } else {
                    jsBuffer.append(SateVariableManager.get(WebServerConstants.FINE_CONTEXT_PATH))
                            .append(importString.startsWith(CoreConstants.SEPARATOR)
                                    ? importString : CoreConstants.SEPARATOR + importString);
                }
                jsBuffer.append("\"></script>").append('\n');
            } catch (Exception e) {
                // 模板转换异常 doNothing
            }
        }
        return isHtmlTag ? jsBuffer.toString() : CodeUtils.javascriptEncode(jsBuffer.toString());
    }

    /**
     * 获取全局的与当前对象需要引入的css
     *
     * @param attr 当前对象
     * @return 需要引入的css数组
     * @date 2014-12-3-下午7:47:10
     */
    private static String[] getImportedCSS(ImportJsCssProvider attr) {
        java.util.Set<String> set = new java.util.LinkedHashSet<String>(); // 用Set避免重复
        ImportJsCssProvider globalAttr = getGlobalWebAttr();

        if (globalAttr != null) {
            set.addAll(Arrays.asList(globalAttr.getCSSImport()));
        }

        if (attr != null) {
            set.addAll(Arrays.asList(attr.getCSSImport()));
        }

        return set.toArray(new String[0]);
    }

    /**
     * 获取全局设置的web属性
     *
     * @return 全局设置的web属性
     * @date 2014-12-4-上午8:51:38
     */
    private static ImportJsCssProvider getGlobalWebAttr() {
        Class globalAttr = StableFactory.getMarkedClass(ImportJsCssProvider.XML_TAG, ImportJsCssProvider.class);
        return (ImportJsCssProvider) ConfigContext.getConfigInstance(globalAttr);
    }

    /**
     * 获取全局的与当前对象需要引入的js
     *
     * @param attr 当前对象
     * @return 需要引入的js数组
     * @date 2014-12-3-下午7:47:10
     */
    private static String[] getImportedJS(ImportJsCssProvider attr) {
        java.util.Set<String> set = new java.util.LinkedHashSet<String>(); // 用Set避免重复
        ImportJsCssProvider globalAttr = getGlobalWebAttr();

        if (globalAttr != null) {
            set.addAll(Arrays.asList(globalAttr.getJSImport()));
        }

        if (attr != null) {
            set.addAll(Arrays.asList(attr.getJSImport()));
        }
        return set.toArray(new String[0]);
    }

}
NetworkHelper.java
package com.fr.data;

import com.fr.base.ServerConfig;
import com.fr.base.TemplateUtils;
import com.fr.general.ComparatorUtils;
import com.fr.general.GeneralUtils;
import com.fr.general.http.HttpClient;
import com.fr.general.web.ParameterConstants;
import com.fr.plugin.injectable.PluginModule;
import com.fr.stable.CodeUtils;
import com.fr.stable.EncodeConstants;
import com.fr.stable.StringUtils;
import com.fr.stable.fun.PrintWriterProcessor;
import com.fr.stable.fun.RequestParameterHandler;
import com.fr.stable.fun.ServletURLTransformer;
import com.fr.stable.plugin.ExtraClassManagerProvider;
import com.fr.stable.web.Device;
import com.fr.stable.web.Format;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @author richie
 * @date 14/11/17
 * @since 8.0
 */
public class NetworkHelper {
    /**
     * 插件中会用到
     */
    @SuppressWarnings("WeakerAccess")
    public static final String POST_EMPTY_SESSION = "POST_EMPTY_SESSION";

    private static final String DEPRECATED_DEVICE_KEY = "__device__";
    private static final String DEVICE_KEY = "deviceType";

    /**
     * 生成一个访问Servelt的相对路径
     *
     * @param req HTTP请求
     * @return 当前URL
     * @date 2014-9-25-下午7:46:46
     */
    public static String createServletURL(HttpServletRequest req) {
        return createServletURL(req, ServerConfig.getInstance().getServletName());
    }

    /**
     * 生成一个访问Servelt的相对路径
     *
     * @param req HTTP请求
     * @return 当前URL
     * @date 2014-9-25-下午7:46:46
     */
    public static String createServletURL(HttpServletRequest req, String servletName) {
        StringBuilder urlBuf = new StringBuilder();

        // peter:这里必须用相对路径,必须必须,
        // 比如连云港人民银行那边,如果用户有内外网的防火墙,IP中途会变化的,
        // 再也找不到原始的IP了,所以必须是相对路径
        urlBuf.append(req.getContextPath());
        urlBuf.append("/").append(servletName);

        ExtraClassManagerProvider extra = PluginModule.getAgent(PluginModule.ExtraCore);
        if (extra != null) {
            Set<ServletURLTransformer> set = extra.getArray(ServletURLTransformer.XML_TAG);
            for (ServletURLTransformer transformer : set) {
                if (transformer.accept(req)) {
                    return transformer.transform(req, urlBuf);
                }
            }
        }
        return urlBuf.toString();
    }

    /**
     * 获取req中的 InputStream
     *
     * @param req HTTP请求
     * @return 输入流
     * @date 2014-9-29-下午3:21:14
     */
    public static InputStream getRequestInputStream(HttpServletRequest req) {
        //首先从req的REQ_IN的字段中读取,如果读到的是空,说明之前没有被设置
        byte[] bytes = (byte[]) req.getAttribute(DataBaseUtils.REQ_IN);
        if (bytes == null || bytes.length == 0) {
            //判断输入流有没有被读过,没读的话,返回该输入流
            if (req.getAttribute(HttpClient.CLOSED) == null) {
                try {
                    //直接返回req的接收缓冲区对应的读取流
                    return req.getInputStream();
                } catch (IOException e) {
                    throw new RuntimeException("Network transfer exception", e);
                }
            } else {
                bytes = new byte[0];
            }
        }
        return new ByteArrayInputStream(bytes);
    }

    /**
     * 获取HTTP请求中指定名字的参数值
     *
     * @param req      HTTP请求
     * @param paraName 参数名
     * @return 参数值
     */
    public static String getHTTPRequestParameter(HttpServletRequest req, String paraName) {
        /*
         * 这个方法用的地方非常多,所有的参数获取都要从这里过 现在对从Browser端过来的参数名与值全部用cjkEncode作处理了
         * 由于我们里面自带的很多参数,这些参数的名字都是英文的,就不需要作cjkEncode处理了
         * 所以,就先直接用paraName来获取参数值,如果没有能够获得,再cjkEncode一下后从req中读取参数值
         */
        return getHTTPRequestEncodeParameter(req, paraName, true);
    }

    /**
     * 获取第一个不为空的参数
     *
     * @param req       HTTP请求
     * @param paraNames 参数列表
     * @return 参数值
     */
    public static String getHTTPRequestParameter(HttpServletRequest req, String... paraNames) {
        if (paraNames != null) {
            for (String paraName : paraNames) {
                String result = getHTTPRequestParameter(req, paraName);
                if (result != null) {
                    return result;
                }
            }
        }
        return StringUtils.EMPTY;
    }

    /**
     * 把HTTP请求中指定名字的参数值转化为布尔值
     *
     * @param req      HTTP请求
     * @param paraName 参数名
     * @return boolean 参数值
     */
    public static boolean getHTTPRequestBoolParameter(HttpServletRequest req, String paraName) {
        return Boolean.parseBoolean(NetworkHelper.getHTTPRequestParameter(req, paraName));
    }

    /**
     * 把HTTP请求中指定名字的参数值转化为整数,参数为空或不是整数则返回-1
     *
     * @param req      HTTP请求
     * @param paraName 参数名
     * @return int 参数值
     */
    public static int getHTTPRequestIntParameter(HttpServletRequest req, String paraName) {
        return getHTTPRequestIntParameter(req, paraName, -1);
    }

    /**
     * 把HTTP请求中指定名字的参数值转化为整数
     *
     * @param req          HTTP请求
     * @param paraName     参数名
     * @param defaultValue 默认值
     * @return 返回req中参数的整数值。参数为空或不是整数则返回defaultValue
     */
    public static int getHTTPRequestIntParameter(HttpServletRequest req, String paraName, int defaultValue) {

        if (req == null) {
            return defaultValue;
        }
        String parameterValue = getHTTPRequestParameter(req, paraName);
        Number num = GeneralUtils.string2Number(parameterValue);
        if (num == null) {
            return defaultValue;
        }
        return num.intValue();
    }

    /**
     * 获取sessionID
     *
     * @param req HTTP请求
     * @return session编号
     */
    public static String getHTTPRequestSessionIDParameter(HttpServletRequest req) {
        return getHTTPRequestParameter(req, ParameterConstants.SESSION_ID);
    }

    /**
     * 获取文件名
     *
     * @param req HTTP请求
     * @return 文件名
     */
    public static String getHTTPRequestFileNameParameter(HttpServletRequest req) {
        return getHTTPRequestParameter(req, ParameterConstants.__FILENAME__);
    }

    /**
     * 获取HTTP请求中指定名字的参数值
     *
     * @param req      请求
     * @param paraName 参数名
     * @param encode   是否 url-decode 解码
     * @return String 参数值
     */
    public static String getHTTPRequestEncodeParameter(HttpServletRequest req, String paraName, boolean encode) {

        ExtraClassManagerProvider provider = PluginModule.getAgent(PluginModule.ExtraCore);
        RequestParameterHandler handler;
        if (provider == null) {
            handler = DefaultRequestParameterHandler.getInstance();
        } else {
            handler = provider.getSingle(RequestParameterHandler.XML_TAG);
            if (handler == null) {
                handler = DefaultRequestParameterHandler.getInstance();
            }
        }
        Object returnValue = handler.getParameterFromHeader(req, paraName);
        if (returnValue == null) {
            returnValue = handler.getParameterFromRequest(req, paraName);
        }
        if (returnValue == null) {
            returnValue = handler.getParameterFromAttribute(req, paraName);
        }
        // alex:从req里面找一下有没有typeSensitive的参数名
        if (returnValue == null) {
            returnValue = handler.getParameterFromJSONParameters(req, paraName);
        }
        //wei : bug10637,最后才从session中取。
        if (returnValue == null) {
            returnValue = handler.getParameterFromSession(req, paraName);
        }

        if (returnValue == null) {
            // p:首先decode一下.因为传递过来参数名字可能是[4554], 但是name这个参数是中日韩文字的.
            // alex:所以需要把文字转成[9853]这样的编码再从req中去取
            paraName = CodeUtils.cjkEncode(paraName);
            returnValue = handler.getParameterFromRequest(req, paraName);
            if (returnValue == null) {
                returnValue = handler.getParameterFromAttribute(req, paraName);    // peter:需要检查一下,是否是通过Struts传递过来的,连云港人民银行要的.
                if (returnValue == null) {
                    returnValue = handler.getParameterFromSession(req, paraName);
                }
            }
        }

        return encode ? checkURLDecode(returnValue) : GeneralUtils.objectToString(returnValue);
    }

    /**
     * post的时候, session取数逻辑要断掉, 不能在从其他地方解析sessionid, 直接return null给外部.
     * 不return POST_EMPTY_SESSION是为了保持兼容, 外部很多地方直接判断sessionid != null && xxxxx(sessionid)
     *
     * @param returnValue 参数值
     * @return 是否是 {@link NetworkHelper#POST_EMPTY_SESSION}
     */
    @SuppressWarnings("WeakerAccess")
    protected static boolean isPostEmptySession(Object returnValue) {
        return POST_EMPTY_SESSION.equals(returnValue);
    }

    private static String checkURLDecode(Object str) {
        if (str == null) {
            return null;
        }

        //url中传参也是一样encodeURIComponent(encodeURIComponent("+"))
        //传下拉树的值的话有问题,得再decodeText一次 //看原始bug好像没问题先改回
        String temp = CodeUtils.decodeText(String.valueOf(str));

        try {
            //8125 29122 js端需要两次encodeURIComponent(默认用的utf-8编码规则)
            // neil:第一次encode是去掉特殊字符, 变成ascii字符串(STR_ENC1), 第二次encode是因为web容器得到后会去自动解一次,
            // 容器req.getParameter自动解的这一次,不管是按 GBK 还是 UTF-8 还是 ISO-8859-1 都好,都能够正确的得到 [STR_ENC1],
            // 如果js只encode一次, 那么容器那边只能按照utf-8解(客户的tomcat可能有多种编码方式), 否则乱码, 最后java端再去URLDecoder.decode
            return URLDecoder.decode(temp, EncodeConstants.ENCODING_UTF_8);
        } catch (UnsupportedEncodingException e) {
            return null;
        } catch (IllegalArgumentException e) {
            //URLDecoder出错
            return temp;
        }
    }

    /**
     * 返回发起指定HTTP请求的URL地址
     *
     * @param req HTTP请求
     * @return URL地址
     */
    public static String getOriginalURL(HttpServletRequest req) {
        return getOriginalURL(req, true);
    }

    /**
     * 返回发起指定HTTP请求的URL地址
     *
     * @param req               req HTTP请求
     * @param decodeQueryString 是否解码参数queryString
     * @return URL地址
     */
    public static String getOriginalURL(HttpServletRequest req, boolean decodeQueryString) {
        return getOriginal(req, true, decodeQueryString);
    }

    /**
     * 返回请求的uri(去除协议和域名端口的路径)
     *
     * @param request           http请求
     * @param decodeQueryString 是否解码参数
     * @return String 原始请求 uri
     */
    @SuppressWarnings("WeakerAccess")
    public static String getOriginalURI(HttpServletRequest request, boolean decodeQueryString) {
        return getOriginal(request, false, decodeQueryString);
    }

    private static String getOriginal(HttpServletRequest req, boolean withPrefix, boolean decodeQueryString) {
        if (req == null) {
            return "";
        }
        StringBuffer sb = withPrefix ? req.getRequestURL() : new StringBuffer(req.getRequestURI());
        Map pMap = req.getParameterMap();
        Iterator itr = pMap.entrySet().iterator();
        boolean isFirst = !sb.toString().contains("?");
        while (itr.hasNext()) {
            Map.Entry entry = (Map.Entry) itr.next();
            if (isFirst) {
                sb.append('?');
                isFirst = false;
            } else {
                sb.append('&');
            }
            sb.append(entry.getKey().toString());
            sb.append('=');
            sb.append(getHTTPRequestEncodeParameter(req, entry.getKey().toString(), decodeQueryString));
        }

        // 这边不encode, 主要是cjk(会带上[])和encodeURIComponent(会把url中&a=123也一起编码导致参数失效)都不太合适,
        // 这个url一般是用来做前台跳转的, 只要在前台跳转的时候encodeURI就行了.
        return sb.toString();
    }

    /**
     * 写出指定的模板
     *
     * @param resource 模板路径
     * @param response HTTP响应
     * @param map      用于替换模板中参数的的参数集
     * @throws java.io.IOException e
     */
    public static void writeOutTemplate(String resource, HttpServletResponse response, Map map) throws IOException {
        PrintWriter writer = createPrintWriter(response);
        TemplateUtils.dealWithTemplate(resource, writer, map);
        writer.flush();
        writer.close();
    }

    /**
     * 生成一个打印输出器
     *
     * @param res HTTP响应
     * @return 打印输出器
     * @throws java.io.IOException e
     */
    public static PrintWriter createPrintWriter(HttpServletResponse res) throws IOException {
        return createPrintWriter(res, ServerConfig.getInstance().getServerCharset());
    }

    /**
     * 按指定编码生成打印输出器
     *
     * @param res         HTTP响应
     * @param charsetName 编码
     * @return 打印输出器
     * @throws java.io.IOException e
     */
    public static PrintWriter createPrintWriter(HttpServletResponse res, String charsetName) throws IOException {
        PrintWriterProcessor processor = null;
        ExtraClassManagerProvider provider = PluginModule.getAgent(PluginModule.ExtraCore);
        if (provider != null) {
            processor = provider.getSingle(PrintWriterProcessor.MARK_STRING);
        }
        if (processor == null) {
            processor = DefaultPrintWriterProcessor.getInstance();
        }
        return processor.createPrintWriter(res, charsetName);
    }

    /**
     * 清楚缓存设置
     *
     * @param res HTTP响应
     */
    public static void setCacheSettings(HttpServletResponse res) {
        //marks:ie6不是嵌在网页中情况下,点保存正常,点打开就出现问题!
        //marks:要对cache进行配置和给其权限,支持https
        // carl:设置不用缓存,生存周期设个3秒,不然会导致bug0004207.
        res.setHeader("Cache-Control", "public");
        res.setHeader("Cache-Control", "max-age=3");
        // 需要首先reset一下,保证buffer里面没有其他东西.
        // 在Weblogic里面常常没有清空buffer里面的东西.
        res.reset();
    }

    /**
     * 根据网络请求判定发起请求的设备
     *
     * @param req HTTP请求
     * @return 设备类型
     */
    public static Device getDevice(HttpServletRequest req) {
        String device = getDeviceType(req);
        if (StringUtils.isNotBlank(device)) {
            return Device.parse(device);
        }
        //wei: 这边判断是不是移动端的逻辑虽然不是很准确,但是现有代码有很多都是根据这个逻辑来的改准确了反而出问题,还是改回原先的写法.
        return Device.parse(NetworkHelper.getHTTPRequestParameter(req, DEPRECATED_DEVICE_KEY));
    }

    public static Format getResponseContentFormat(HttpServletRequest req) {
        Device device = getDevice(req);
        if (device.isMobile()) {
            return Format.JSON;
        }
        return Format.parse(NetworkHelper.getHTTPRequestParameter(req, "__format__"));
    }

    /**
     * 从Cookie获取token
     * @param request request
     * @return token
     */
    public static String getTokenFromCookie(HttpServletRequest request) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (ComparatorUtils.equals(cookie.getName(), ParameterConstants.TOKEN_NAME)) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }

    /**
     * 从Header Authorization获取token
     * @param request request
     * @return token
     */
    public static String getTokenFromHeader(HttpServletRequest request) {
        String authorization = request.getHeader(ParameterConstants.AUTHORIZATION_HEADER);
        if (StringUtils.isNotEmpty(authorization)) {
            return authorization.substring(ParameterConstants.AUTHORIZATION_PREFIX.length());
        } else {
            return StringUtils.EMPTY;
        }
    }

    /**
     * 从Parameter获取token
     * @param request request
     * @return token
     */
    public static String getTokenFromParameter(HttpServletRequest request) {
        return getHTTPRequestParameter(request, ParameterConstants.TOKEN_NAME);
    }

    private static String getDeviceType(HttpServletRequest req) {
        String deviceType = req.getHeader(DEVICE_KEY);
        if (StringUtils.isNotBlank(deviceType)) {
            return deviceType;
        }
        deviceType = (String) req.getAttribute(DEVICE_KEY);
        if (StringUtils.isNotBlank(deviceType)) {
            return deviceType;
        }
        deviceType = NetworkHelper.getHTTPRequestParameter(req, DEVICE_KEY);
        if (StringUtils.isNotBlank(deviceType)) {
            return deviceType;
        }
        deviceType = req.getHeader(DEPRECATED_DEVICE_KEY);
        if (StringUtils.isNotBlank(deviceType)) {
            return deviceType;
        }
        return (String) req.getAttribute(DEPRECATED_DEVICE_KEY);
    }

}


三、接口/方法/对象说明

WebUtils是帆软产品内对请求信息获取

四、常用链接

3种插件中较为稳定的接口说明

五、开源案例


  • No labels