JavaWeb 课堂笔记 —— 19 SpringBootWeb案例 文件上传
本文摘要了JavaWeb开发中的文件上传功能实现过程,内容涵盖:
- 新增员工功能的RESTful接口设计与实现;
- 前端文件上传的三要素(file表单项、POST方法、multipart编码);
- 服务端通过MultipartFile接收文件,并演示临时文件处理;
- 本地存储方案实现及UUID防重名优化。
文章采用代码片段+截图的方式,详细展示了从接口定义到前后端联调的完整开发流程,适合JavaWeb初学者参考学习。
本系列为笔者学习JavaWeb的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员JavaWeb开发教程,实现javaweb企业开发全流程(涵盖Spring+MyBatis+SpringMVC+SpringBoot等)》,章节分布参考视频教程,为同样学习JavaWeb系列课程的同学们提供参考。
01 新增员工
① 需求 + 思路
请求数据:
{"image": "https://web-framework.oss-cn-hangzhou.aliyuncs.com/2022-09-03-07-37-38222.jpg","username": "linpingzhi","name":"林平之","gender": 1,"job": 1,"entrydate": "2022-89-18","deptId": 1
}
响应数据:
{"code": 1,"msg": "success","data": null
}
② 牛马开发
EmpController.java
@PostMapping("/emps")
public Result save(@RequestBody Emp emp){log.info("新增员工,emp:{}", emp);empService.save(emp);return Result.success();
}
EmpService.java
void save(Emp emp);
EmpServiceImpl.java
@Override
public void save(Emp emp){//补全基本信息emp.setCreateTime(LocalDateTime.now());emp.setUpdateTime(LocalDateTime.now());empMapper.insert(emp);
}
EmpMapper.java
//基于注解的insert操作
@Insert("insert into emp {username, name, gender, image, job, entrydate, dept_id, create_time, update_time}" "values(#{username}, #{name}, #{gender}, #{image}, #{job}, #{entrydate}, #{deptId}, #{createTime}, #{updateTime})")
void insert(Emp emp);
③ Postman
测试 + 前后端联调测试
02 文件上传(前端)
文件上传,是指将本地图片、视频、音频等文件上传到服务器,供其他用户浏览或下载的过程,其在项目中应用非常广泛,比如发微博,发微信朋友圈。
文件上传三要素
① 表单项file
<form action="/upload" method="post" enctype="multipart/form-data">姓名: <input type="text" name="username"><br>年龄: <input type="text" name="age"><br>头像: <input type="file" name="image"><br><input type="submit" value="提交">
</form>
② 提交方式 post
③ 编码格式 multipart
upload.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>上传文件</title>
</head>
<body><form action="/upload" method="post" enctype="multipart/form-data">姓名: <input type="text" name="username"><br>年龄: <input type="text" name="age"><br>头像: <input type="file" name="image"><br><input type="submit" value="提交"></form></body>
</html>
Google
浏览器打开
注:boundary
为分割符,用来将请求数据分隔为不同部分。
03 文件接收(服务端)
upload
参数列表:String username、Integer age、MultipartFile image
牛马开发:
① UploadController.java
@Slf4j
@RestController
public class UploadController {@PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image){log.info("文件上传:{}, {}, {}", username, age, image);return Result.success();}
}
② Debug
模式启动IDEA
,Google
浏览器输入localhost:8080/upload.html
,输入姓名、年龄和选择文件,点击提交
③ 复制临时文件路径C:\Users\zz\AppData\Local\Temp\tomcat.8080.14589401216072368145\work\Tomcat\localhost\ROOT
,将临时文件复制粘贴到桌面,修改文件名为1.txt
、2.txt
、3.txt
,点击放行 ||》键,临时文件被删除
04 临时文件存储(本地存储)
① UploadController.java
@Slf4j
@RestController
public class UploadController {@PostMapping("/upload")public Result upload(String username, Integer age, MultipartFile image) throws Exception {log.info("文件上传:{}, {}, {}", username, age, image);//调用MultipartFile方法,获取原始文件名String originalFilename = image.getOriginalFilename();//本地存储 E:\imagesimage.transferTo(new File("E:\\images\\" + originalFilename));return Result.success();}
}
② Debug
模式启动IDEA
,Postman
中输入请求地址localhost:8080/upload
,传输文件QQ头像.jpg
,发送请求
③ 文件自动保存到路径E://images
,终身文件不被删除
注:此方法存在隐患,当两个用户同时传输名为1.jpg
文件时,会导致数据覆盖问题,因此采用UUID
标准统一标识符创建唯一文件名。
//构造唯一文件名
int index = originalFilename.lastIndexOf(".");
String extname = originalFilename.substring(index);
String newFileName = UUID.randomUUID().toString() + extname;
log.info("新的文件名:{}", newFileName);
注:此方法存在隐患,当传输文件过大时,会导致服务端异常,号码为500,具体为FilesizeLimitExceededException
,默认情况下,上传文件最大为1MB
。
修改配置
#配置单个 文件 最大上传大小
spring.servlet.multipart.max-file-size=10MB
#配置单个 请求 最大上传大小(一次请求可以上传多个文件)
spring.servlet.multipart.max-request-size=100MB
总结:本地存储有几个缺点,会导致程序无法直接访问文件,如果磁盘满了或坏了,维修起来会比较麻烦,因此,近年来已经逐渐被企业开发所淘汰。如今,程序员要么基于FastDFS、MinIO
等分布式文件系统,自己构建一个文件存储服务,要么依赖公开的云服务,比如阿里云、腾讯云、百度云等,上传自己的文件并支付相应费用。
05 临时文件存储(阿里云)
阿里云时阿里巴巴旗下的云计算公司,也是国内最大的云服务提供商,云可以简单理解为互联网。
阿里云OSS
阿里云对象存储OSS(Object Storage Service)
,是一款海量、安全、低成本、高可靠的云存储服务,使用OSS
,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。
第三方服务通用思路
SDK(Software Development Kit)
为软件开发工具包,包括辅助软件开发的依赖(jar包)
、代码示例等,都可以叫做SDK
。
① 准备工作
Bucket
存储空间是用户用于存储对象(Object,就是文件)
的容器,所有的对象都必须隶属于某个存储空间。
完成阿里云服务注册和实名认证之后,开通对象存储OSS
服务,创建自定义bucket
,名称为hmleadnews1988
,地域为华东1(杭州),创建后关闭阻止公共访问,修改访问权限为公共读。
创建AccessKey
,获取对应ID
和密钥
AccessKey ID
:LTAI5tNddW7JFUeFaPW6DNwH
AccessKey Secret
:9BhAvB8X64d8axPyfeRVPm4j809qoH
Bucket Name
:hmleadnews1988
② 参考官方SDK
编写入门程序
在SDK
下载示例当中,查看如何安装SDK
,复制Maven
相关依赖到IDEA
的pom.xml
当中。
<!--阿里云OSS--><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version></dependency><dependency><groupId>javax.xml.bind</groupId><artifactId>jaxb-api</artifactId><version>2.3.1</version></dependency><dependency><groupId>javax.activation</groupId><artifactId>activation</artifactId><version>1.1.1</version></dependency><!-- no more than 2.3.3--><dependency><groupId>org.glassfish.jaxb</groupId><artifactId>jaxb-runtime</artifactId><version>2.3.3</version></dependency>
配置系统的环境遍比量,AccessKey ID
和AccessKey Secret
,参考如下命令。
点击运行IDEA
中Demo
的main
方法,上传一张图片到阿里云OSS
服务器当中。
③ 案例集成OSS
06 文件上传(服务端)
① 引入阿里云OSS
上传文件工具类(由官方示例代码改造)
AliOSSUtils.java
package com.itheima.utils;import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.UUID;/*** 阿里云 OSS 工具类*/
@Component //交给IOC容器管理
public class AliOSSUtils {private String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";private String accessKeyId = "LTAI5tNddW7JFUeFaPW6DNwH";private String accessKeySecret = "9BhAvB8X64d8axPyfeRVPm4j809qoH";private String bucketName = "hmleadnews1988";/*** 实现上传图片到OSS*/public String upload(MultipartFile file) throws IOException {// 获取上传的文件的输入流InputStream inputStream = file.getInputStream();// 避免文件覆盖String originalFilename = file.getOriginalFilename();String fileName = UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));//上传文件到 OSSOSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);ossClient.putObject(bucketName, fileName, inputStream);//文件访问路径String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;// 关闭ossClientossClient.shutdown();return url;// 把上传到oss的路径返回}}
② 牛马开发
UploadController.java
//阿里云存储
@PostMapping("/upload")
public Result upload(MultipartFile image) throws IOException {log.info("文件上传,文件名:{}", image.getOriginalFilename());//调用阿里云OSS工具类,将上传文件存入阿里云String url = aliOSSUtils.upload(image); //返回urllog.info("文件上传完成,文件访问的url:{}", url);return Result.success(url); //返回前端,浏览器展示
}
③ Postman
测试
④ 前后端联调测试