目录
一、简介
我们在工作和生活中经常遇到上传资料或者下载资料,这些资料可能是视频,语音,文件等等,我们统称为文件上传和文件下载,今天我们就基于Spring Boot,实现简单的文件上传下载功能。
二、maven依赖
本文用到的依赖如下:
pom.mxl
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.alian</groupId>
<artifactId>file</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>file</name>
<description>文件上传和下载</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.68</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.14</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
三、配置
3.1、application.yml
application.yml
server:
port: 8081
servlet:
context-path: /fileServer
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
freemarker:
request-context-attribute: request
charset: UTF-8
template-loader-path: classpath:/
suffix: .ftl
prefix: /view
app:
download-path: C:\\myFile\\download\\
upload-path: C:\\myFile\\upload\\
file-type-array: .png,.jpg,.jpeg,.txt,.zip,.rar,.pdf,.xml,xls
max-file-size: 8192
这个配置文件包含几个配置:
- tomcat容器配置
- springboot内部文件上传配置
- freemarker配置
- 自定义文件处理配置(app)
3.2、属性配置类
AppProperties.java
package com.alian.file.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(value = "app")
public class AppProperties {
/** * 上传路径 */
private String uploadPath = "";
/** * 下载路径 */
private String downloadPath = "";
/** * 文件类型 */
private String[] fileTypeArray;
/** * 文件大小 */
private int maxFileSize;
}
此配置类不懂的可以参考我另一篇文章:Spring Boot读取配置文件常用方式
四、工具类(非FTP)
4.1、文件上传
FileUploadUtil.java
package com.alian.file.utils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@Slf4j
public class FileUploadUtil {
/** * 上传文件 * * @param multiFile 文件 * @param uploadPath 服务器上要存储文件的路径 * @param uploadFileName 服务器上要存储的文件的名称 * @return */
public static boolean uploadToServer(MultipartFile multiFile, String uploadPath, String uploadFileName) {
//构建文件对象
File file = new File(uploadPath);
//文件目录不存在则递归创建目录
if (!file.exists()) {
boolean mkdirs = file.mkdirs();
if (!mkdirs) {
log.error("创建文件夹异常");
return false;
}
}
InputStream ins = null;
FileOutputStream outs = null;
try {
//获取文件输入流
ins = multiFile.getInputStream();
//构建文件输出流
outs = new FileOutputStream(uploadPath + uploadFileName);
int len;
byte[] bytes = new byte[1024];
//读取一个bytes的文件内容
while ((len = ins.read(bytes)) != -1) {
outs.write(bytes, 0, len);
}
outs.close();
log.info("上传成功:{}", uploadPath + uploadFileName);
return true;
} catch (IOException e) {
log.error("文件上传异常");
e.printStackTrace();
} finally {
try {
if (outs != null) {
outs.close();
}
if (ins != null) {
ins.close();
}
} catch (IOException e) {
log.error("关闭流异常");
e.printStackTrace();
}
}
return false;
}
/** * 新文件上传 * * @param multiFile 文件 * @param uploadPath 服务器上要存储文件的路径 * @param uploadFileName 服务器上要存储的文件的名称 * @return */
public static boolean newUploadToServer(MultipartFile multiFile, String uploadPath, String uploadFileName) {
//构建文件对象
File file = new File(uploadPath);
//文件目录不存在则递归创建目录
if (!file.exists()) {
boolean mkdirs = file.mkdirs();
if (!mkdirs) {
log.error("创建文件夹异常");
return false;
}
}
try {
//获取文件输入流
InputStream inputStream = multiFile.getInputStream();
//构建文件输出流
FileOutputStream outputStream = new FileOutputStream(uploadPath + uploadFileName);
int copy = FileCopyUtils.copy(inputStream, outputStream);
log.info("上传成功,文件大小:{}", copy);
return true;
} catch (IOException e) {
log.error("文件上传异常", e);
e.printStackTrace();
}
return false;
}
}
文件上传我们这里写了两个方法,一个是原生的,一个是Spring Boot自带工具类org.springframework.util.FileCopyUtils里的,两个方法都可以了解下。
4.2、文件下载
FileDownloadUtil.java
package com.alian.file.utils;
import lombok.extern.slf4j.Slf4j;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
@Slf4j
public class FileDownloadUtil {
/** * 下载文件到服务器 * * @param downloadUrl 要下载的文件的地址 * @param downloadPath 服务器上存储的文件路径 * @param downloadFileName 服务器上存储的文件名称 * @return */
public static boolean downloadToServer(String downloadUrl, String downloadPath, String downloadFileName) {
FileOutputStream fos = null;
BufferedInputStream bis = null;
boolean flag = false;
try {
URL url = new URL(downloadUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.connect();
bis = new BufferedInputStream(connection.getInputStream());
File file = new File(downloadPath);
if (!file.exists()) {
boolean mkdirs = file.mkdirs();
if (!mkdirs) {
log.error("创建文件目录失败");
return false;
}
}
String filePathName = downloadPath + File.separator + downloadFileName;
byte[] buf = new byte[1024];
int size;
fos = new FileOutputStream(filePathName);
while ((size = bis.read(buf)) != -1) {
fos.write(buf, 0, size);
}
flag = true;
log.info("文件下载成功,文件路径[" + filePathName + "]");
flag = true;
} catch (Exception e) {
log.error("下载文件异常", e);
} finally {
try {
if (bis != null) {
bis.close();
}
if (fos != null) {
fos.close();
}
} catch (IOException e) {
log.error("关流异常", e);
e.printStackTrace();
}
}
return flag;
}
}
五、测试
5.1、远端下载到服务器
我们这里远端指定是一个地址通过获取到文件的情况,比如一个图片,或者文件,然后通过流处理生成我们要的文件,这里我们写个测试方法即可:
package com.alian.file.service;
import com.alian.file.utils.FileDownloadUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class TestService {
public static void main(String[] args) {
String downloadUrl = "http://invoice.shenzhentong.com/downInvoice/downpdf/914403007703110594/TG643260802798850048";
String filePath = "C:\\myFile\\download";
String fileName = "download.pdf";
FileDownloadUtil.downloadToServer(downloadUrl, filePath, fileName);
}
}
执行后,可以看到我们的目录下已经存在一个文件(C:\myFile\download\download.pdf):
5.2、服务器下载到客户端
服务器下载到客户端这种情况,一般是浏览器请求服务器进行文件下载,工具类已经实现了,我们写一个接口进行处理:
FileDownloadController.java
package com.alian.file.controller;
import com.alian.file.config.AppProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
@Slf4j
@RestController
@RequestMapping("/fileDownload")
public class FileDownloadController {
@Autowired
private AppProperties appProperties;
@RequestMapping(value = "/downloadToClient")
public void downloadToClient(HttpServletRequest request, HttpServletResponse response) {
String filePath = appProperties.getDownloadPath();
String fileName = "download.pdf";
String filePathName = filePath + File.separator + fileName;
BufferedInputStream bins = null;
BufferedOutputStream bouts = null;
try {
//同一个窗口下载多次,清除空白流
response.reset();
File file = new File(filePathName);
if (!file.exists()) {
log.error("要下载的文件不存在:{}", filePathName);
return;
}
bins = new BufferedInputStream(new FileInputStream(filePathName));
bouts = new BufferedOutputStream(response.getOutputStream());
String userAgent = request.getHeader("USER-AGENT").toLowerCase();
// 如果是火狐浏览器
if (userAgent.contains("firefox")) {
fileName = new String(fileName.getBytes(), "ISO8859-1");
} else {
fileName = URLEncoder.encode(fileName, "UTF-8");
}
//设置发送到客户端的响应的内容类型
response.setContentType("application/download");
//指定客户端下载的文件的名称
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
int len;
byte[] bytes = new byte[1024];
while ((len = bins.read(bytes)) != -1) {
bouts.write(bytes, 0, len);
}
//刷新流
bouts.flush();
log.info("下载完成");
} catch (IOException e) {
log.error("下载文件异常:{}", e.getMessage());
e.printStackTrace();
} finally {
try {
if (bouts != null) {
bouts.close();
}
if (bins != null) {
bins.close();
}
} catch (IOException e) {
log.error("关闭流异常", e);
e.printStackTrace();
}
}
}
}
我们就把我们上一个事例里下载到服务的文件下载到客户端,请求地址:http://localhost:8081/fileServer/fileDownload/downloadToClient我们浏览器里就可以自动下载了
5.3、浏览器上传到服务端
文件的具体路径是:resource/view/upload.ftl
upload.ftl
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>文件上传</title>
<script type="text/javascript" src="http://localhost:8081/fileServer/js/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="http://localhost:8081/fileServer/js/ajaxfileupload.js"></script>
<style> </style>
</head>
<body>
<script> function upload() {
var requestUrl= "http://localhost:8081/fileServer/fileUpload/uploadToServer"; $.ajaxFileUpload({
url:requestUrl, secureuri:true, //是否启用安全提交 dataType: 'text', //数据类型 fileElementId:'uploadFile', //表示文件域ID success: function(data,status){
alert(status); alert(data); }, //提交失败处理函数 error: function (data,status,e){
alert(status); } }); } </script>
<div>
<input type="file" name="uploadFile" id="uploadFile"/>
<button type="submit" value="" onclick="upload();">上传文件</button>
</div>
</body>
</html>
我这里简单的写个文件上传的页面,这里使用到了ajaxfileupload.js,大家可以去网上下载到,这里需要注意的是,下面三者要保持一致:
- input里的id值(id=“uploadFile”)
- ajax请求里的参数 fileElementId
- controller接口定义的参数uploadFile
我们再准备一个controller处理请求:
package com.alian.file.controller;
import com.alian.file.config.AppProperties;
import com.alian.file.utils.FileUploadUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Controller
@RequestMapping(value = "/fileUpload")
public class FileUploadController {
@Autowired
private AppProperties appProperties;
@RequestMapping(value = "upload")
public String index(HttpServletRequest request, HttpServletResponse response) {
return "/upload";
}
@ResponseBody
@RequestMapping(value = "/uploadToServer")
public String uploadToServer(HttpServletRequest request, @RequestParam(value = "uploadFile", required = false) MultipartFile multiFile) {
JSONObject json = new JSONObject();
try {
Pair<Boolean, String> pair = checkFile(multiFile);
if (!pair.getLeft()) {
json.put("msg", pair.getRight());
return json.toJSONString();
}
boolean b = FileUploadUtil.uploadToServer(multiFile, appProperties.getUploadPath(), multiFile.getOriginalFilename());
json.put("msg", b ? "上传成功" : "上传失败");
return json.toJSONString();
} catch (Exception e) {
log.error("系统异常e:", e);
json.put("msg", "上传失败");
return json.toJSONString();
}
}
public Pair<Boolean, String> checkFile(MultipartFile multiFile) {
if (multiFile.isEmpty()) {
return Pair.of(false, "文件为空");
}
//获取
String filename = multiFile.getOriginalFilename();
String contentType = multiFile.getContentType();
if (StringUtils.isBlank(filename)) {
return Pair.of(false, "文件名为空");
}
long size = multiFile.getSize();//字节
log.info("收到的请求文件信息:原生文件名:{},文件类型:{},文件大小:{}", filename, contentType, size);
//获取文件后缀
String suffix = filename.substring(filename.lastIndexOf("."));
//判断配置的文件列表里是否支持该文件类型
if (!ArrayUtils.contains(appProperties.getFileTypeArray(), suffix)) {
return Pair.of(false, "不支持该类型文件上传");
}
double fileSize = size / 1024.0;//单位kb
if (fileSize > appProperties.getMaxFileSize()) {
return Pair.of(false, "文件大小超过限制");
}
return Pair.of(true, "验证通过");
}
}
你可以对文件大小,类型等进行更严格的限制,我这里是粗略的处理了下,但是需要注意的是,文件上传的大小,在springBoot项目里文件上传的大小是 1M,所以需要你在 application.yml 增加如下配置(文章之前就已经贴出来了),并且要注意的是这里MB是大写,如果你书写时时红色的时候说明就是错误的。
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
运行结果:
浏览器请求:http://localhost:8081/fileServer/fileUpload/upload
在我们的上传目录即可看到我们上传的文件了
至此,我们的文件就已经上传到我们的服务器了。
结语
文件上传的方式有很多,实现方式也很多,本文主要是用原生java的方式来实现,后续我们有时间可以介绍一些其他的类库或者工具来实现。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/36068.html