Browse Source

笔记资源相关接口

master
review512jwy@163.com 1 month ago
parent
commit
938eec2648
  1. 18
      src/main/java/com/youlai/boot/file/service/impl/AliyunFileService.java
  2. 33
      src/main/java/com/youlai/boot/mini/controller/StrayAnimalController.java
  3. 3
      src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalNoteMediaMapper.java
  4. 36
      src/main/java/com/youlai/boot/mini/model/dto/DeleteStrayAnimalNoteMediaDTO.java
  5. 2
      src/main/java/com/youlai/boot/mini/model/entity/MiniStrayAnimalNoteMedia.java
  6. 7
      src/main/java/com/youlai/boot/mini/service/StrayAnimalService.java
  7. 153
      src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalServiceImpl.java
  8. 8
      src/main/resources/mapper/mini/MiniStrayAnimalNoteMediaMapper.xml

18
src/main/java/com/youlai/boot/file/service/impl/AliyunFileService.java

@ -6,6 +6,8 @@ import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.DeleteObjectsRequest;
import com.aliyun.oss.model.DeleteObjectsResult;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.youlai.boot.file.service.FileService;
@ -14,6 +16,7 @@ import jakarta.annotation.PostConstruct;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ -21,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.List;
/**
* Aliyun 对象存储服务类
@ -33,6 +37,7 @@ import java.time.LocalDateTime;
@ConfigurationProperties(prefix = "oss.aliyun")
@RequiredArgsConstructor
@Data
@Slf4j
public class AliyunFileService implements FileService {
/**
* 服务Endpoint
@ -109,4 +114,17 @@ public class AliyunFileService implements FileService {
aliyunOssClient.deleteObject(bucketName, fileName);
return true;
}
public void deleteMultiFile(List<String> objectNames) {
DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName).withKeys(objectNames);
DeleteObjectsResult deleteResult = aliyunOssClient.deleteObjects(deleteRequest);
List<String> deletedObjects = deleteResult.getDeletedObjects();
deletedObjects.forEach(key -> log.info(" - {}", key));
log.info("aliyun oss files delete successfully.......");
}
}

33
src/main/java/com/youlai/boot/mini/controller/StrayAnimalController.java

@ -6,6 +6,7 @@ import com.youlai.boot.common.enums.ActionTypeEnum;
import com.youlai.boot.common.enums.LogModuleEnum;
import com.youlai.boot.common.model.Option;
import com.youlai.boot.common.result.Result;
import com.youlai.boot.mini.model.dto.DeleteStrayAnimalNoteMediaDTO;
import com.youlai.boot.mini.model.form.StrayAnimalForm;
import com.youlai.boot.mini.service.StrayAnimalService;
import io.swagger.v3.oas.annotations.Operation;
@ -35,7 +36,7 @@ public class StrayAnimalController {
private final StrayAnimalService strayAnimalService;
@Operation(summary = "添加动物信息")
@PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@PostMapping(value = "save", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@RepeatSubmit
@Log(module = LogModuleEnum.STRAY_ANIMAL_INFO, value = ActionTypeEnum.INSERT)
public Result<?> saveStrayAnimal(
@ -49,13 +50,37 @@ public class StrayAnimalController {
@Operation(summary = "编辑动物信息(不包含图片/视频媒体资源)")
@PutMapping(value = "/{uuid}")
@PostMapping(value = "/update/{animalUuid}")
@Log(module = LogModuleEnum.STRAY_ANIMAL_INFO, value = ActionTypeEnum.UPDATE)
public Result<?> updateStrayAnimal(
@PathVariable String uuid,
@PathVariable String animalUuid,
@Validated @RequestBody StrayAnimalForm formData
) {
strayAnimalService.updateStrayAnimal(uuid, formData);
strayAnimalService.updateStrayAnimal(animalUuid, formData);
return Result.success();
}
@Operation(summary = "编辑动物信息时,删除流浪动物信息媒体资源")
@PostMapping(value = "/update/deleteMediaSource")
@Log(module = LogModuleEnum.STRAY_ANIMAL_INFO, value = ActionTypeEnum.UPDATE)
public Result<?> deleteMediaSource(
@RequestBody @Validated DeleteStrayAnimalNoteMediaDTO deleteStrayAnimalNoteMediaDTO
){
strayAnimalService.deleteMediaSource(deleteStrayAnimalNoteMediaDTO);
return Result.success();
}
@Operation(summary = "编辑动物信息时,添加流浪动物信息媒体资源", description = "比如补充图片、补充视频")
@PostMapping(value = "update/saveMediaSource/{noteMediaUuid}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
@RepeatSubmit
@Log(module = LogModuleEnum.STRAY_ANIMAL_INFO, value = ActionTypeEnum.UPDATE)
public Result<?> saveMediaSource(
@PathVariable String noteMediaUuid,
@RequestPart(name = "images", required = false) List<MultipartFile> images,
@RequestPart(name = "videos", required = false) List<MultipartFile> videos
) {
strayAnimalService.saveMediaSource(noteMediaUuid, images, videos);
return Result.success();
}

3
src/main/java/com/youlai/boot/mini/mapper/MiniStrayAnimalNoteMediaMapper.java

@ -3,6 +3,8 @@ package com.youlai.boot.mini.mapper;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNoteMedia;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import java.util.Map;
/**
* 流浪信息资源表 Mapper 接口
*
@ -11,4 +13,5 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/
public interface MiniStrayAnimalNoteMediaMapper extends BaseMapper<MiniStrayAnimalNoteMedia> {
int getMediaCountByNoteIdAndType(Map<String, Object> param);
}

36
src/main/java/com/youlai/boot/mini/model/dto/DeleteStrayAnimalNoteMediaDTO.java

@ -0,0 +1,36 @@
package com.youlai.boot.mini.model.dto;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.util.List;
@Data
public class DeleteStrayAnimalNoteMediaDTO {
@NotEmpty(message = "媒体资源uuid不能为空")
@ArraySchema(
arraySchema = @Schema(
description = "流浪动物信息媒体资源uuid列表",
example = "[\"uuid1\",\"uuid2\"]",
requiredMode = Schema.RequiredMode.REQUIRED
),
schema = @Schema(
description = "媒体资源uuid",
example = "uuid1"
)
)
private List<@NotBlank(message = "uuid不能为空") String> noteMediaUuidList;
@NotBlank(message = "笔记uuid不能为空")
@Schema(
description = "流浪动物信息笔记uuid",
example = "2d7890db8a6e47016ccef2d679d5a2c8",
requiredMode = Schema.RequiredMode.REQUIRED
)
private String noteUuid;
}

2
src/main/java/com/youlai/boot/mini/model/entity/MiniStrayAnimalNoteMedia.java

@ -62,7 +62,7 @@ public class MiniStrayAnimalNoteMedia implements Serializable {
@TableField("sort_order")
@Schema(description = "排序顺序")
private Integer sortOrder;
private Long sortOrder;
@TableField("create_time")
@Schema(description = "创建时间")

7
src/main/java/com/youlai/boot/mini/service/StrayAnimalService.java

@ -1,6 +1,7 @@
package com.youlai.boot.mini.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.mini.model.dto.DeleteStrayAnimalNoteMediaDTO;
import com.youlai.boot.mini.model.entity.MiniStrayAnimal;
import com.youlai.boot.mini.model.form.StrayAnimalForm;
import jakarta.validation.Valid;
@ -12,5 +13,9 @@ public interface StrayAnimalService extends IService<MiniStrayAnimal> {
String saveStrayAnimal(@Valid StrayAnimalForm formData, List<MultipartFile> images, List<MultipartFile> videos);
void updateStrayAnimal(String uuid, StrayAnimalForm formData);
void updateStrayAnimal(String animalUuid, StrayAnimalForm formData);
void deleteMediaSource(DeleteStrayAnimalNoteMediaDTO deleteStrayAnimalNoteMediaDTO);
void saveMediaSource(String noteMediaUuid, List<MultipartFile> images, List<MultipartFile> videos);
}

153
src/main/java/com/youlai/boot/mini/service/impl/StrayAnimalServiceImpl.java

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.common.constant.CommonConstants;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.util.CoordinateTransformUtils;
import com.youlai.boot.common.util.FileUtils;
import com.youlai.boot.common.util.JavaVCUtils;
@ -18,6 +19,7 @@ import com.youlai.boot.mini.converter.MiniStrayAnimalConverter;
import com.youlai.boot.mini.mapper.MiniStrayAnimalMapper;
import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteMapper;
import com.youlai.boot.mini.mapper.MiniStrayAnimalNoteMediaMapper;
import com.youlai.boot.mini.model.dto.DeleteStrayAnimalNoteMediaDTO;
import com.youlai.boot.mini.model.enums.AnimalNoteMediaTypeEnum;
import com.youlai.boot.mini.model.entity.MiniStrayAnimal;
import com.youlai.boot.mini.model.entity.MiniStrayAnimalNote;
@ -26,6 +28,7 @@ import com.youlai.boot.mini.model.form.StrayAnimalForm;
import com.youlai.boot.mini.service.StrayAnimalService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.FilenameUtils;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
@ -37,9 +40,8 @@ import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.text.MessageFormat;
import java.util.*;
/**
* 流浪动物业务实现类
@ -71,20 +73,22 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
MiniStrayAnimalNote note = saveNoteInfo(formData, miniStrayAnimal);
// 4. 处理并保存媒体文件
saveMediaFiles(note, images, videos);
saveMediaFiles(note, images, videos, miniStrayAnimal.getCreateTimestamp());
// 5. 提交审核
return miniStrayAnimal.getUuid();
}
private void saveMediaFiles(MiniStrayAnimalNote note, List<MultipartFile> images, List<MultipartFile> videos) {
int sortOrder = 0;
private void saveMediaFiles(MiniStrayAnimalNote note, List<MultipartFile> images, List<MultipartFile> videos, long currentTimestamp) {
long sortOrder = currentTimestamp;
// 处理图片
if (images != null) {
for (MultipartFile image : images) {
try {
String objectName = "animal_note/"
+ note.getId() + "/"
+ note.getCreateTimestamp() + RandomNumberUtils.createRandomLowerLetterAndNumber(8)
+ currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8)
+ "."
+ FilenameUtils.getExtension(image.getOriginalFilename());
String url = aliyunFileService.uploadFile(objectName, image.getInputStream());
@ -98,8 +102,8 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
miniStrayAnimalNoteMedia.setWidth(imageInfo.getWidth());
miniStrayAnimalNoteMedia.setHeight(imageInfo.getHeight());
miniStrayAnimalNoteMedia.setSortOrder(sortOrder++);
miniStrayAnimalNoteMedia.setCreateTimestamp(note.getCreateTimestamp());
miniStrayAnimalNoteMedia.setCreateTime(new Date(miniStrayAnimalNoteMedia.getCreateTimestamp()));
miniStrayAnimalNoteMedia.setCreateTimestamp(currentTimestamp);
miniStrayAnimalNoteMedia.setCreateTime(new Date(currentTimestamp));
miniStrayAnimalNoteMedia.setCreateBy(note.getMiniUserId());
int result = miniStrayAnimalNoteMediaMapper.insert(miniStrayAnimalNoteMedia);
@ -114,7 +118,7 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
String tmpPath = System.getProperty("user.dir") + "/tmp";
for (MultipartFile video : videos) {
try {
String fileName = note.getCreateTimestamp() + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String fileName = currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String objectName = "animal_note/"
+ note.getId() + "/"
+ fileName
@ -128,8 +132,8 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
miniStrayAnimalNoteMedia.setSourceUrl(url);
miniStrayAnimalNoteMedia.setStorageKey(objectName);
miniStrayAnimalNoteMedia.setSortOrder(sortOrder++);
miniStrayAnimalNoteMedia.setCreateTimestamp(note.getCreateTimestamp());
miniStrayAnimalNoteMedia.setCreateTime(new Date(miniStrayAnimalNoteMedia.getCreateTimestamp()));
miniStrayAnimalNoteMedia.setCreateTimestamp(currentTimestamp);
miniStrayAnimalNoteMedia.setCreateTime(new Date(currentTimestamp));
miniStrayAnimalNoteMedia.setCreateBy(note.getMiniUserId());
//时长
FileUtils.saveFile(video, tmpPath, fileName);
@ -138,7 +142,7 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
miniStrayAnimalNoteMedia.setDuration((int) Math.ceil(duration));
//缩略图
BufferedImage thumbnail = JavaVCUtils.getVideoThumbnail(videoPath, 1);
String thumbnailFileName = note.getCreateTimestamp() + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String thumbnailFileName = currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String thumbnailObjectName = "animal_note/"
+ note.getId() + "/"
+ thumbnailFileName
@ -207,27 +211,40 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
private void validateInput(List<MultipartFile> images, List<MultipartFile> videos) {
// 验证必填图片
Assert.notEmpty(images, "需要上传图片");
if (images == null || images.isEmpty()) {
throw new BusinessException("需要上传图片");
}
// 验证图片数量
Assert.isTrue(
images.size() <= CommonConstants.STRAY_ANIMAL_IMAGE_NUM_LIMIT,
"最多只能上传" + CommonConstants.STRAY_ANIMAL_IMAGE_NUM_LIMIT + "张图片");
if (images.size() > CommonConstants.STRAY_ANIMAL_IMAGE_NUM_LIMIT) {
throw new BusinessException(
"最多只能上传" + CommonConstants.STRAY_ANIMAL_IMAGE_NUM_LIMIT + "张图片"
);
}
// 验证视频数量
Assert.isTrue(
CollUtil.isEmpty(videos) || videos.size() <= CommonConstants.STRAY_ANIMAL_VIDEO_NUM_LIMIT,
"最多只能上传" + CommonConstants.STRAY_ANIMAL_VIDEO_NUM_LIMIT + "个视频");
if (!CollUtil.isEmpty(videos) && videos.size() > CommonConstants.STRAY_ANIMAL_VIDEO_NUM_LIMIT) {
throw new BusinessException(
"最多只能上传" + CommonConstants.STRAY_ANIMAL_VIDEO_NUM_LIMIT + "个视频"
);
}
}
@Override
public void updateStrayAnimal(String uuid, StrayAnimalForm formData) {
public void updateStrayAnimal(String animalUuid, StrayAnimalForm formData) {
// 校验动物是否存在
MiniStrayAnimal animal = miniStrayAnimalMapper.selectOne(
new LambdaQueryWrapper<MiniStrayAnimal>()
.eq(MiniStrayAnimal::getUuid, uuid)
.eq(MiniStrayAnimal::getUuid, animalUuid)
.eq(MiniStrayAnimal::getDeleted, 0)
);
Assert.notNull(animal, "动物不存在");
if (animal == null) {
throw new BusinessException("动物不存在");
}
if (1 == animal.getAuditStatus()) {
throw new BusinessException("审核中无法更改");
}
long currentTimestamp = System.currentTimeMillis();
@ -235,6 +252,7 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
updateAnimalInfo(animal.getId(), formData, currentTimestamp);
// 3. 更新笔记信息`
updateNoteInfo(animal.getId(), formData, currentTimestamp);
// 4. 提交审核
}
@ -269,4 +287,93 @@ public class StrayAnimalServiceImpl extends ServiceImpl<MiniStrayAnimalMapper, M
miniStrayAnimalMapper.updateStrayAnimal(miniStrayAnimal);
}
@Override
public void deleteMediaSource(DeleteStrayAnimalNoteMediaDTO deleteStrayAnimalNoteMediaDTO) {
List<String> noteMediaUuidList = deleteStrayAnimalNoteMediaDTO.getNoteMediaUuidList();
MiniStrayAnimalNote note = miniStrayAnimalNoteMapper.selectOne(new LambdaQueryWrapper<MiniStrayAnimalNote>()
.eq(MiniStrayAnimalNote::getUuid, deleteStrayAnimalNoteMediaDTO.getNoteUuid()));
if (note == null) {
throw new BusinessException("笔记不存在");
}
LambdaQueryWrapper<MiniStrayAnimalNoteMedia> queryWrapper =
new LambdaQueryWrapper<MiniStrayAnimalNoteMedia>()
.in(MiniStrayAnimalNoteMedia::getUuid, noteMediaUuidList)
.eq(MiniStrayAnimalNoteMedia::getNoteId, note.getId())
.eq(MiniStrayAnimalNoteMedia::getDeleted, 0);
List<MiniStrayAnimalNoteMedia> mediaList =
miniStrayAnimalNoteMediaMapper.selectList(queryWrapper);
if (CollectionUtils.isNotEmpty(mediaList)) {
// 删除源文件
List<String> storageKeyList = mediaList.stream()
.map(MiniStrayAnimalNoteMedia::getStorageKey)
.toList();
aliyunFileService.deleteMultiFile(storageKeyList);
long currentTimestamp = System.currentTimeMillis();
// 逻辑删除
miniStrayAnimalNoteMediaMapper.update(
null,
new LambdaUpdateWrapper<MiniStrayAnimalNoteMedia>()
.in(MiniStrayAnimalNoteMedia::getUuid, noteMediaUuidList)
.eq(MiniStrayAnimalNoteMedia::getNoteId, note.getId())
.set(MiniStrayAnimalNoteMedia::getDeleted, 1)
.set(MiniStrayAnimalNoteMedia::getUpdateTimestamp, currentTimestamp)
.set(MiniStrayAnimalNoteMedia::getUpdateTime, new Date(currentTimestamp))
.set(MiniStrayAnimalNoteMedia::getUpdateBy, SecurityUtils.getUserId())
);
}
}
@Override
public void saveMediaSource(String noteMediaUuid, List<MultipartFile> images, List<MultipartFile> videos) {
if ((images == null || images.isEmpty()) && (videos == null || videos.isEmpty())) {
throw new BusinessException("需要上传媒体资源");
}
MiniStrayAnimalNote note = miniStrayAnimalNoteMapper.selectOne(
new LambdaQueryWrapper<MiniStrayAnimalNote>()
.eq(MiniStrayAnimalNote::getUuid, noteMediaUuid)
.eq(MiniStrayAnimalNote::getDeleted, 0)
);
if (note == null) {
throw new BusinessException("笔记不存在");
}
Long animalId = note.getStrayAnimalId();
MiniStrayAnimal miniStrayAnimal = miniStrayAnimalMapper.selectById(animalId);
if (miniStrayAnimal == null) {
throw new BusinessException("动物信息不存在");
}
if (1 == miniStrayAnimal.getAuditStatus()){
throw new BusinessException("审核中");
}
//校验数量有没有超出
Map<String, Object> param = new HashMap<>();
param.put("noteId", note.getId());
if (CollectionUtils.isNotEmpty(images)){
param.put("mediaType", AnimalNoteMediaTypeEnum.IMAGE.name().toLowerCase());
int imagesExist = miniStrayAnimalNoteMediaMapper.getMediaCountByNoteIdAndType(param);
if (imagesExist+images.size() > CommonConstants.STRAY_ANIMAL_IMAGE_NUM_LIMIT) {
throw new BusinessException("图片总数不能超过" + CommonConstants.STRAY_ANIMAL_IMAGE_NUM_LIMIT + "张");
}
}
if (CollectionUtils.isNotEmpty(videos)){
param.put("mediaType", AnimalNoteMediaTypeEnum.VIDEO.name().toLowerCase());
int videosExist = miniStrayAnimalNoteMediaMapper.getMediaCountByNoteIdAndType(param);
if(videosExist+videos.size() > CommonConstants.STRAY_ANIMAL_VIDEO_NUM_LIMIT){
throw new BusinessException("视频总数不能超过" + CommonConstants.STRAY_ANIMAL_VIDEO_NUM_LIMIT + "个");
}
}
saveMediaFiles(note, images, videos, System.currentTimeMillis());
}
}

8
src/main/resources/mapper/mini/MiniStrayAnimalNoteMediaMapper.xml

@ -5,5 +5,13 @@
<mapper namespace="com.youlai.boot.mini.mapper.MiniStrayAnimalNoteMediaMapper">
<select id="getMediaCountByNoteIdAndType" resultType="java.lang.Integer">
SELECT
count(1)
FROM
mini_stray_animal_note_media
WHERE
note_id = #{noteId} AND media_type = #{mediaType}
</select>
</mapper>

Loading…
Cancel
Save