package com.artfess.base.util; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLEncoder; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.artfess.base.conf.SaaSConfig; import com.artfess.base.conf.SsoConfig; import com.artfess.base.jwt.JwtTokenHandler; import org.apache.commons.io.IOUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.ParseException; import org.apache.http.StatusLine; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; public class HttpUtil { // \b 是单词边界(连着的两个(字母字符 与 非字母字符) 之间的逻辑上的间隔), // 字符串在编译时会被转码一次,所以是 "\\b" // \B 是单词内部逻辑间隔(连着的两个字母字符之间的逻辑上的间隔) private static final String phoneReg = "\\b(ip(hone|od)|android|opera m(ob|in)i" +"|windows (phone|ce)|blackberry" +"|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp" +"|laystation portable)|nokia|fennec|htc[-_]" +"|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b"; private static final String tabletReg = "\\b(ipad|tablet|(Nexus 7)|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b"; //移动设备正则匹配:手机端、平板 private static Pattern phonePat = Pattern.compile(phoneReg, Pattern.CASE_INSENSITIVE); private static Pattern tabletPat = Pattern.compile(tabletReg, Pattern.CASE_INSENSITIVE); public final static String METHOD_GET = "GET"; public final static String METHOD_POST = "POST"; /** * 获取当前请求的request对象 * @return */ public static HttpServletRequest getRequest() { RequestAttributes requestAttributes = null; try{ requestAttributes = RequestContextHolder.currentRequestAttributes(); }catch (IllegalStateException e){ return null; } return ((ServletRequestAttributes) requestAttributes).getRequest(); } /** * 获取当前请求的参数 * @param name * @return */ public static String getRequestParameter(String name) { HttpServletRequest request = getRequest(); if(BeanUtils.isEmpty(request)) { return null; } return request.getParameter(name); } /** * 从jwt中获取当前登录用户的tenantId * @return */ private static String getTenantIdByAuthorization() { HttpServletRequest request = getRequest(); if(BeanUtils.isEmpty(request)) { return null; } String requestHeader = request.getHeader("Authorization"); if(BeanUtils.isNotEmpty(requestHeader) && requestHeader.startsWith("Bearer ")) { String authToken = requestHeader.substring(7); return HttpUtil.getTenantIdFromJwt(authToken); } return null; } /** * 从jwt中解析tenantId * @return */ private static String getTenantIdFromJwt(String jwt) { if(StringUtil.isEmpty(jwt)) { return null; } SaaSConfig saaSConfig = AppUtil.getBean(SaaSConfig.class); // 非SaaS模式,不从jwt中解析租户ID if(!saaSConfig.isEnable()) { return null; } JwtTokenHandler jwtTokenHandler = AppUtil.getBean(JwtTokenHandler.class); String tenantId = jwtTokenHandler.getTenantIdFromToken(jwt); if(StringUtil.isNotEmpty(tenantId)) { return tenantId; } return null; } /** *
* 访问进入controller层时 设置enterController属性 * 如果有tenantId 参数则从参数中获取 * * 没有进入controller层时 从jwttoken中获取用户认证的tenantId ** @return */ public static String getTenantId() { HttpServletRequest request = HttpUtil.getRequest(); if(BeanUtils.isEmpty(request)) { return null; } Boolean enterController = (Boolean) request.getAttribute("enterController"); String tenantId = null; // 只有request属性中有enterController信息时才进行判断,即只有请求Controller方法(且必须有@ApiOperation注解)时判断。 if(BeanUtils.isNotEmpty(enterController) && enterController) { // 1.获取url地址后面是否有tenantId参数(临时租户ID,在某些情况下,只在访问某个接口时以指定租户身份来访问) // TODO 只有平台管理用户才能使用,防止租户之间水平越权 tenantId = HttpUtil.getRequestParameter("tenantId"); if(StringUtil.isNotEmpty(tenantId)) { return tenantId; } // 2.获取url地址后面是否有token参数(携带token进行单点登录时) String token = HttpUtil.getRequestParameter("ticket"); SsoConfig ssoConfig = AppUtil.getBean(SsoConfig.class); // 只有非单点模式才提取ticket参数,对于cas、oauth2.0模式下时使用统一的单点登录认证 if(!ssoConfig.isEnable() || (ssoConfig.MODE_JWT).equals(ssoConfig.getMode())) { tenantId = HttpUtil.getTenantIdFromJwt(token); if(StringUtil.isNotEmpty(tenantId)) { return tenantId; } } } // 3.获取请求头部的Authorization,从中解析出租户ID tenantId = HttpUtil.getTenantIdByAuthorization(); if(StringUtil.isNotEmpty(tenantId)) { return tenantId; } return tenantId; } /** * 下载文件。 * * @param response * @param fullPath * 下载文件路径 * @param fileName * 下载文件名 * @throws IOException * void */ public static void downLoadFile(HttpServletResponse response, String fullPath, String fileName) throws IOException { OutputStream outp = response.getOutputStream(); File file = new File(fullPath); if (file.exists()) { response.setContentType("application/x-download"); response.setHeader("Access-Control-Expose-Headers", "Content-Disposition"); if (System.getProperty("file.encoding").equals("GBK")) { response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes(), "ISO-8859-1")); } else { response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8")); // response.addHeader("Content-Disposition", "attachment;filename="+fileName+";filename*=utf-8''"+URLEncoder.encode(fileName,"utf-8") ); } try (FileInputStream in = new FileInputStream(fullPath);){ IOUtils.copy(in, outp); } catch (Exception e) { e.printStackTrace(); } finally { if (outp != null) { outp.close(); outp = null; response.flushBuffer(); } } } else { outp.write("文件不存在!".getBytes("utf-8")); } } /** *
* 压缩多个文件到一个zip下然后提供到页面下载 * 目前常用于导出xml * 里面进行了1:写一个临时文件;2:打包;3:导出打包好的文件;4:删除临时文件 ** * @param request * @param response * @param fileContentMap * :{a:a的内容,b:b的内容,...} * @param zipName * :压缩包的名字 * @throws Exception * void * @exception * @since 1.0.0 */ public static void downLoadFile(HttpServletRequest request, HttpServletResponse response, Map
* 压缩一个文件到压缩包下然后提供到页面下载 * 目前常用于导出xml * 里面进行了1:写一个临时文件;2:打包;3:导出打包好的文件;4:删除临时文件 ** * @param request * @param response * @param content :要导出的文本 * @param fileName :文件名称 * @param zipName :压缩包名称 * @throws Exception * void */ public static void downLoadFile(HttpServletRequest request, HttpServletResponse response, String content, String fileName, String zipName) throws Exception { Map