要实现Java图片上传与删除,并使本地和服务器上都能同时正常使用。
1.定义线上线下文件保存和显示路径
application-dev.properties
kapok.SHOW_PIC_PREFIX = http://localhost:8910/image/
#mac
#kapok.SAVE_PATH = /Users/luoyihao/images/
#win
kapok.SAVE_PATH = C:\\images\\
application-prod.properties
kapok.SHOW_PIC_PREFIX = http://xxxxx.com:8500/image/
kapok.SAVE_PATH = /projects/compositive-system/images/
2.在上面两个配置文件加上图片上传限制配置(不加则会报上传图片大小超出限制的错误)
spring.servlet.multipart.max-file-size = 5MB
spring.servlet.multipart.max-request-size = 20MB
3.在Controller导入配置变量
@Value("${kapok.SHOW_PIC_PREFIX}")
private String showPicPrefix;
@Value("${kapok.SAVE_PATH}")
private String savePath;
4.图片上传接口
@RequestMapping(value = "/uploadPic", method = RequestMethod.POST)
public Result uploadPic(@RequestParam("id") int id, @RequestParam("file") MultipartFile file) {
if (file == null || file.isEmpty()) {
return ResultGenerator.genFailResult("上传文件为空");
}
String fileName = file.getOriginalFilename();
List<String> FILE_WHILE_EXT_LIST = Arrays.asList("JPG", "PNG", "JPEG", "GIF");
String fileExtName = fileName.substring(fileName.lastIndexOf(".") + 1);
if (FILE_WHILE_EXT_LIST.contains(fileExtName.toUpperCase())) {
String newFileName = UUID.randomUUID() + "." + fileExtName;
File dest = new File(savePath + newFileName);
if(!dest.getParentFile().exists()){
dest.getParentFile().mkdirs();
}
try {
file.transferTo(dest);
PointsExchange pointsExchange = pointsExchangeService.getById(id);
pointsExchange.setPic(newFileName);
pointsExchangeService.updateById(pointsExchange);
return ResultGenerator.genSuccessResult();
} catch (IOException e) {
e.printStackTrace();
return ResultGenerator.genFailResult("上传失败");
}
}
return ResultGenerator.genFailResult("图片格式不正确");
}
5.图片删除接口
@RequestMapping(value = "/delPic", method = RequestMethod.POST)
public Result delPic(@RequestBody PointsExchange pointsExchange) {
File file = new File(savePath + pointsExchange.getPic());
PointsExchange pe = pointsExchangeService.getById(pointsExchange.getId());
pe.setPic(Constants.DEFAULT_IMG);
pointsExchangeService.updateById(pe);
//判断文件存不存在
if (!file.exists()) {
return ResultGenerator.genFailResult("删除文件失败:" + pointsExchange.getPic() + "不存在!");
} else if (Constants.DEFAULT_IMG.equals(pointsExchange.getPic())) {
return ResultGenerator.genFailResult("该奖品没有图片");
} else {
//判断这是不是一个文件,ps:有可能是文件夹
if (file.isFile()) {
boolean res = file.delete();
return ResultGenerator.genSuccessResult(res);
}
}
return ResultGenerator.genFailResult("删除文件失败");
}
6.图片展示接口
@RequestMapping(value = "/list", method = RequestMethod.GET)
public Result list(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "0") Integer size) {
PageHelper.startPage(page, size);
QueryWrapper qw = new QueryWrapper();
qw.orderByAsc("points");
List<PointsExchange> list = pointsExchangeService.list(qw);
for (PointsExchange pe:list){
pe.setPic(showPicPrefix + pe.getPic());
}
PageInfo pageInfo = new PageInfo(list);
return ResultGenerator.genSuccessResult(pageInfo);
}
7.给继承自WebMvcConfigurationSupport的KapokWebMvcConfigurer类的addResourceHandlers方法增加一条语句
作用:将启动的服务上的/images/作为虚拟路径,映射到真实的图片保存路径,用于图片展示。
registry.addResourceHandler("/image/**").addResourceLocations("file:"+savePath+"/");
8.如果是用Docker部署,部署的时候要给docker run命令加上 -v 服务器真实目录:容器内部目录,实现文件夹的挂载,同步两边的文件。
docker run -d -p 8005:8910 -v /projects/compositive-system/images:/projects/compositive-system/images compositive-system
9.前端增加图片上传按钮
<a-upload
v-model:file-list="fileList"
name="file"
:headers="headers"
:action="url"
:before-upload="(file) => beforeUpload(file, record)"
:showUploadList="false"
@change="handleChange"
>
<a-button type="primary">
<upload-outlined></upload-outlined>
上传图片
</a-button>
</a-upload>
10.前端图片上传JS
const url = ref("");
const beforeUpload = (file, record) => {
url.value =
import.meta.env.VITE_APP_BASE_API +
"/pointsexchange/uploadPic?id=" +
record.id;
};
const fileList = ref([]);
const handleChange = (info) => {
if (info.file.status !== "uploading") {
console.log(info.file, info.fileList);
}
if (info.file.status === "done") {
console.log("info", info);
if (info.file.response.code == 200) {
message.success(`${info.file.name}上传成功`);
query();
} else {
message.error(info.file.response.message);
}
} else if (info.file.status === "error") {
message.error(`${info.file.name}上传失败`);
}
};
const headers = {
Authorization: getToken(),
"trace-id": uuid.v1(),
"trace-user": store.getters.userid,
};
11.前端增加删除图片按钮
<a-button type="primary" danger @click="delPic(record)">
<template #icon>
<delete-outlined />
</template>
删除图片
</a-button>
12.前端图片删除JS
// 删除图片
const delPic = (row) => {
const modal = Modal.confirm();
modal.update({
title: "确认删除该图片吗?",
icon: createVNode(ExclamationCircleOutlined),
content: "",
okText: "删除",
okType: "danger",
cancelText: "取消",
closable: true,
maskClosable: true,
onOk(e) {
const param = Object.assign({}, row);
PointsExchangeApi.delPic(param)
.then((response) => {
const data = response.data;
console.log(response);
if (data.code === 200) {
message.success("删除成功");
} else {
message.warning(data.message);
}
query();
modal.destroy();
})
.catch((error) => {
query();
});
},
onCancel() {
console.log("Cancel");
modal.destroy();
},
});
};
13.前端图片展示(404的时候显示默认图片)
<img :src="item.pic" alt="" class="img" onerror="this.src='../src/assets/default.png'"/>
14.Nginx配置
如果在线上出现大图片无法上传的情况,则是Nginx对图片传输做了限制,默认限制图片上传大小为1M。
解决方法:在nginx.conf的http对象增加配置(设置为5M)
client_max_body_size 5m;
即可。