package com.deloitte.system.service;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.alibaba.fastjson.JSONArray;
|
import com.common.aws.util.S3Util;
|
import com.common.core.constant.GlobalConst;
|
import com.common.core.enums.ResultCodeEnum;
|
import com.common.core.exception.BizException;
|
import com.common.core.utils.UUID;
|
import com.common.core.utils.*;
|
import com.common.redis.util.RedisUtil;
|
import com.deloitte.system.request.FileRequest;
|
import com.j256.simplemagic.ContentInfoUtil;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.codec.binary.Base64;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.http.MediaType;
|
import org.springframework.stereotype.Service;
|
import org.springframework.web.multipart.MultipartFile;
|
import software.amazon.awssdk.core.ResponseBytes;
|
import software.amazon.awssdk.services.s3.model.GetObjectResponse;
|
import software.amazon.awssdk.services.s3.model.S3Exception;
|
|
import javax.servlet.ServletOutputStream;
|
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletResponse;
|
import javax.xml.bind.DatatypeConverter;
|
import java.io.*;
|
import java.net.URLDecoder;
|
import java.net.URLEncoder;
|
import java.nio.charset.StandardCharsets;
|
import java.text.SimpleDateFormat;
|
import java.util.*;
|
|
import static com.common.core.constant.GlobalConst.PIPL_UNCONFIRM_FILE;
|
|
@Slf4j
|
@Service
|
public class FileService {
|
@Autowired
|
private RedisUtil redisUtil;
|
@Value("${salesforce.referer}")
|
private String refererUrl;
|
@Value("${aws.s3.bucketName}")
|
private String bucketName;
|
|
public String upload(String txId,FileRequest fileRequest){
|
log.info("上传文件txId:"+txId);
|
String key=uploadFile(fileRequest);
|
String keyName = PIPL_UNCONFIRM_FILE + txId;
|
redisUtil.set(keyName, new JSONArray(Arrays.asList(key)), GlobalConst.DATA_EXPIRE);
|
return key;
|
}
|
|
public List<String> batchUpload(String txId, List<FileRequest> fileList) {
|
log.info("上传文件txId:"+txId);
|
List<String> keys=new ArrayList<>();
|
try {
|
fileList.forEach(fileRequest -> {
|
String key = uploadFile(fileRequest);
|
keys.add(key);
|
});
|
String keyName = PIPL_UNCONFIRM_FILE + txId;
|
redisUtil.set(keyName, new JSONArray((List)keys), GlobalConst.DATA_EXPIRE);
|
}catch (Exception e){
|
this.cleanS3File(keys);
|
throw e;
|
}
|
return keys;
|
}
|
|
public String uploadFile(FileRequest fileRequest){
|
if (fileRequest == null) {
|
throw new BizException(ResultCodeEnum.NO_DATA);
|
}
|
log.info("fileName:{}", fileRequest.getFileName());
|
//文件大小限制,最大单文件30M
|
if(fileRequest.getSize()>31457280){
|
throw new BizException(ResultCodeEnum.FILE_SIZE_EXCEED);
|
}
|
if(fileRequest.getFile().startsWith("base64,")){
|
String contentType= ContentInfoUtil.findExtensionMatch(fileRequest.getFileName())==null?
|
"text/plain": ContentInfoUtil.findExtensionMatch(fileRequest.getFileName()).getMimeType();
|
fileRequest.setFile("data:"+contentType+";"+fileRequest.getFile());
|
}
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
String oldFileName = fileRequest.getFileName();
|
String suffix=oldFileName.lastIndexOf(".")==-1?"":oldFileName.substring(oldFileName.lastIndexOf("."));
|
String newFileName = UUID.randomUUID().toString().replace("-","")+suffix;
|
String key = sdf.format(new Date()) + "/" + newFileName;
|
// 将文件base64存入缓存
|
MultipartFile multipartFile = null;
|
try {
|
multipartFile = BASE64DecodedMultipartFile.base64ToMultipart(fileRequest.getFile());
|
} catch (IOException e) {
|
log.error("上传文件失败:",e);
|
}
|
if (multipartFile == null) {
|
throw new BizException("未找到文件");
|
}
|
String bucketName = SpringContextUtils.getEnvParam("aws.s3.bucketName");
|
S3Util.uploadFile(multipartFile, key,bucketName);
|
return key;
|
}
|
|
public String uploadFileNoSize(FileRequest fileRequest){
|
if (fileRequest == null) {
|
throw new BizException(ResultCodeEnum.NO_DATA);
|
}
|
log.info("fileName:{}", fileRequest.getFileName());
|
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
|
String oldFileName = fileRequest.getFileName();
|
String suffix=oldFileName.lastIndexOf(".")==-1?"":oldFileName.substring(oldFileName.lastIndexOf("."));
|
String newFileName = UUID.randomUUID().toString().replace("-","")+suffix;
|
String key = sdf.format(new Date()) + "/" + newFileName;
|
// 将文件base64存入缓存
|
MultipartFile multipartFile = null;
|
try {
|
multipartFile = BASE64DecodedMultipartFile.base64ToMultipart(fileRequest.getFile());
|
} catch (IOException e) {
|
log.error("上传文件失败:",e);
|
}
|
if (multipartFile == null) {
|
throw new BizException("未找到文件");
|
}
|
String bucketName = SpringContextUtils.getEnvParam("aws.s3.bucketName");
|
S3Util.uploadFile(multipartFile, key,bucketName);
|
return key;
|
}
|
|
public void cleanS3File(Collection<String> keyList){
|
if (!keyList.isEmpty()){
|
String bucketName = SpringContextUtils.getEnvParam("aws.s3.bucketName");
|
S3Util.deleteByKeys(new ArrayList<String>(keyList),bucketName);
|
}
|
}
|
|
private boolean checkReferer(String referer){
|
String[] refererUrls=refererUrl.split(",");
|
for (String str : refererUrls) {
|
if(str.equalsIgnoreCase(referer)||str.substring(0,str.length()-1).equalsIgnoreCase(referer)){
|
return true;
|
}
|
}
|
return false;
|
}
|
|
public void preview(HttpServletRequest request,HttpServletResponse response,String key){
|
String referer = request.getHeader("Referer");
|
if (StrUtil.isBlank(referer)) {
|
throw new BizException(ResultCodeEnum.NO_PERMISSION);
|
}
|
//referer 截取
|
String replace = referer.replace("https://", "");
|
String newReferer = "https://"+replace.substring(0, replace.indexOf("/")+1);
|
if (!checkReferer(newReferer)) {
|
throw new BizException(ResultCodeEnum.NO_PERMISSION);
|
}
|
String fileName = key.substring(key.lastIndexOf("/")+1);
|
log.info("文件预览key:{},fileName:{}",key,fileName);
|
OutputStream out = null;
|
try {
|
response.setCharacterEncoding("utf-8");
|
String s = ContentInfoUtil.findExtensionMatch(fileName).getMimeType();
|
log.info("文件预览key:{},contentType:{}",key,s);
|
if (StrUtil.isNotBlank(s)) {
|
response.setContentType(s);
|
} else{
|
response.setContentType(MediaType.ALL_VALUE);
|
}
|
String agent = request.getHeader("User-Agent");
|
if(agent.toLowerCase().contains("firefox")) {
|
response.setHeader("Content-Disposition", "inline; filename==?UTF-8?B?" + new String(Base64.encodeBase64(fileName.getBytes("UTF-8")))+"?=");
|
}else {
|
response.setHeader("Content-Disposition", "inline; filename=" + new String(fileName.getBytes("gbk"),"iso8859-1"));
|
}
|
ResponseBytes<GetObjectResponse> objectBytes = S3Util.downloadFile(key,bucketName);
|
InputStream inputStream = objectBytes.asInputStream();
|
BufferedInputStream bufInputStream = new BufferedInputStream(inputStream);
|
out = response.getOutputStream();
|
byte[] buf = new byte[1024];
|
int len;
|
while ((len = bufInputStream.read(buf)) > 0) {
|
out.write(buf, 0, len);
|
}
|
response.flushBuffer();
|
out.close();
|
} catch (IOException e) {
|
log.error("文件预览失败:",e);
|
throw new BizException(ResultCodeEnum.RT_ERROR);
|
}catch (S3Exception e) {
|
log.error("文件预览失败:",e);
|
throw new BizException(e.getMessage());
|
}
|
|
}
|
|
public void download(HttpServletRequest request,HttpServletResponse response,String key){
|
String referer = request.getHeader("Referer");
|
|
log.info("referer:"+referer);
|
|
if (StrUtil.isBlank(referer)) {
|
throw new BizException(ResultCodeEnum.NO_PERMISSION);
|
}
|
//referer 截取
|
String replace = referer.replace("https://", "");
|
String newReferer = "https://"+replace.substring(0, replace.indexOf("/")+1);
|
if (!checkReferer(newReferer)) {
|
throw new BizException(ResultCodeEnum.NO_PERMISSION);
|
}
|
|
OutputStream out = null;
|
try {
|
String fileName = request.getParameter("fileName");
|
if (StrUtil.isBlank(fileName)) {
|
throw new BizException("fileName不能为空");
|
}
|
log.info("文件下载key:{},fileName:{}",key,fileName);
|
response.setHeader("Pragma", "No-cache");
|
response.setHeader("Cache-Control", "No-cache");
|
response.setDateHeader("Expires", 0);
|
response.setContentType("application/octet-stream");
|
String agent = request.getHeader("User-Agent");
|
if (null != agent && agent.contains("MSIE") || null != agent && agent.contains("Trident") || null != agent && agent.contains("Edge")) {
|
// ie浏览器及Edge浏览器
|
fileName = java.net.URLEncoder.encode(fileName, "UTF-8");
|
} else if (null != agent && agent.contains("Mozilla")) {
|
// 火狐,Chrome等浏览器
|
fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
|
}else {
|
// 其它浏览器
|
fileName = URLEncoder.encode(fileName, "utf-8");
|
}
|
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
|
ResponseBytes<GetObjectResponse> objectBytes = S3Util.downloadFile(key,bucketName);
|
InputStream inputStream = objectBytes.asInputStream();
|
BufferedInputStream bufInputStream = new BufferedInputStream(inputStream);
|
out = response.getOutputStream();
|
byte[] buf = new byte[1024];
|
int len;
|
while ((len = bufInputStream.read(buf)) > 0) {
|
out.write(buf, 0, len);
|
}
|
response.flushBuffer();
|
out.close();
|
} catch (IOException e) {
|
log.error("文件下载失败:",e);
|
throw new BizException(ResultCodeEnum.RT_ERROR);
|
}catch (S3Exception e) {
|
log.error("文件下载失败:",e);
|
throw new BizException(e.getMessage());
|
}
|
|
}
|
|
public void deleteFile(List<String> keys){
|
if (CollUtil.isEmpty(keys)) {
|
throw new BizException(ResultCodeEnum.NO_DATA);
|
}
|
String bucketName = SpringContextUtils.getEnvParam("aws.s3.bucketName");
|
S3Util.deleteByKeys(keys,bucketName);
|
}
|
|
public void convert(HttpServletRequest request,HttpServletResponse response) {
|
//从param参数中获取fileName,如果为空则取当前时间为文件名
|
String fileName = request.getParameter("fileName");
|
fileName = fileName==null? DateUtils.format(new Date()) : fileName;
|
response.setContentType("application/pdf");
|
//要保存的文件名
|
response.setHeader("Content-Disposition", "inline;filename=" + fileName + ".pdf");
|
response.addHeader("Pargam", "no-cache");
|
response.addHeader("Cache-Control", "no-cache");
|
|
ServletOutputStream outputStream = null;
|
BufferedReader bufferReader=null;
|
String base64Str="";
|
try {
|
if(StringUtils.isNotBlank(request.getParameter("base64Str"))){
|
base64Str=request.getParameter("base64Str");
|
}else {
|
bufferReader = new BufferedReader(request.getReader());
|
StringBuilder sb = new StringBuilder();
|
String line = null;
|
while ((line = bufferReader.readLine()) != null) {
|
sb.append(line);
|
}
|
String body = sb.toString();
|
String[] strings = body.split("&");
|
Map<String, String> valueMap = new HashMap<>();
|
for (String string : strings) {
|
String[] keyValue = string.split("=", 2);
|
String key = keyValue[0];
|
String value = keyValue[1];
|
valueMap.put(URLDecoder.decode(key, "UTF-8"), URLDecoder.decode(value, "UTF-8"));
|
}
|
base64Str = valueMap.get("base64Str");
|
}
|
outputStream = response.getOutputStream();
|
byte[] b = DatatypeConverter.parseBase64Binary(base64Str);
|
outputStream.write(b, 0, b.length);
|
} catch (IOException e) {
|
log.error("文件转换异常:",e);
|
throw new BizException(ResultCodeEnum.RT_ERROR);
|
}finally {
|
try {
|
if(bufferReader!=null)bufferReader.close();
|
} catch (IOException e) {
|
}
|
}
|
}
|
|
public static String getFilecharset(InputStream inputStream) {
|
//默认GBK
|
String charset = "GBK";
|
byte[] first3Bytes = new byte[3];
|
try(BufferedInputStream bis = new BufferedInputStream(inputStream)) {
|
bis.mark(0);
|
int read = bis.read(first3Bytes, 0, 3);
|
// 文件编码为 ANSI
|
if (read == -1) {
|
return charset;
|
}
|
// 文件编码为 Unicode
|
if (first3Bytes[0] == (byte) 0xFF && first3Bytes[1] == (byte) 0xFE) {
|
return "UTF-16LE";
|
}
|
// 文件编码为 Unicode big endian
|
if (first3Bytes[0] == (byte) 0xFE && first3Bytes[1] == (byte) 0xFF) {
|
return "UTF-16BE";
|
}
|
// 文件编码为 UTF-8
|
if (first3Bytes[0] == (byte) 0xEF && first3Bytes[1] == (byte) 0xBB && first3Bytes[2] == (byte) 0xBF) {
|
return "UTF-8";
|
}
|
bis.reset();
|
|
int loc = 0;
|
while ((read = bis.read()) != -1) {
|
loc++;
|
if (read >= 0xF0) {
|
break;
|
}
|
// 单独出现BF以下的,也算是GBK
|
if (0x80 <= read && read <= 0xBF) {
|
break;
|
}
|
if (0xC0 <= read && read <= 0xDF) {
|
read = bis.read();
|
// 双字节 (0xC0 - 0xDF)
|
if (0x80 <= read && read <= 0xBF) {
|
// (0x80
|
// - 0xBF),也可能在GB编码内
|
continue;
|
}
|
break;
|
}
|
// 也有可能出错,但是几率较小
|
if (0xE0 <= read && read <= 0xEF) {
|
read = bis.read();
|
if (0x80 <= read && read <= 0xBF) {
|
read = bis.read();
|
if (0x80 <= read && read <= 0xBF) {
|
charset = "UTF-8";
|
}
|
}
|
break;
|
}
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
}
|
return charset;
|
}
|
}
|