第一篇文章,值得纪念一下
点击编辑或者新增摄影师,都可以出现编辑界面
点击新增,是这样的
点击编辑,是这样,支持回显
选择一张新的图片上传的时候,后台回把新的图片上传到图片服务器,再次上传,后台会把上一次上传的图片再删除,只保留最新的。
如果点击确定,那么后台会更新数据库里面的图片地址,并且保证图片服务器中的图片与数据库中一一对应
如果点击取消,那么之前的选择的图片也会从图片服务器中删除
能够保证图片服务器中的图片与数据库中一致
知识点
axios中各种请求方式以及参数的传递
方法:get post
参数类型:json和formdata
后端接收
@requestbody
使用gson获取前端数据
代码
vue
这个是遍历所有的摄影师
<table class="table table-hover table-bordered">
<thead>
<tr>
<th>姓名</th><th>级别</th><th>简介</th><th>形象照</th><th>编辑</th>
</tr>
</thead>
<tbody>
<tr v-for="item in list">
<td>{{item.photographerName}}</td>
<td>{{item.photographerLevelName}}</td>
<td>{{item.photographerDes}}</td>
<td><img :src="URL+item.photographerIcon" alt="" onerror="this.src='http://localhost:9000/iphoto/img/img/waitforuploadpic.jpg'" width="50px"></td> <!--TODO 还没有实现图片的上传和下载-->
<td><a @click="onEdit(item)">编辑</a><a @click="onDel(item)">删除</a></td>
</tr>
</tbody>
</table>
点击编辑或者新增
<form role="form" style="width: 400px" >
<div class="form-group">
<label>摄影师姓名</label><input v-model="editingContact.photographerName" placeholder="请输入摄影师姓名" />
</div>
<!--v-if="!editingContact.hasOwnProperty('photographerLevelName') "
表示如果editingContact中有photographerLevelName这个元素,则返回true-->
<div class="form-group" v-if="!editingContact.hasOwnProperty('photographerLevelName') ">
<label >摄影师级别</label>
<select v-model="editingContact.photographerLevelName" >
<option >请选择</option>
<option v-for="item1 in allLevels" >{{item1.photographerLevelName}}</option>
</select>
</div>
<div class="form-group" v-else>
<label >摄影师级别</label>
<select v-model="editingContact.photographerLevelName"> //设置回显,v-model与option中的value值相同则被选中
<option>请选择</option>
<option v-for="item1 in allLevels" >{{item1.photographerLevelName}}</option>
</select>
</div>
<div class="form-group">
<label >摄影师简介</label><input v-model="editingContact.photographerDes" placeholder="请输入摄影师简介" />
</div>
<div class="form-group">
<label>形象照</label>
<input type="file" @change="onUpload">
<img :src=relativePath onerror="this.src='http://localhost:9000/iphoto/img/img/waitforuploadpic.jpg'" width="120px" />
</div>
<button type="button" class="btn btn-default" @click="onSave">确定</button>
<button type="button" class="btn btn-default" @click="onCancel">取消</button>
</form>
data
data(){
return{
URL:this.$const_api.BASEURL,
error_img:this.$const_api.ERROR_IMG, //todo 替换到onerror里面的时候不好使,不知道为什么
list:[],
instance:null,
shopId:'',
editingContact:{}, //正在编辑的对象,用于回显
isShow:false, //是否显示弹窗
isEdit:false, //是否是编辑
allLevels:{},
relativePath:'',
/*图片在数据组中的地址,在上传图片的时候,如果iconPathInDB为空,证明是新建对象,当保存的时候无需删除这个地址的图片
* 在上传图片的时候,如果iconPathInDB不为空,证明是编辑对象,当保存的时候,需要删除这个地址的图片,防止污染数据库*/
iconPathInDB:'',
}
},
点击新增
/*点击打开创建摄影师界面的弹窗*/
onAdd(){
this.editingContact = {photographerLevelName:'请选择'}
this.getAllphotographerLevels()
this.isShow = true
this.isEdit = false
this.relativePath = ''
},
点击编辑
/*编辑摄影师信息*/
onEdit(item){
console.log(item)
console.log(item.photographerId)
this.getAllphotographerLevels()
this.isShow = true
this.isEdit = true
this.instance.get('/photographers/findByPhotographerId?photographerId='+item.photographerId).then(res=>{
this.editingContact = res.data.data
this.relativePath = this.URL + this.editingContact.photographerIcon
this.iconPathInDB = item.photographerIcon
})
},
上传图片
/*上传图片*/
onUpload(event){
let file = event.target.files[0] //得到的是一个file文件
let formData = new FormData()
/*将图片的二进制流传给后台*/
formData.append('file',file)
/*将上一次上传的图片的路径传给后台,以便替换照片的时候后台将不需要的图片从服务器删除*/
formData.append('oldPath', this.relativePath)
/*将iconPathInDB传给后台,如果是新建则为null,如果是编辑,则是一个相对路径,如果iconPathInDB与oldPath相同,则
* 是编辑状态,则未点击确定之前不可以删除iconPathInDB的照片,以防服务器照片文件丢失*/
if (this.isEdit){
formData.append('iconPathInDB', this.URL + this.iconPathInDB)
}
this.instance.post('/upload/toUpload',formData).then(res =>{
this.relativePath = this.URL + res.data.data.relativePath
this.editingContact.photographerIcon = res.data.data.relativePath
})
},
保存
/*保存*/
onSave(){
/*vue 中的for循环与java不一样,一定牢记
* item 代表的是第几个元素,比如0,1 所以对象还是allLevels,只不过需要加上[item]*/
for(let item in this.allLevels){
if (this.editingContact.photographerLevelName === this.allLevels[item].photographerLevelName){
/*获得photographerLevelId*/
this.editingContact.photographerLevelId = this.allLevels[item].photographerLevelId
}
}
this.editingContact.shopId = this.shopId
let data = {
editingContact:this.editingContact,
iconPathInDB:this.iconPathInDB
}
this.instance.post('/photographers/create',data).then((res) =>{
console.log(res)
this.isShow = false
this.getPhotographerList()
})
this.editingContact = {}
this.iconPathInDB = ''
},
取消
/*取消*/
onCancel(){
if (this.isEdit){
/*需要判断是否是数据库里面的地址,如果不是,需要删除*/
if ((this.URL + this.iconPathInDB) !== this.relativePath){
/*this.URL + this.iconPathInDB url加上数据库地址
* this.relativePath 当前图片的地址
* 如果不同,证明是新上传的图片*/
this.instance.post('/shops/delIcon',{relativePath:this.relativePath})
}
}else {
/*如果是新建,则relativePath 无需判断是否是数据库里面的地址 可以直接删除*/
if (this.relativePath){
this.instance.post('/shops/delIcon',{relativePath:this.relativePath})
}
}
this.isShow = false
this.editingContact = {}
},
springboot
PhotographerController
@PostMapping("/create")
public ResultVo create(@RequestBody String req){
Gson gson = new Gson();
JsonObject jsonObject = new JsonParser().parse(req).getAsJsonObject();
JsonElement editingContact = jsonObject.get("editingContact");
JsonElement iconPathInDB = jsonObject.get("iconPathInDB");
PhotographerDTO photographerDTO = gson.fromJson(editingContact,PhotographerDTO.class);
/*获得iconPathInDB,如果不为空,说明是编辑保存,需要将原本的照片删掉*/
String iconPath = gson.fromJson(iconPathInDB, String.class);
if (iconPath != null && !iconPath.equals(photographerDTO.getPhotographerIcon())){
UploadPicUtil.delOldPic(iconPath);
}
Photographer photographer1 = new Photographer();
BeanUtils.copyProperties(photographerDTO,photographer1);
photographerService.save(photographer1);
return ResultVOUtil.success();
}
photographerDTO
@Data
public class PhotographerDTO {
private Integer photographerId;
/*摄影师级别id*/
private Integer photographerLevelId;
/*摄影师级别名称*/
private String photographerLevelName;
/*摄影师姓名*/
private String photographerName;
/*摄影师简介*/
private String photographerDes;
/*摄影师照片*/
private String photographerIcon;
/*摄影师所属店铺的id*/
private Integer shopId;
}
UploadPicUtil工具类
public static Map<String,String> uopload(HttpServletRequest request) throws IOException {
/*如果请求格式不是MultipartHttpServletRequest 则无法转化*/
if (!(request instanceof MultipartHttpServletRequest)) {
throw new IphotoException(ResultEnum.REQUEST_TYPE_ERROR.getCode(),ResultEnum.REQUEST_TYPE_ERROR.getMessage());
}
/*将request转换成MultipartHttpServletRequest*/
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
/*如果不是第一次上传照片,则会得到上一次上传的照片的相对完整路径
* 比如:oldPath: http://localhost:9000/iphoto/img/1571192853730127718.jpg*/
Enumeration<String> parameterNames = multipartRequest.getParameterNames();
String oldPath = null;
String iconPathInDB = null;
while (parameterNames.hasMoreElements()){
String parameterName = parameterNames.nextElement();
if (parameterName.equals("iconPathInDB")){
iconPathInDB = request.getParameter(parameterName);
}else {
oldPath = request.getParameter(parameterName);;
}
}
/*得到请求中所有文件的名字*/
Iterator<String> fileNames = multipartRequest.getFileNames();
/*获得第一个文件的名字,因为只传一张图片过来,所以第一个就是*/
String fileName = fileNames.next();
/*通过文件的名字,获得请求中的文件*/
MultipartFile file = multipartRequest.getFile(fileName);
if (file.isEmpty()){
throw new IphotoException(ResultEnum.FILE_EMPTY_ERROR.getCode(),
ResultEnum.FILE_EMPTY_ERROR.getMessage());
}
/*通过得到的文件获得文件名*/
String originalFilename = file.getOriginalFilename();
/*通过substring获得文件的后缀*/
String suffix = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);
/*利用生成的文件名加上后缀得到新的文件名字*/
String newFileName = KeyUtil.genKey() + "." + suffix;
/*真实文件路径,用于存储文件*/
String realPath = URLEnum.STATIC_LOCATIONS.getMessage()+"/"+newFileName;
/*相对路径,用于前端获取图片位置以及存储数据库*/
String relativePath = URLEnum.STATIC_PATH_PATTERN.getMessage() + "/" + newFileName;
/*如果传进来的oldPath不为空,说明不是第一次上传,需要覆盖之前的图片*/
if (oldPath != null && oldPath.length() > 0 && !iconPathInDB.equals(oldPath)){
delOldPic(oldPath);
}
/*创建一个新的文件*/
File file1 = new File(realPath);
/*将传递过来的文件写入新文件*/
file.transferTo(file1);
Map<String,String> map = new HashMap();
map.put("relativePath", relativePath);
map.put("realPath", realPath);
return map;
}
delOldPic
@CrossOrigin
public static void delOldPic(String relativePath){
/*通过相对路径,得到文件名,然后加上本地路径,得到绝对路径*/
String str = relativePath.substring(relativePath.lastIndexOf("/"));
String str1 = URLEnum.STATIC_LOCATIONS.getMessage();
/*新建一个文件*/
File file1 = new File(str1+str);
/*删除这个文件*/
file1.delete();
}