SpringBoot与H5实现文件上传和下载
2023-07-21 本文已影响0人
h2coder
环境说明
- 前端:HTML\CSS\JavaScript + axios
- 后端:Java8 + SpringBoot
后端
依赖(pom.xml)
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zh</groupId>
<artifactId>spring-boot-file-upload</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<!--使用上springboot都必须要继承父模块-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/>
</parent>
<dependencies>
<!--spring-boot启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--junit启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--springmvc的启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<scope>compile</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!--字符串工具类-->
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
<build>
<!-- 设置打包的jar包名称,如果不设置,默认模块名为打包名称 -->
<!-- <finalName>spring-boot-file-upload</finalName> -->
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
配置
- 服务端口,8080
- 上传的文件大小设置,这里设置500MB
- 上传目录配置,注意window和linux的路径区别(Linux没有盘符)
# 服务端口
server:
port: 8080
# 文件上传配置
spring:
application:
name: spring-boot-file-upload
# SpringMVC,设置上传文件大小
servlet:
multipart:
max-file-size: 500MB
# 上传目录配置
upload:
# Windows文件上传到的目录地址
path: c:\Project\upload\file\
# Linux 文件上传目录
# path: /img/
启动类
@SpringBootApplication
//打印日志注解,是lombok提供的,打印日志时,会带有类全名、方法名、标识哪里输出的日志
@Slf4j
public class AppApplication {
public static void main(String[] args) {
SpringApplication.run(AppApplication.class, args);
log.info("项目启动成功");
}
}
跨域配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
// 是否发送Cookie
.allowCredentials(true)
// 放行哪些原始域
.allowedOriginPatterns("*")
// 放行哪些请求方式
.allowedMethods("GET", "POST", "PUT", "DELETE")
// 放行哪些原始请求头部信息
.allowedHeaders("*")
// 暴露哪些头部信息
.exposedHeaders("*");
}
}
服务配置
服务配置,用于获取服务器的IP和端口
@Component
public class ServerConfig implements ApplicationListener<WebServerInitializedEvent> {
/**
* 端口
*/
private int serverPort;
/**
* 获取服务器的访问Url
*/
public String getUrl() {
InetAddress address = null;
try {
address = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return "http://" + address.getHostAddress() + ":" + this.serverPort;
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
this.serverPort = event.getWebServer().getPort();
}
}
Controller控制器
/**
* 文件上传与下载接口
*/
@RestController
@RequestMapping("/common")
public class CommonController {
/**
* 存储上传文件的目录路径
*/
@Value("${upload.path}")
private String baseDir;
/**
* 服务端配置
*/
@Autowired
private ServerConfig serverConfig;
/**
* 上传文件
* MultipartFile:SpringMVC获取前端的输入文件流,封装的文件解析对象
* file:是 MultipartFile 对象参数的变量名(参数名),这个名字必须与前端传递的文件参数一致!,这里就是file
*/
@PostMapping("/upload")
public R<Map<String, String>> upload(MultipartFile file) throws IOException {
//判断上传目录是否存在,不存在则创建
File fileDir = new File(baseDir);
if (!fileDir.exists()) {
fileDir.mkdirs();
}
//获取上传的原始文件名
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
originalFilename = "";
}
//获取拓展名,截取最后一个.后面的字符串,就是拓展名
String extName = originalFilename.substring(originalFilename.lastIndexOf("."));
//直接使用原始文件名,会导致相同文件名的图片会覆盖,所以添加UUID作为文件夹
String fileName = UUIDUtils.getUUID() + extName;
//存储到服务器上
file.transferTo(new File(fileDir, fileName));
//构造访问文件Url,并返回
String fileUrl = serverConfig.getUrl() + "/common/download?name=" + fileName;
Map<String, String> resultMap = new HashMap<>();
resultMap.put("url", fileUrl);
return R.success(resultMap);
}
/**
* 文件下载
* 注意:方法返回值为void,而不是R,因为响应的是一个图片文件流,而不是json
*
* @param name 需要下载的文件名
* @param response 响应对象,用于输出文件流给客户端
*/
@GetMapping("/download")
public void download(String name, HttpServletResponse response) throws IOException {
//文件
File file = new File(baseDir + name);
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
ServletOutputStream out = response.getOutputStream();
//原生IO流实现
//输出文件到响应中
byte[] buf = new byte[1024];
int length;
while ((length = bis.read(buf)) != -1) {
out.write(buf, 0, length);
}
out.flush();
//关闭资源,ServletOutputStream out 响应输出流不需要关闭,Tomcat会帮我们关闭
bis.close();
//使用工具类实现
//IOUtils.copy(fis, out);
}
}
统一返回结果实体类
/**
* 统一返回结果实体
*/
@Data
public class R<T> implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 编码:1成功,0和其它数字为失败
*/
private Integer code;
/**
* 错误信息
*/
private String msg;
/**
* 数据对象
*/
private T data;
/**
* 动态数据对象
*/
private Map map = new HashMap();
public static <T> R<T> success(T object) {
R<T> r = new R<T>();
r.data = object;
r.code = 1;
return r;
}
public static <T> R<T> error(String msg) {
R r = new R();
r.msg = msg;
r.code = 0;
return r;
}
public R<T> add(String key, Object value) {
this.map.put(key, value);
return this;
}
}
UUID工具类
- 用于生成唯一Id,作为文件名
public class UUIDUtils {
public static String getUUID() {
return UUID.randomUUID().toString().replace("-", "");
}
public static Integer getUUIDInOrderId() {
int orderId = UUID.randomUUID().toString().hashCode();
orderId = orderId < 0 ? -orderId : orderId; //String.hashCode() 值会为空
return orderId;
}
}
前端
- 使用axios作为请求框架
前端页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片上传</title>
</head>
<body>
<!-- 文件选择元素 -->
<input type="file" class="upload">
<img src="" alt="" class="my-img">
<script src="../lib/axios.js"></script>
<script>
// 文件选择
const uploadInput = document.querySelector('.upload');
// 图片
const myImg = document.querySelector('.my-img');
/*
绑定值改变事件
通过文件input框的files属性,获取到文件列表
*/
uploadInput.addEventListener('change', function (e) {
// 获取上传的文件
const file = uploadInput.files[0];
// 创建FormData实例
const formData = new FormData();
// key是参数名,value是文件
formData.append('file', file);
const url = 'http://localhost:8080/common/upload';
// 发送请求,上传文件
axios({
url: url,
method: 'POST',
data: formData
}).then(result => {
console.log(result);
// 获取图片Url,并设置到图片
const imgUrl = result.data.data.url;
myImg.src = imgUrl;
});
});
</script>
</body>
</html>