一、上传功能
1. 后端代码
-
pom.xml
引入依赖
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
- com.xx.xx.controller.CommonController
@Api(tags = "通用方法")
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
CommonService commonService;
@ApiOperation(value = "上传单文件", notes = "参数:")
@PostMapping("/upload_file")
public ServerResponse uploadFile(@RequestParam("file") MultipartFile[] file) throws IOException, InvalidExtensionException, FileUploadBase.FileSizeLimitExceededException {
FileVo fileVo = commonService.uploadFile(file);
return ServerResponse.createBySuccess("上传文件成功!",fileVo);
}
}
- com.xx.xx.service.CommonService
public interface CommonService {
FileVo uploadFile(MultipartFile[] file) throws IOException, InvalidExtensionException, FileUploadBase.FileSizeLimitExceededException;
}
- com.xx.xx.service.impl.CommonServiceImpl
@Service
public class CommonServiceImpl implements CommonService {
@Value("${upload.dir}")
String fileDir;
@Override
public FileVo uploadFile(MultipartFile[] files) throws IOException, InvalidExtensionException, FileSizeLimitExceededException {
UUID uuid = UUID.randomUUID();
String folderPath = fileDir + uuid.toString();
MultipartFile file = files[0];
// 文件大小校验
FileUploadUtil.assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
String filePath = folderPath + "/" + file.getOriginalFilename();
String dbPath = uuid.toString() + "/" + file.getOriginalFilename();
FileUploadUtil.uploadFile(folderPath, filePath, file);
FileVo fileVo = new FileVo();
fileVo.setFileName(file.getOriginalFilename());
fileVo.setFilePath(dbPath);
return fileVo;
}
}
-
com.xx.xx.utils.FileUploadUtil
文件上传工具类
public class FileUploadUtil {
/**
* 默认大小 50M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
/**
* 上传文件工具类
*
* @param path 文件夹位置
* @param filePath 文件的全路径名
* @param file 文件
* @throws IOException
*/
public static void uploadFile(String path, String filePath, MultipartFile file) throws IOException {
File fileDir = new File(path);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
try {
file.transferTo(new File(filePath).getAbsoluteFile());
} catch (IOException e) {
e.printStackTrace();
throw e;
}
}
/**
* 判断MIME类型是否是允许的MIME类型
*
* @param extension
* @param allowedExtension
* @return
*/
public static boolean isAllowedExtension(String extension, String[] allowedExtension) {
for (String str : allowedExtension) {
if (str.equalsIgnoreCase(extension)) {
return true;
}
}
return false;
}
/**
* 获取文件名的后缀
*
* @param file 表单文件
* @return 后缀名
*/
public static String getExtension(MultipartFile file) {
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
if (extension == null || extension.equals("")) {
extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
}
return extension;
}
/**
* 文件大小校验
*
* @param file 上传的文件
* @return
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws InvalidExtensionException
*/
public static void assertAllowed(MultipartFile file, String[] allowedExtension)
throws InvalidExtensionException, FileSizeLimitExceededException {
long size = file.getSize();
if (size > DEFAULT_MAX_SIZE)
throw new FileSizeLimitExceededException("upload.exceed.maxsize", size, DEFAULT_MAX_SIZE / 1024 / 1024);
String fileName = file.getOriginalFilename();
String extension = getExtension(file);
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
fileName);
} else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
fileName);
} else {
throw new InvalidExtensionException(allowedExtension, extension, fileName);
}
}
}
}
-
com.xx.xx.utils.MimeTypeUtils
媒体类型工具类
public class MimeTypeUtils
{
public static final String IMAGE_PNG = "image/png";
public static final String IMAGE_JPG = "image/jpg";
public static final String IMAGE_JPEG = "image/jpeg";
public static final String IMAGE_BMP = "image/bmp";
public static final String IMAGE_GIF = "image/gif";
public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
public static final String[] FLASH_EXTENSION = { "swf", "flv" };
public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
"asf", "rm", "rmvb" };
public static final String[] VIDEO_EXTENSION = { "mp4", "avi", "rmvb" };
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf" };
public static String getExtension(String prefix)
{
switch (prefix)
{
case IMAGE_PNG:
return "png";
case IMAGE_JPG:
return "jpg";
case IMAGE_JPEG:
return "jpeg";
case IMAGE_BMP:
return "bmp";
case IMAGE_GIF:
return "gif";
default:
return "";
}
}
}
-
com.xx.xx.exception.InvalidExtensionException
文件上传 误异常类
public class InvalidExtensionException extends FileUploadException
{
private static final long serialVersionUID = 1L;
private final String[] allowedExtension;
private final String extension;
private final String filename;
public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
{
super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
this.allowedExtension = allowedExtension;
this.extension = extension;
this.filename = filename;
}
public String[] getAllowedExtension()
{
return allowedExtension;
}
public String getExtension()
{
return extension;
}
public String getFilename()
{
return filename;
}
public static class InvalidImageExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidFlashExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidMediaExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
public static class InvalidVideoExtensionException extends InvalidExtensionException
{
private static final long serialVersionUID = 1L;
public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
{
super(allowedExtension, extension, filename);
}
}
}
2. 前端代码
-
element的upload组件
这里设置只能上传一个文件。
<el-upload
ref="upload"
action="/api/common/upload_file"
:on-remove="handleRemove"
:on-progress="handleFileUploadProgress"
:before-remove="beforeRemove"
:before-upload="beforeUpload"
:on-error = "handleError"
:on-success="uploadFileSuccess"
:limit="1"
:disabled="isUploading"
:on-exceed="handleExceed"
:file-list="fileList">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
</el-upload>
<script>
export default {
data() {
return {
isUploading: false,
fileList: []
};
},
methods: {
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
this.isUploading = true;
},
// 文件上传错误处理
handleError(err, file, fileList) {
this.isUploading = false;
this.$refs.upload.clearFiles();
this.$message.error('上传失败!上传文件大小限制50MB。')
},
// 文件上传相关回调
handleRemove(file, fileList) {
// 删除文件及其目录
if (this.formHandle.filePath !== '' && this.formHandle.filePath !== null){
request({
method: 'get',
url: 'common/delete_file',
params: {
fid: this.formHandle.fid,
fileName: this.formHandle.filePath,
}
}).then(() => {
this.$refs.upload.clearFiles();
this.formHandle.filePath = null;
})
}
},
// 上传限制处理
handleExceed(files, fileList) {
this.$message.warning(`当前限制上传 1 个文件,如需上传多个文件,请打包压缩后上传!`);
},
// 上传之前处理
beforeUpload(file, fileList) {
return this.$confirm(`确定上传 ${file.name} 到服务器吗 ?`, '上传提示', {
type: 'warning',
});
},
// 移除之前处理
beforeRemove(file, fileList) {
return this.$confirm(`确定移除 ${file.name} ?`, '删除提示', {
type: 'error',
});
},
// 上传成功后处理
uploadFileSuccess(response, file, fileList) {
this.isUploading = false;
this.uploadFilePath = response.data.filePath;
console.log('uploadFileSuccess!~', this.uploadFilePath)
},
}
</script>
二、 下载功能
1. 后端代码
- com.xx.xx.controller.CommonController
@Api(tags = "通用方法")
@RestController
@RequestMapping("/common")
public class CommonController {
@Autowired
CommonService commonService;
@Autowired
ExamineInfoService examineInfoService;
@Value("${upload.dir}")
String downloadPath;
/**
* 通用下载请求
*
* @param fileName 文件名称
* @param delete 是否删除
*/
@ApiOperation(value = "通用下载请求", notes = "参数:")
@GetMapping("/download")
public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) {
try {
if (!FileUtils.checkAllowDownload(fileName)) {
throw new Exception("文件非法,不允许下载。");
}
String realFileName = fileName.substring(fileName.lastIndexOf('/') + 1);
String filePath = downloadPath + fileName;
response.setContentType("application/octet-stream");
FileUtils.setAttachmentResponseHeader(response, realFileName);
FileUtils.writeBytes(filePath, response.getOutputStream());
// 下载完是否删除该文件
if (delete) {
FileUtils.deleteFile(filePath);
}
} catch (Exception ignored) {
}
}
}
- com.xx.xx.utils.FileUtils
public class FileUtils {
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
// 图片
"bmp", "gif", "jpg", "jpeg", "png",
// word excel powerpoint
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
// 压缩文件
"rar", "zip", "gz", "bz2",
// 视频格式
"mp4", "avi", "rmvb",
// pdf
"pdf"};
/**
* 获取文件类型
* <p>
* 例如: ruoyi.txt, 返回: txt
*
* @param fileName 文件名
* @return 后缀(不含".")
*/
public static String getFileType(String fileName) {
int separatorIndex = fileName.lastIndexOf(".");
if (separatorIndex < 0) {
return "";
}
return fileName.substring(separatorIndex + 1).toLowerCase();
}
/**
* 检查文件是否可下载
*
* @param resource 需要下载的文件
* @return true 正常 false 非法
*/
public static boolean checkAllowDownload(String resource) {
// 禁止目录上跳级别
if (StringUtils.contains(resource, "..")) {
return false;
}
// 检查允许下载的文件规则
return ArrayUtils.contains(DEFAULT_ALLOWED_EXTENSION, getFileType(resource));
// 不在允许下载的文件规则
}
/**
* 下载文件名重新编码
*
* @param response 响应对象
* @param realFileName 真实文件名
* @return
*/
public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException {
String percentEncodedFileName = percentEncode(realFileName);
StringBuilder contentDispositionValue = new StringBuilder();
contentDispositionValue.append("attachment; filename=")
.append(percentEncodedFileName)
.append(";")
.append("filename*=")
.append("utf-8''")
.append(percentEncodedFileName);
response.setHeader("Content-disposition", contentDispositionValue.toString());
}
/**
* 百分号编码工具方法
*
* @param s 需要百分号编码的字符串
* @return 百分号编码后的字符串
*/
public static String percentEncode(String s) throws UnsupportedEncodingException {
String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
return encode.replaceAll("\\+", "%20");
}
/**
* 输出指定文件的byte数组
*
* @param filePath 文件路径
* @param os 输出流
* @return
*/
public static void writeBytes(String filePath, OutputStream os) throws IOException {
FileInputStream fis = null;
try {
File file = new File(filePath);
if (!file.exists()) {
throw new FileNotFoundException(filePath);
}
fis = new FileInputStream(file);
byte[] b = new byte[1024];
int length;
while ((length = fis.read(b)) > 0) {
os.write(b, 0, length);
}
} catch (IOException e) {
throw e;
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
/**
* 删除文件
*
* @param filePath 文件
*/
public static void deleteFile(String filePath) {
// boolean flag = false;
File file = new File(filePath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
// 获取父目录,并删除父目录文件夹
File parentFile = file.getParentFile();
if (parentFile.isDirectory() && parentFile.exists()){
parentFile.delete();
}
// flag = true;
}
}
}
2. 前端代码
- src.utils.common.js
const baseURL = '/api'
// 通用下载方法
export function download(fileName) {
window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + false;
}
-
src.main.js
全局挂载
import {download} from "./utils/common";
Vue.prototype.download = download
- 示例
<div class="pull-right">
<el-link @click="downloadFile(lawDetail.filePath)">{{downloadFilePath.split("/")[1]}}
</el-link>
</div>
<script>
data: function () {
return {
downloadFilePath: "",
lawDetail: [],
}
},
export default {
methods: {
downloadFile(fileName) {
this.download(fileName);
},
}
}
参考: 若依后端手册 - 上传下载