Springboot文件上传下载
文件的上传操作
前端代码
<form action="http://localhost:8091/file" method="post"
enctype="multipart/form-data">
<input name="fileImage" type="file" />
<input type="submit" value="提交"/>
</form>
服务端controller
@RequestMapping("/upload")
public String file(MultipartFile fileImage) {
String fileDirPath = "D:/images"; // 存放位置
File dirFile = new File(fileDirPath);
// 判断文件目录是否存在
if (!dirFile.exists()) {
// 如果目录没有, 则应该新建目录
dirFile.mkdir();
}
// 准备文件上传路径, 路径 + 文件名称
String fileName = fileImage.getOriginalFilename(); // 获取文件名
File realFile = new File(fileDirPath + "/" + fileName); // 保存磁盘路径 + 文件名拼接
// 将字节信息输出到文件中
try {
fileImage.transferTo(realFile); // 保存到指定的路径
return "文件上传成功";
} catch (IOException e) {
e.printStackTrace();
return "文件上传失败";
}
}
文件下载操作
下载操作也是非常的简单, 我们只需要用流的形式返回到客户端即可
别看长, 其实没多少代码
@RequestMapping("/download")
@ResponseBody
public String downloadFile(HttpServletResponse response) {
String fileName = "aaa.txt";// 设置文件名,即用户下载得到文件的名字(可以和磁盘中的文件名不同)
if (fileName != null) {
//设置文件路径
String filePath = "D:/file/001.txt"; // 要下载的文件位置
File file = new File(filePath);
if (file.exists()) {
// 关于: application/octet-stream
// 1、只能提交二进制,而且只能提交一个二进制,如果提交文件的话,只能提交一个文件,后台接收参数只能有一个,而且只能是流(或者字节数组)
// 2、属于HTTP规范中Content-Type的一种
// 3、很少使用
response.setContentType("application/octet-stream");
// response.setHeader("content-type", "application/octet-stream"); // 也可以这样写
response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名
byte[] buffer = new byte[1024];
FileInputStream fis = null;
BufferedInputStream bis = null;
try {
fis = new FileInputStream(file);
bis = new BufferedInputStream(fis);
OutputStream os = response.getOutputStream();
int i = bis.read(buffer);
while (i != -1) {
os.write(buffer, 0, i);
i = bis.read(buffer);
}
System.out.println("success"); // 下载成功返回信息
} catch (Exception e) {
e.printStackTrace();
} finally { // 关闭流
if (bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null; // 下载失败返回信息
}
扩展: 上传图片并校验
上传图片是经常有的操作, 所以在上传图片的时候也要对文件进行校验, 防止不符合规范的文件或者伪装的木马病毒等, 例如:
- 校验文件的有效性
- 校验文件是否为恶意程序
- 提高用户简餐图片的效率 分目录存储
- 为了防止重名图片的提交 自定义文件名
- 实现图片的物理上传
- 准备一个访问的虚拟路径
Controller编写
@Autowarld
private FileService fileService;
@RequestMapping("/pic/upload")
public ImageVO upload(MultipartFile uploadFile) {
return fileService.upload(uploadFile); // 调用service进行保存图片
}
Service编写(接口略)
service类-结构
@Service
public class FileServiceImpl implements FileService {
@Override
public ImageVO upload(MultipartFile uploadFile) {
}
}
1.校验文件后缀
service中定义一个localDirPath静态变量, 用于存储支持的图片你后缀, 例如:
private static Set<String> imageTypeSet = new HashSet<>();
static {
imageTypeSet.add(".jps");
imageTypeSet.add(".png");
imageTypeSet.add(".gif");
imageTypeSet.add("/bmp");
//.....其他省略
}
upload方法中
// 1. 图片的类型 (1) 利用正则表达式 (2) 利用集合的方式进行校验Set 数据是否存在即可
String fileName = uploadFile.getOriginalFilename();
// 获取后缀 并转为全小写
String fileType = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
if (!imageTypeSet.contains(fileType)) { // 如果后缀没在集合中, 则上传失败
return ImageVO.fail();
}
2.检验是否为图片
upload方法中
// 2. 如何判断文件是否为恶意程序, 是否有图片的属性
// 2.1 将上传文件类型利用图片API进行转化
try {
BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
// 2.2 校验是否有图片的特有属性 高度, 宽度
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
// 2.3 校验宽度和高度是否有值
if (width == 0 || height == 0) {
return ImageVO.fail();
}
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
3.分目录存储
service中定义属性, 表示文件存储的位置根路径
private String localDirPath = "D:/images"; // 定义本地磁盘目录
upload方法中
// 3. 实现分目录存储:
// 方案1: 利用hash之后每隔2-3位截取之后拼接
// 方案2: 以时间为单位进行分割 /yyyy/MM/dd/ 这里使用方案2, 方案1自行脑补
// 3.1 利用工具的API将时间转化为执行的格式
String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
// 3.2 动态生成文件目录 2部分=根目录+时间目录
String localDir = localDirPath + datePath;
// 3.3 判断目录是否存在, 如果不存在则新建目录
File dirFile = new File(localDir);
if (!dirFile.exists()) {
dirFile.mkdirs(); // 如果不存在, 则新建目录
}
4.自定义文件名称
使用UUID自定义名称
//4. 防止文件重名, 需要自定义文件名称 UUID
//4.1 生成uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
//4.2动态生成文件名称
String uuidFileName = uuid + fileType;
5.保存上传的文件
// 5. 实现文件的上传
String realFilePath = localDir + uuidFileName;
// 5.1 封装文件的真实对象
File imageFile = new File(realFilePath);
// 5.1 实现文件的保存
try {
uploadFile.transferTo(imageFile);
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
6.返回虚拟url路径
// 6.暂时使用京东的路径代替
// 检查文件上传业务调用是否正确
// [http://image.jt.com] + [/yyyy/MM/dd/] + [文件名]
String url = urlPath + datePath + uuidFileName;
return ImageVO.succcess(url);
完整文件如下
@Service
@PropertySource("classpath:/properties/image.properties")
public class FileServiceImpl implements FileService {
private static Set<String> imageTypeSet = new HashSet<>();
@Value("${image.localDirPath}")
private String localDirPath; // 定义本地磁盘目录
static {
imageTypeSet.add(".jps");
imageTypeSet.add(".png");
imageTypeSet.add(".gif");
imageTypeSet.add("." +
"bmp");
//.....其他省略
}
@Value("${image.urlPath}")
private String urlPath;
/**
* 1. 校验文件的有效性 .jsp|.png|.bmp|.gif
* 2. 校验文件是否为恶意程序
* 3. 提高用户简餐图片的效率 分目录存储
* 4. 为了防止重名图片的提交 自定义文件名
* 5. 实现图片的物理上传
* 6. 准备一个访问的虚拟路径
*/
@Override
public ImageVO upload(MultipartFile uploadFile) {
// 1. 图片的类型 (1) 利用正则表达式 (2) 利用集合的方式进行校验Set 数据是否存在即可
String fileName = uploadFile.getOriginalFilename();
// 获取后缀 并转为全小写
String fileType = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
if (!imageTypeSet.contains(fileType)) {
return ImageVO.fail();
}
// 2. 如何判断文件是否为恶意程序, 是否有图片的属性
// 2.1 将上传文件类型利用图片API进行转化
try {
BufferedImage bufferedImage = ImageIO.read(uploadFile.getInputStream());
// 2.2 校验是否有图片的特有属性 高度, 宽度
int width = bufferedImage.getWidth();
int height = bufferedImage.getHeight();
// 2.3 校验宽度和高度是否有值
if (width == 0 || height == 0) {
return ImageVO.fail();
}
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
// 3. 实现分目录存储:
// 方案1: 利用hash之后每隔2-3位截取之后拼接
// 方案2: 以时间为单位进行分割 /yyyy/MM/dd/
// 3.1 利用工具的API将时间转化为执行的格式
String datePath = new SimpleDateFormat("/yyyy/MM/dd/").format(new Date());
// 3.2 动态生成文件目录 2部分=根目录+时间目录
String localDir = localDirPath + datePath;
// 3.3 判断目录是否存在, 如果不存在则新建目录
File dirFile = new File(localDir);
if (!dirFile.exists()) {
dirFile.mkdirs(); // 如果不存在, 则新建目录
}
//4. 防止文件重名, 需要自定义文件名称 UUID
//4.1 生成uuid
String uuid = UUID.randomUUID().toString().replace("-", "");
//4.2动态生成文件名称
String uuidFileName = uuid + fileType;
// 5. 实现文件的上传
String realFilePath = localDir + uuidFileName;
// 5.1 封装文件的真实对象
File imageFile = new File(realFilePath);
// 5.1 实现文件的保存
try {
uploadFile.transferTo(imageFile);
} catch (IOException e) {
e.printStackTrace();
return ImageVO.fail();
}
// 6.暂时使用京东的路径代替
// 检查文件上传业务调用是否正确
// [http://image.jt.com] + [/yyyy/MM/dd/] + [文件名]
String url = urlPath + datePath + uuidFileName;
return ImageVO.succcess(url);
}
}
页面显示图片
可参考nginx中的图片服务器配置 [点击跳转到nginx图片服务器配置]