【仅供内部供应商使用,不提供对外解答和培训】
...
| Code Block | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||
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是帆软产品内对请求信息获取WebUtils是帆软产品内对请求信息获取的工具类封装,该工具类提供了对请求信息进行额外处理的的入口。
3种插件中较为稳定的接口说明com.fr.stable.fun.RequestParameterHandler
无