springboot實現(xiàn)圖片上傳與下載功能
寫一下后端spring項目經常要做的功能,實現(xiàn)圖片上傳和下載,這里也把前端代碼附上了??赡芩闶莻€簡單版的,我這里圖片上傳都存在當前項目的根目錄resource下了。
這里包含了,上傳文件、下載文件(下載文件流、獲取base64),service中還有個文件流轉base64的工具方法。
下面是后端代碼
Controller
package com.wft.controller;
import com.wft.model.ActionResult;
import com.wft.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
@RestController
@RequestMapping("/file")
public class TestController {
@Autowired
TestService testService;
/**
* 文件上傳
* @param file
* @return
* @throws IOException
*/
@PostMapping("/upload")
public ActionResult uploadTest(@RequestParam("file") MultipartFile file) throws IOException {
return testService.upload(file);
}
/**
* 文件下載
* @param name
* @return
* @throws FileNotFoundException
*/
@GetMapping("/download/{name}")
@CrossOrigin
public ResponseEntity<InputStreamResource> downloadTest(@PathVariable("name") String name) throws FileNotFoundException {
return testService.download(name);
}
/**
* 獲取文件的base64編碼
* @param name
* @return
* @throws IOException
*/
@GetMapping("/getBase64/{name}")
public ActionResult getBase64(@PathVariable("name") String name) throws IOException {
return testService.getBase64(name);
}
}Service接口就不貼了哈
ServiceImpl
package com.wft.service.impl;
import com.wft.model.ActionResult;
import com.wft.service.TestService;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.file.Files;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Service
public class TestServiceImpl implements TestService {
/**
* 文件上傳邏輯
* @param file
* @return
* @throws IOException
*/
@Override
public ActionResult upload(MultipartFile file) throws IOException {
if(file.isEmpty()) {
return ActionResult.fail("文件不能為空");
}
// 上傳的文件名稱
String originalFilename = file.getOriginalFilename();
// 文件后綴
String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
// 使用uuid當前文件名存儲,防止名稱相同覆蓋
String uuid = UUID.randomUUID().toString();
String fileName = uuid + suffix;
// 文件保存的路徑(我這里存在當前項目下,所以獲取當前項目的絕對路徑,然后拼接上圖片存放的文件夾的名稱)
String savePath = ResourceUtils.getURL("resource").getPath();
// 判斷是否存在resource目錄, 沒有則創(chuàng)建
File dir = new File(savePath);
if(dir != null && !dir.exists()) {
dir.mkdir();
}
savePath = savePath + File.separator + fileName;
// 文件上傳
file.transferTo(new File(savePath));
// 將文件存儲的名稱uuid和原文件名稱返回給前端
Map<String, Object> map = new HashMap<>();
map.put("id", uuid);
map.put("name", originalFilename);
// 將下載圖片的接口(返回文件流)路徑返回給前端,前端直接將服務器地址拼上該鏈接即可回顯圖片
map.put("url", "/file/download/" + fileName);
return ActionResult.success("上傳成功", map);
}
/**
* 文件下載邏輯(文件流)
* @param name
* @return
* @throws FileNotFoundException
*/
@Override
public ResponseEntity<InputStreamResource> download(String name) throws FileNotFoundException {
String path = ResourceUtils.getURL("resource").getPath() + File.separator + name;
File file = new File(path);
if(!file.exists()) {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
// 創(chuàng)建輸入流
InputStream inputStream = new FileInputStream(file);
// 設置HTTP頭部信息
HttpHeaders headers = new HttpHeaders();
System.out.println(file.getName() + "---->>>文件名");
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
// 返回文件流
ResponseEntity<InputStreamResource> body = ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(new InputStreamResource(inputStream));
return body;
}
/**
* 獲取文件的base64編碼
* @param name
* @return
* @throws IOException
*/
@Override
public ActionResult getBase64(String name) throws IOException {
String path = ResourceUtils.getURL("resource").getPath() + File.separator + name;
File file = new File(path);
if(!file.exists()) {
return ActionResult.fail("文件不存在");
}
byte[] fileContent = Files.readAllBytes(file.toPath());
String base64 = Base64.getEncoder().encodeToString(fileContent);
base64 = "data:image/png;base64," + base64;
return ActionResult.success((Object) base64);
}
/**
* 將文件流轉為base64編碼(工具方法, service中接口沒有該方法)
* @param response
* @return
* @throws IOException
*/
public String streamToBase64(ResponseEntity<InputStreamResource> response) throws IOException {
// 獲取InputStreamResource對象
InputStreamResource resource = response.getBody();
if (resource == null) {
throw new IllegalArgumentException("Response body is null");
}
try (InputStream inputStream = resource.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, bytesRead);
}
// 將InputStream轉換為字節(jié)數(shù)組
byte[] fileBytes = byteArrayOutputStream.toByteArray();
// 使用Base64編碼器進行編碼
String base64Encoded = Base64.getEncoder().encodeToString(fileBytes);
base64Encoded = "data:image/png;base64," + base64Encoded;
return base64Encoded;
}
}
}
代碼里面也都寫注釋了,大家一看應該就明白了。
簡單說一下思路把,存圖片的時候,我是以uuid當作圖片的名稱存儲的,這樣即便是前端是兩個文件,但是名稱一樣,上傳之后也不會覆蓋掉原來的圖片。
然后圖片上傳完之后,我把回顯圖片的路徑返回給前端了,前端可以使用服務器地址(當然開發(fā)環(huán)境下會有跨域問題,一般會直接用前綴)拼上返回的這個路徑即可回顯圖片。
返回的這個url其實就是后端編寫好的一個接口,返回的是個文件流,前端直接將完整的請求的后端的路徑放在img標簽的src上,其實就相當于發(fā)送了請求,所以這里注意這種方式回顯要求后端將改接口放在白名單中(即該接口不需要token校驗),否則前端就不能像正常路徑一樣直接放在img的src上回顯,就要像普通的接口一樣調用接口,然后通過URL.createObjectURL(new Blob(res))的方式轉為路徑再復制給src。
然后我上面封裝了了個ActionResult的返回給前端的包裝類,也在這貼一下吧:
ActionResult
package com.wft.model;
import lombok.Data;
@Data
public class ActionResult<T> {
private Integer code;
private String msg;
private T data;
public static ActionResult success() {
ActionResult jsonData = new ActionResult();
jsonData.setCode(200);
jsonData.setMsg("success");
return jsonData;
}
public static ActionResult success(String msg) {
ActionResult jsonData = new ActionResult();
jsonData.setCode(200);
jsonData.setMsg(msg);
return jsonData;
}
public static ActionResult success(Object object) {
ActionResult jsonData = new ActionResult();
jsonData.setData(object);
jsonData.setCode(200);
jsonData.setMsg("success");
return jsonData;
}
public static ActionResult success(String msg, Object object) {
ActionResult jsonData = new ActionResult();
jsonData.setData(object);
jsonData.setCode(200);
jsonData.setMsg(msg);
return jsonData;
}
public static ActionResult fail(Integer code, String message) {
ActionResult jsonData = new ActionResult();
jsonData.setCode(code);
jsonData.setMsg(message);
return jsonData;
}
public static ActionResult fail(String msg, String data) {
ActionResult jsonData = new ActionResult();
jsonData.setMsg(msg);
jsonData.setData(data);
return jsonData;
}
public static ActionResult fail(String msg) {
ActionResult jsonData = new ActionResult();
jsonData.setMsg(msg);
jsonData.setCode(400);
return jsonData;
}
}
接下來再貼一下前端代碼:
<template>
<div class="wft-test">
<el-upload
class="avatar-uploader"
:action="baseURL + '/file/upload'"
:show-file-list="false"
:on-success="handleAvatarSuccess"
>
<img v-if="imageUrl" :src="baseURL + imageUrl" class="avatar" />
<el-icon v-else class="avatar-uploader-icon"><Plus /></el-icon>
</el-upload>
<!-- 測試下載圖片 獲取文件流 -->
<el-button @click="testDownload('12b83c8d-3d54-420d-a191-bd750fa571c4.png')">測試下載圖片流</el-button>
<!-- 測試下載圖片 獲取base64 -->
<el-button @click="testDownloadBase64('12b83c8d-3d54-420d-a191-bd750fa571c4.png')">測試下載圖片base64</el-button>
<img style="width: 200px;height: 200px;" v-if="imgBase64" :src="imgBase64" alt="">
</div>
</template>
<script setup lang='ts'>
import { ref } from 'vue';
import request from '@/utils/request';
const imageUrl = ref("");
const imgBase64 = ref("");
// 上傳成功回調
function handleAvatarSuccess(res: any) {
if(res.code == 200) {
imageUrl.value = res.data.url // 正常成功回顯
}
}
/**
* 測試下載圖片(獲取文件流)
* @param fileName 文件名
*/
function testDownload(fileName: string) {
request({
url: `/file/download/${fileName}`,
method: 'get',
responseType: 'blob'
}).then((res: any) => {
const link = document.createElement('a')
link.href = URL.createObjectURL(new Blob([res]))
link.download = 'test.png'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
})
}
/**
* 測試下載圖片(獲取文件base64編碼)
* @param fileName
*/
function testDownloadBase64(fileName: string) {
request({
url: `/file/getBase64/${fileName}`,
method: 'get'
}).then((res: any) => {
if(res.code == 200) {
imgBase64.value = res.data
}
})
}
</script>
<style scoped>
.wft-test {
width: 100%;
height: 100%;
}
.avatar-uploader .avatar {
width: 178px;
height: 178px;
display: block;
}
</style>
<style>
.avatar-uploader .el-upload {
border: 1px dashed var(--el-border-color);
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: var(--el-transition-duration-fast);
}
.avatar-uploader .el-upload:hover {
border-color: var(--el-color-primary);
}
.el-icon.avatar-uploader-icon {
font-size: 28px;
color: #8c939d;
width: 178px;
height: 178px;
text-align: center;
}
</style>以上就是springboot實現(xiàn)圖片上傳與下載功能的詳細內容,更多關于springboot圖片上傳下載的資料請關注腳本之家其它相關文章!
相關文章
Java連接mysql數(shù)據(jù)庫的詳細教程(推薦)
這篇文章主要介紹了Java連接mysql數(shù)據(jù)庫的詳細教程,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08

