图片的上传管理有多种方案,可以使用服务商提供的对象存储,只要是文件都可以。按存储空间和流量计费,也有一些其他的服务,例如转码之类的。
也可以用fastDFS, 这个也用得比较多,以前。搭建起来比较麻烦,这里不详细说,有兴趣的同学可以自行尝试。
这里我们只是普通的文件上传,没有做太多的优化处理。同学们跟着来做就好,先完成功能先吧。
图片上传
接口
/**
* 关于图片(文件)上传
* 一般来说,现在比较常用的是对象存储--->很简单,看文档就可以学会了
* 使用 Nginx + fastDFS == > fastDFS -- > 处理文件上传, Nginx -- > 负责处理文件访问
*
* @param file
* @return
*/
@PreAuthorize("@permission.admin()")
@PostMapping
public ResponseResult uploadImage(@RequestParam("file") MultipartFile file) {
return imageService.uploadImage(file);
}
上传图片实现
/**
* 上传的路径:可以配置,在配置文件里配置
* 上传的内容,命名-->可以用ID,-->每天一个文件夹保存
* 限制文件大小,通过配置文件配置
* 保存记录到数据库里
* ID|存储路径|url|原名称|用户ID|状态|创建日期|更新日期
*
* @param file
* @return
*/
@Override
public ResponseResult uploadImage(MultipartFile file) {
//判断是否有文件
if (file == null) {
return ResponseResult.FAILED("图片不可以为空.");
}
//判断文件类型,我们只支持图片上传,比如说:png,jpg,gif
String contentType = file.getContentType();
log.info("contentType == > " + contentType);
if (TextUtils.isEmpty(contentType)) {
return ResponseResult.FAILED("图片格式错误.");
}
//获取相关数据,比如说文件类型,文件名称
String originalFilename = file.getOriginalFilename();
log.info("originalFilename == > " + originalFilename);
String type = getType(contentType, originalFilename);
if (type == null) {
return ResponseResult.FAILED("不支持此图片类型");
}
//限制文件的大小
long size = file.getSize();
log.info("maxSize === > " + maxSize + " size ==> " + size);
if (size > maxSize) {
return ResponseResult.FAILED("图片最大仅支持" + (maxSize / 1024 / 1024) + "Mb");
}
//创建图片的保存目录
//规则:配置目录/日期/类型/ID.类型
long currentMillions = System.currentTimeMillis();
String currentDay = simpleDateFormat.format(currentMillions);
log.info("current day == > " + currentDay);
String dayPath = imagePath + File.separator + currentDay;
File dayPathFile = new File(dayPath);
//判断日期文件夹是否存在//2020_06_26
if (!dayPathFile.exists()) {
dayPathFile.mkdirs();
}
String targetName = String.valueOf(idWorker.nextId());
String targetPath = dayPath +
File.separator + type + File.separator + targetName + "." + type;
File targetFile = new File(targetPath);
//判断类型文件夹是否存在//gif
if (!targetFile.getParentFile().exists()) {
targetFile.getParentFile().mkdirs();
}
try {
if (!targetFile.exists()) {
targetFile.createNewFile();
}
log.info("targetFile == > " + targetFile);
//保存文件
file.transferTo(targetFile);
//返回结果:包含这个图片的名称和访问路径
//第一个是访问路径 -- > 得对应着解析来
Map<String, String> result = new HashMap<>();
String resultPath = currentMillions + "_" + targetName + "." + type;
result.put("id", resultPath);
//第二个是名称--->alt="图片描述",如果不写,前端可以使用名称作为这个描述
result.put("name", originalFilename);
Image image = new Image();
image.setContentType(contentType);
image.setId(targetName);
image.setCreateTime(new Date());
image.setUpdateTime(new Date());
image.setPath(targetFile.getPath());
image.setName(originalFilename);
image.setUrl(resultPath);
image.setState("1");
SobUser sobUser = userService.checkSobUser();
image.setUserId(sobUser.getId());
//记录文件
//保存记录到数据里
imageDao.save(image);
//返回结果
return ResponseResult.SUCCESS("文件上传成功").setData(result);
} catch (IOException e) {
e.printStackTrace();
}
return ResponseResult.FAILED("图片上传失败,请稍后重试");
}
两个配置项
@Value("${sob.blog.image.save-path}")
public String imagePath;
@Value("${sob.blog.image.max-size}")
public long maxSize;
sob.blog.image.save-path: E:\codes\Idear\images
# 2MB
sob.blog.image.max-size: 2097152
获取图片列表
使用场景:发表文章的时候,获取到图片列表,然后插入图片
接口
@PreAuthorize("@permission.admin()")
@GetMapping("/list/{page}/{size}")
public ResponseResult listImages(@PathVariable("page") int page, @PathVariable("size") int size){
return imageService.listImages(page, size);
}
获取图片列表实现
@Override
public ResponseResult listImages(int page, int size) {
//处理page,size
page = checkPage(page);
size = checkPage(size);
SobUser sobUser = userService.checkSobUser();
if (sobUser == null) {
return ResponseResult.ACCOUNT_NOT_LOGIN();
}
//创建分页条件
Sort sort = new Sort(Sort.Direction.DESC, "createTime");
//查询
Pageable pageable = PageRequest.of(page - 1, size, sort);
//返回结果
final String userId = sobUser.getId();
Page<Image> all = imageDao.findAll(new Specification<Image>() {
@Override
public Predicate toPredicate(Root<Image> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
//根据用户ID
Predicate userIdPre = cb.equal(root.get("userId").as(String.class), userId);
//根据状态
Predicate statePre = cb.equal(root.get("state").as(String.class), "1");
return cb.and(userIdPre, statePre);
}
}, pageable);
return ResponseResult.SUCCESS("获取图片列表成功.").setData(all);
}
图片删除
删除图片我们不是真的删除,只是修改其状态,如果真的删除了,则会访问不了了。有些图片,可能被多个文章引用着,如果删除一张图片去检查文章是否有引用,这个资源消耗比较多,当然啦,也可以用统计法。如果图片有被引用则记录一下值,得加多一张表记录一下。
这里我们只是修改图片的状态
需要管理员权限
@PreAuthorize("@permission.admin()")
@DeleteMapping("/{imageId}")
public ResponseResult deleteImage(@PathVariable("imageId") String imageId) {
return imageService.deleteById(imageId);
}
实现代码
/**
* 删除图片,
* 只改变状态
*
* @param imageId
* @return
*/
@Override
public ResponseResult deleteById(String imageId) {
int result = imageDao.deleteImageByUpdateState(imageId);
if (result > 0) {
return ResponseResult.SUCCESS("删除成功.");
}
return ResponseResult.FAILED("图片不存在.");
}
DAO修改语句
@Modifying
@Query(nativeQuery = true, value = "UPDATE `tb_images` SET `state` = '0' WHERE id = ?")
int deleteImageByUpdateState(String imageId);