package com.xxx;
import cn.hutool.core.io.FileUtil;
import com.album.manager.response.ReturnT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/*
* @author hewenjun
* @date 2022/12/26
* */
@Slf4j
@Service //如果不加@Service或Component注解,那么@Value定义的属性获取不到
public class FileUtils {
//不推荐使用,推荐调用公共方法时再传入路径,保持方法的公共性
// @Value("${4mUploadFolder}")4m上传路径 --${qualityExceptionUploadFolder}品质异常上传路径
// public String uploadFolder; //注意: 不能使用static 装饰,否则无法获取, 使用了uploadFolder的方法也一样,否则无法调用
/*
*获取jar所在路径地址 :一般用于保存用户上传的文件 以及 根据该路径下载用户上传的文件 ,
* 不推荐使用jar包地址
**/
public static String getJarPath(){
ApplicationHome home = new ApplicationHome(FileUtils.class);
File jarFile = home.getSource();
return jarFile.getParentFile().toString();
}
/*获取用户上传pdf等文件的地址*/
// public String getFilePath(){
// return getJarPath()+ UPLOAD_PATH; //根据jar包所在地进行上传
//当前方法不推荐使用,既然是公共方法,那么路径应该在调用的地方传进来,而不是在当前文件中写死,毕竟不一定所有文件都相同路径
// return uploadFolder + File.separator; //固定某个位置上传上传 --》这样就不会出现测试环境与正式环境位置不相同,导致测试麻烦
// }
/*获取用户上传pdf等文件路径某个文件夹下的所有文件列表*/
public List<UploadFile> getFilesByPath(String filePath){
log.info("获取以下目录文件列表:" + filePath);
File directoryPath = new File(filePath); //获取已上传文件路径
File[] filesList = directoryPath.listFiles(); //已上传文件路径下的文件详情列表 directoryPath.list()>>文件名列表
if(null != filesList){
List<UploadFile> files = new ArrayList<>();
for(File file : filesList) {
//因当前方法是公共方法,不应该指定路径filePath,只获取文件名file.getName(),下载时再拼接完整路径
files.add(new UploadFile(org.apache.commons.io.FileUtils.sizeOf(file), file.getName() ));
}
return files;
}
return new ArrayList<>();
}
/*判断文件夹下是否有文件文件列表*/
public boolean hasFileForPath(String path){
File directoryPath = new File(path); //获取已上传文件路径
String[] files = directoryPath.list(); //已上传文件路径下的文件详情列表 directoryPath.list()>>文件名列表
return null != files && files.length > 0;
}
/*上传文件*/
public ReturnT fileUpload(MultipartFile file, String path) throws IOException {
BufferedOutputStream out = null;
String fileName = file.getOriginalFilename();
//1. 传入固定路径,判断是否已存在同名
File temp =new File(path + File.separator + fileName);
if(temp.exists()) {
return ReturnT.error("重复上传!");
}
long size = file.getSize()/1024/1024;//大小
if(size > 10){
return ReturnT.error("文件超出上传大小(10M)!");
}
String type = FileUtil.extName(fileName);//.jpg .pdf
assert type != null;
if(type.equalsIgnoreCase(".pdf")){
return ReturnT.error("只能上传pdf");
}
try {
MkdirsUtils.mkdirs(path);
out = new BufferedOutputStream(new FileOutputStream(path + File.separator + fileName));
out.write(file.getBytes());
out.flush();
} catch (IOException e) {
e.printStackTrace();
return ReturnT.error("上传异常失败!");
}catch (Exception ex){
return ReturnT.error(ex.getMessage());
}finally {
if(null != out){ //必须处理,否则想要再次删除文件得重启服务器,否则流一直开启是无法删除文件的
out.close();
}
}
log.info("在"+path+"路径下保存文件:" + fileName);
return ReturnT.success("上传成功");
}
/*下载或预览
* path:完整路径
* fileName: 文件名
* downOrRead = down -->下载 -------------else 预览
*/
public void pdfStreamHandler(String path, String fileName, String downOrRead, HttpServletResponse response) {
//PDF文件地址
File file = new File(path + File.separator + fileName);
if (file.exists()) {
byte[] data;
FileInputStream inStream=null;
try {
inStream = new FileInputStream(file);
data = new byte[inStream.available()];
if(downOrRead.equalsIgnoreCase("down")){ //如果是下载就需要设置格式,否则直接预览
response.reset();
response.setContentType("text/html;charset=utf-8");
//Content-Disposition的作用:告知浏览器以何种方式显示响应返回的文件,用浏览器打开还是以附件的形式下载到本地保存
//attachment表示以附件方式下载 inline表示在线打开
// filename表示文件的默认名称,因为网络传输只支持URL编码的相关支付,因此需要将文件名URL编码后进行传输,前端收到后需要反编码才能获取到真正的名称
response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
}
// 循环取出流中的数据
int len;
while ((len = inStream.read(data)) > 0) {
response.getOutputStream().write(data, 0, len);
}
} catch (Exception e) {
System.out.println("pdf文件处理异常:" + e);
}finally{
try {
if(inStream!=null){
inStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//下载通用方法 (文件详细路径例如:D://xxx//xxx.ppt, 文件名例如xxx.ppt)
public static ResponseEntity<InputStreamResource> downppt(String path, String fileName) throws Exception {
fileName = URLEncoder.encode(fileName, "utf-8"); // 导包时不要导错了是java.net的包,如果导入deploy的包是无法打包的,因为这是JDK自带的包不参与打包,所以找不到这个类
return ResponseEntity.ok().contentType(MediaType.APPLICATION_OCTET_STREAM)
.header("Content-disposition", "attachment; filename=" + fileName)
.body(new InputStreamResource(new FileInputStream(path)));
}
/* 删除文件 */
public ReturnT delFile(String filePath) {
try {
File temp = new File(filePath);
log.info("删除文件:" + filePath );
if(temp.exists()) {
return temp.delete()?ReturnT.success("del_success"):ReturnT.error("del_error!");
}else{
return ReturnT.success("文件不存在,前端可直接删除");
}
} catch (Exception e) {
e.printStackTrace();
log.error("文件删除异常", e);
return ReturnT.error("文件删除异常");
}
}
}
涉及到的实体1(文件列表实体):
@Data
public class UploadFile {
private long size;
private String fileName ; //因下载或上传方法是公共方法,不应该指定路径,只获取文件名,下载时再拼接完整路径
public UploadFile(long size, String fileName) {
this.size = size;
this.fileName = fileName;
}
}
涉及到的实体2(Controller统一返回结果实体):
import lombok.Data;
/**
* @author hewenjun
* @version 1.0
* @date 2022/06/23 16:08
*/
@Data
public class ReturnT {
private Integer code; //默认值时0,因为Layui取table值时返回code不是0就会报错格式不正确
private String msg;
private Object data;
private Integer count;
private Object result;
public ReturnT(Integer code, String msg, Integer count, Object result) { //返回code,msg,分页数据总条数, 分页数据
this.code = code;
this.msg = msg;
this.count = count;
this.data = result;
}
public ReturnT(Integer code) {
this.code = code;
}
public ReturnT(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public ReturnT(int code, String msg, Object data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public static ReturnT error(){ return new ReturnT(400); }
public static ReturnT error(int code){ return new ReturnT(code); }
public static ReturnT error(String msg){
return new ReturnT(400, msg);
}
public static ReturnT error(int code, String msg){
return new ReturnT(code, msg, msg);
}
public static ReturnT error(String msg, Object data){
return new ReturnT(0, msg, data);
}
public static ReturnT success(){ return new ReturnT(0); }
public static ReturnT success(int code){ return new ReturnT(code); }
public static ReturnT success(String msg){ return new ReturnT(0, msg); }
public static ReturnT success(String msg, Object data){ return new ReturnT(0, msg, data); }
public static ReturnT success(int code, String msg){ return new ReturnT(code, msg); }
public static ReturnT success(Integer count, Object result){
return new ReturnT(0, "获取成功", count, result);
}