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

Page tree

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

Skip to end of metadata
Go to start of metadata

一、特殊名词介绍

二、接口/方法/对象源码——【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是帆软产品内对请求信息获取的工具类封装,该工具类提供了对请求信息进行额外处理的的入口。

四、常用链接

com.fr.stable.fun.RequestParameterHandler

五、开源案例


  • No labels