package com.vci.starter.web.util; import com.vci.starter.web.constant.VConstant; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLDecoder; import java.net.URLEncoder; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * 在controller层使用的工具 * @author weidy * @date 2020/2/19 */ public class ControllerUtil { /** * 日志对象 */ private static Logger logger = LoggerFactory.getLogger(ControllerUtil.class); /** * 将文件写入到返回流中 * @param response 响应对象 * @param fileName 文件名称 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response,String fileName) throws FileNotFoundException,IOException{ writeFileToResponse(response,fileName,true); } /** * 将文件写入到返回流中 * @param response 响应对象 * @param fileName 文件名称 * @param deleteFile 下载完成后是否删除文件,true表示删除,另外这个文件的上级文件夹也会被删除,因此临时文件夹一般都添加了随机名称的文件夹 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response,String fileName,boolean deleteFile) throws FileNotFoundException,IOException{ writeFileToResponse(response,fileName,null,deleteFile); } /** * 将文件写入到返回流中 * @param response 响应对象 * @param fileName 文件名称 * @param deleteFile 下载完成后是否删除文件,true表示删除,另外这个文件的上级文件夹也会被删除,因此临时文件夹一般都添加了随机名称的文件夹 * @param showName 显示文件名,即用户看到的名称,否则直接为原文件的名称 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response,String fileName,String showName,boolean deleteFile) throws FileNotFoundException,IOException { File file = new File(fileName); if(!file.exists()){ throw new FileNotFoundException(fileName); } writeFileToResponse(response,file,showName,deleteFile); } /** * 将文件写入到返回流中 * @param response 响应对象 * @param file 文件对象 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response, File file) throws FileNotFoundException,IOException{ writeFileToResponse(response,file,true); } /** * 将文件写入到返回流中 * @param response 响应对象 * @param file 文件对象 * @param deleteFile 下载完成后是否删除文件,true表示删除,另外这个文件的上级文件夹也会被删除,因此临时文件夹一般都添加了随机名称的文件夹 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response,File file,boolean deleteFile) throws FileNotFoundException,IOException{ writeFileToResponse(response,file,null,deleteFile); } /** * 将文件写入到返回流中 * @param response 响应对象 * @param file 文件对象 * @param deleteFile 下载完成后是否删除文件,true表示删除,另外这个文件的上级文件夹也会被删除,因此临时文件夹一般都添加了随机名称的文件夹 * @param showName 显示文件名,即用户看到的名称,否则直接为原文件的名称 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response,File file,String showName,boolean deleteFile) throws FileNotFoundException,IOException { writeFileToResponse(response,file,showName,deleteFile,null); } /** * 将文件写入到返回流中 * @param response 响应对象 * @param file 文件对象 * @param deleteFile 下载完成后是否删除文件,true表示删除,另外这个文件的上级文件夹也会被删除,因此临时文件夹一般都添加了随机名称的文件夹 * @param showName 显示文件名,即用户看到的名称,否则直接为原文件的名称 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeFileToResponse(HttpServletResponse response,File file,String showName,boolean deleteFile,String contentType) throws FileNotFoundException,IOException { VciBaseUtil.alertNotNull(file, "文件对象"); if (!file.exists()) { throw new FileNotFoundException(file.getName()); } if (StringUtils.isBlank(showName)) { showName = file.getName(); } InputStream in = null; try { in = new FileInputStream(file); writeFileToResponse(response, in, showName, contentType); } catch (IOException e) { //有可能客户端的链接 if (logger.isErrorEnabled()) { logger.error("写入文件到响应流出错", e); } } finally { IOUtils.closeQuietly(in); if (deleteFile) { File parentFile = file.getParentFile(); file.delete(); parentFile.delete(); } } } /** * 将输入流写入到返回流中 * @param response 响应对象 * @param ins 输入流 * @param showName 名称 * @throws IOException 拷贝出错的时候会抛出异常 */ public static void writeFileToResponse(HttpServletResponse response,InputStream ins,String showName) throws IOException{ writeFileToResponse(response,ins,showName,null); } /** * 将输入流写入到返回流中 * @param response 响应对象 * @param ins 输入流 * @param showName 名称 * @throws IOException 拷贝出错的时候会抛出异常 */ public static void writeFileToResponse(HttpServletResponse response,InputStream ins,String showName,String contentType ) throws IOException{ if(StringUtils.isBlank(contentType)) { contentType = "application/force-download"; } if(StringUtils.isBlank(showName)){ showName = "下载文件"; } // 设置强制下载不打开 response.setContentType(contentType); try{ String fileName = URLEncoder.encode(showName, "UTF8"); response.addHeader("Content-Disposition", "attachment; filename="+ fileName+ ";filename*=utf-8''" + fileName); }catch(Exception e){ if(logger.isErrorEnabled()){ logger.error("设置文件的名称到响应流的时候出错",e); } } response.setCharacterEncoding("UTF-8"); Cookie cookie = new Cookie("fileDownload", "true"); cookie.setPath("/"); response.addCookie(cookie); try{ IOUtils.copy(ins,response.getOutputStream()); } catch (IOException e) { //有可能客户端的链接 if(logger.isErrorEnabled()){ logger.error("写入文件到响应流出错",e); } throw e; }finally { IOUtils.closeQuietly(ins); } } /** * 将输入流写入到返回流中 * @param response 响应对象 * @param data 数据的信息 * @throws IOException 拷贝出错的时候会抛出异常 */ public static void writeDataToResponse(HttpServletResponse response,byte[] data,String contentType) throws IOException { if (StringUtils.isBlank(contentType)) { contentType = "application/force-download"; } response.setContentType(contentType); response.setCharacterEncoding("UTF-8"); Cookie cookie = new Cookie("fileDownload", "true"); cookie.setPath("/"); response.addCookie(cookie); try { response.getOutputStream().write(data); } catch (IOException e) { //有可能客户端的链接 if (logger.isErrorEnabled()) { logger.error("写入文件到响应流出错", e); } throw e; } } /** * 将环境变量中的某个文件写到返回流中 * @param response 响应对象 * @param classPathFileName 在环境变量里的文件名称 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeClasspathFileToResponse(HttpServletResponse response,String classPathFileName) throws FileNotFoundException,IOException{ writeClasspathFileToResponse(response,classPathFileName,null); } /** * 将环境变量中的某个文件写到返回流中 * @param response 响应对象 * @param classPathFileName 在环境变量里的文件名称 * @param showName 显示名称 * @throws FileNotFoundException 文件没有找到 * @throws IOException 读取文件出错,或者写数据出错 */ public static void writeClasspathFileToResponse(HttpServletResponse response,String classPathFileName,String showName) throws FileNotFoundException,IOException{ InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(classPathFileName); if(StringUtils.isBlank(showName)){ showName = classPathFileName.contains("/")?classPathFileName.substring(classPathFileName.lastIndexOf("/") + 1):classPathFileName; } try { writeFileToResponse(response, in, showName); }catch (IOException e){ throw e; }finally { IOUtils.closeQuietly(in); } } /** * 获取IP地址,通过request * @param request http请求对象 * @return ip地址 */ public static String getClientInfo(HttpServletRequest request){ String ip = request.getHeader("X-Forwarded-For"); if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("WL-Proxy-Client-IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_CLIENT_IP"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getHeader("HTTP_X_FORWARDED_FOR"); } if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { ip = request.getRemoteAddr(); } if (ip == null || ip.length() == 0 || ip.indexOf("0:0:0:0:0:0:0:1") >-1) {//0:0:0:0:0:0:0:1是本机在访问 ip = "127.0.0.1"; } return ip; } /** * 下载错误文件的映射内容 */ public static final Map tempFileForDownloadMap = new ConcurrentHashMap<>(); /** * 设置查询总数 * @param request 请求对象 * @param isQueryTotal 是否查询总数 */ public static void setQueryTotal(HttpServletRequest request, boolean isQueryTotal){ WebThreadLocalUtil.setNeedQueryTotalInThread(isQueryTotal?"true":"false"); //request.setAttribute(webProperties.getQueryTotalSessionName(), isQueryTotal); } /** * 放置错误的文件 * @param errorFile 错误的文件 * @return 唯一标识 */ public static String putErrorFile(String errorFile){ String uuid = VciBaseUtil.getPk(); tempFileForDownloadMap.put(uuid,errorFile); return uuid; } /** * 下载错误的文件(仅限于excel) * @param response 响应对象 * @param uuid 唯一的标识 * @throws IOException 写入文件出错的时候抛出异常 */ public static void downloadErrorFile(HttpServletResponse response,String uuid) throws IOException{ String errorFile = tempFileForDownloadMap.getOrDefault(uuid, ""); try { if (StringUtils.isNotBlank(errorFile)) { ControllerUtil.writeFileToResponse(response, new File(errorFile), null, true, "application/msexcel"); } }finally { tempFileForDownloadMap.remove(uuid); } } /** * 内容编码 * * @param str 内容 * @return 编码后的内容 */ public static String urlEncode(String str) { try { return URLEncoder.encode(str, VConstant.UTF8); } catch (UnsupportedEncodingException e) { return StringUtils.EMPTY; } } /** * 内容解码 * * @param str 内容 * @return 解码后的内容 */ public static String urlDecode(String str) { try { return URLDecoder.decode(str, VConstant.UTF8); } catch (UnsupportedEncodingException e) { return StringUtils.EMPTY; } } }