Browse Source

领养日记模块接口实现

glx_phase2
glx 1 week ago
parent
commit
4797810162
  1. 1
      src/main/java/com/youlai/boot/codegen/freemarker/MyBatisPlusGenerator.java
  2. 4
      src/main/java/com/youlai/boot/common/enums/LogModuleEnum.java
  3. 21
      src/main/java/com/youlai/boot/mini/controller/AdoptionDiaryController.java
  4. 15
      src/main/java/com/youlai/boot/mini/mapper/MiniAdoptionDiaryMapper.java
  5. 14
      src/main/java/com/youlai/boot/mini/mapper/MiniAdoptionDiaryMediaMapper.java
  6. 21
      src/main/java/com/youlai/boot/mini/model/dto/DeleteAdoptionDiaryDTO.java
  7. 29
      src/main/java/com/youlai/boot/mini/model/dto/DeleteAdoptionDiaryMediaDTO.java
  8. 6
      src/main/java/com/youlai/boot/mini/model/entity/MiniAdoptionDiary.java
  9. 94
      src/main/java/com/youlai/boot/mini/model/entity/MiniAdoptionDiaryMedia.java
  10. 29
      src/main/java/com/youlai/boot/mini/model/form/AdoptionDiaryForm.java
  11. 17
      src/main/java/com/youlai/boot/mini/model/vo/AdoptionDiaryDetailsVO.java
  12. 63
      src/main/java/com/youlai/boot/mini/model/vo/AdoptionDiaryVO.java
  13. 35
      src/main/java/com/youlai/boot/mini/model/vo/MiniAdoptionDiaryMediaVO.java
  14. 7
      src/main/java/com/youlai/boot/mini/service/AdoptionDiaryService.java
  15. 352
      src/main/java/com/youlai/boot/mini/service/impl/AdoptionDiaryServiceImpl.java
  16. 137
      src/main/resources/mapper/mini/MiniAdoptionDiaryMapper.xml
  17. 9
      src/main/resources/mapper/mini/MiniAdoptionDiaryMediaMapper.xml

1
src/main/java/com/youlai/boot/codegen/freemarker/MyBatisPlusGenerator.java

@ -105,6 +105,7 @@ public class MyBatisPlusGenerator {
,new TableConfig("mini_stray_animal_note_collect", IdType.AUTO, "mini") ,new TableConfig("mini_stray_animal_note_collect", IdType.AUTO, "mini")
,new TableConfig("mini_stray_animal_note_view", IdType.AUTO, "mini") ,new TableConfig("mini_stray_animal_note_view", IdType.AUTO, "mini")
,new TableConfig("mini_adoption_diary", IdType.AUTO, "mini") ,new TableConfig("mini_adoption_diary", IdType.AUTO, "mini")
,new TableConfig("mini_adoption_diary_media", IdType.AUTO, "mini")
// ,new TableConfig("mini_stray_animal", IdType.AUTO, "mini") // ,new TableConfig("mini_stray_animal", IdType.AUTO, "mini")
// ,new TableConfig("mini_stray_animal", IdType.INPUT, "minitest") // ,new TableConfig("mini_stray_animal", IdType.INPUT, "minitest")

4
src/main/java/com/youlai/boot/common/enums/LogModuleEnum.java

@ -33,8 +33,8 @@ public enum LogModuleEnum implements IBaseEnum<Integer> {
POINT_RECORD(101, "积分流水"), POINT_RECORD(101, "积分流水"),
POINT_RULE(102, "积分规则"), POINT_RULE(102, "积分规则"),
SIGN_RECORD(103, "签到记录"), SIGN_RECORD(103, "签到记录"),
STRAY_ANIMAL_NOTE_COMMENT(104, "流浪动物笔记评论"), STRAY_ANIMAL_NOTE_COMMENT(110, "流浪动物笔记评论"),
ADOPTION_DIARY_INFO(105, "领养日记信息"); ADOPTION_DIARY_INFO(112, "领养日记信息");
@EnumValue @EnumValue
private final Integer value; private final Integer value;

21
src/main/java/com/youlai/boot/mini/controller/AdoptionDiaryController.java

@ -11,8 +11,7 @@ import com.youlai.boot.mini.model.dto.*;
import com.youlai.boot.mini.model.form.AdoptionDiaryForm; import com.youlai.boot.mini.model.form.AdoptionDiaryForm;
import com.youlai.boot.mini.model.query.OwnAdoptionDiaryQuery; import com.youlai.boot.mini.model.query.OwnAdoptionDiaryQuery;
import com.youlai.boot.mini.model.vo.AdoptionDiaryVO; import com.youlai.boot.mini.model.vo.AdoptionDiaryVO;
import com.youlai.boot.mini.model.vo.SaveStrayAnimalVO; import com.youlai.boot.mini.model.vo.AdoptionDiaryDetailsVO;
import com.youlai.boot.mini.model.vo.StrayAnimalDetailsVO;
import com.youlai.boot.mini.service.AdoptionDiaryService; import com.youlai.boot.mini.service.AdoptionDiaryService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
@ -29,6 +28,7 @@ import java.util.List;
@RestController @RestController
@RequestMapping("/api/v1/mini/adoptionDiary") @RequestMapping("/api/v1/mini/adoptionDiary")
@RequiredArgsConstructor @RequiredArgsConstructor
public class AdoptionDiaryController { public class AdoptionDiaryController {
private final AdoptionDiaryService adoptionDiaryService; private final AdoptionDiaryService adoptionDiaryService;
@ -51,8 +51,8 @@ public class AdoptionDiaryController {
public Result<?> saveAdoptionDiary( public Result<?> saveAdoptionDiary(
@Valid @RequestBody AdoptionDiaryForm formData @Valid @RequestBody AdoptionDiaryForm formData
) { ) {
SaveStrayAnimalVO vo = adoptionDiaryService.saveAdoptionDiary(formData); String diaryUuid = adoptionDiaryService.saveAdoptionDiary(formData);
return Result.success(vo); return Result.success(diaryUuid);
} }
@Operation(summary = "编辑领养日记信息(不包含图片/视频媒体资源)") @Operation(summary = "编辑领养日记信息(不包含图片/视频媒体资源)")
@ -121,12 +121,11 @@ public class AdoptionDiaryController {
return PageResult.success(adoptionDiaryService.getSelfCreatedPage(queryParams)); return PageResult.success(adoptionDiaryService.getSelfCreatedPage(queryParams));
} }
@Operation(summary = "获取领养日记详情") // @Operation(summary = "获取领养日记详情")
@RequestMapping(value = "/getDetails/{animalUuid}", method = RequestMethod.GET) // @RequestMapping(value = "/getDetails/{animalUuid}", method = RequestMethod.GET)
public Result<StrayAnimalDetailsVO> getDetails( // public Result<AdoptionDiaryDetailsVO> getDetails(
@PathVariable String animalUuid){ // @PathVariable String diaryUuid){
return Result.success(adoptionDiaryService.getDetails(animalUuid, SecurityUtils.getUserId())); // return Result.success(adoptionDiaryService.getDetails(diaryUuid, SecurityUtils.getUserId()));
} // }
} }

15
src/main/java/com/youlai/boot/mini/mapper/MiniAdoptionDiaryMapper.java

@ -1,7 +1,12 @@
package com.youlai.boot.mini.mapper; package com.youlai.boot.mini.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.boot.mini.model.entity.MiniAdoptionDiary; import com.youlai.boot.mini.model.entity.MiniAdoptionDiary;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.youlai.boot.mini.model.query.OwnAdoptionDiaryQuery;
import com.youlai.boot.mini.model.vo.AdoptionDiaryVO;
import org.apache.ibatis.annotations.Param;
/** /**
* 领养日记表 Mapper 接口 * 领养日记表 Mapper 接口
@ -11,4 +16,14 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/ */
public interface MiniAdoptionDiaryMapper extends BaseMapper<MiniAdoptionDiary> { public interface MiniAdoptionDiaryMapper extends BaseMapper<MiniAdoptionDiary> {
/**
* 分页查询领养日记列表
*/
IPage<AdoptionDiaryVO> getDiaryPage(Page<AdoptionDiaryVO> page, @Param("query") OwnAdoptionDiaryQuery query);
/**
* 查询领养日记详情
*/
AdoptionDiaryVO getDiaryDetails(@Param("diaryUuid") String diaryUuid, @Param("miniUserId") Long miniUserId);
} }

14
src/main/java/com/youlai/boot/mini/mapper/MiniAdoptionDiaryMediaMapper.java

@ -0,0 +1,14 @@
package com.youlai.boot.mini.mapper;
import com.youlai.boot.mini.model.entity.MiniAdoptionDiaryMedia;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 领养日记资源表 Mapper 接口
*
* @author jwy
* @since
*/
public interface MiniAdoptionDiaryMediaMapper extends BaseMapper<MiniAdoptionDiaryMedia> {
}

21
src/main/java/com/youlai/boot/mini/model/dto/DeleteAdoptionDiaryDTO.java

@ -1,7 +1,28 @@
package com.youlai.boot.mini.model.dto; 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 lombok.Data; import lombok.Data;
import java.util.List;
@Data @Data
public class DeleteAdoptionDiaryDTO { public class DeleteAdoptionDiaryDTO {
@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> diaryUuidList;
} }

29
src/main/java/com/youlai/boot/mini/model/dto/DeleteAdoptionDiaryMediaDTO.java

@ -1,7 +1,36 @@
package com.youlai.boot.mini.model.dto; 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 lombok.Data; import lombok.Data;
import java.util.List;
@Data @Data
public class DeleteAdoptionDiaryMediaDTO { public class DeleteAdoptionDiaryMediaDTO {
@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> diaryMediaUuidList;
@NotBlank(message = "领养日记uuid不能为空")
@Schema(
description = "领养日记uuid",
example = "2d7890db8a6e47016ccef2d679d5a2c8",
requiredMode = Schema.RequiredMode.REQUIRED
)
private String diaryUuid;
} }

6
src/main/java/com/youlai/boot/mini/model/entity/MiniAdoptionDiary.java

@ -20,7 +20,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
public class MiniAdoptionDiary implements Serializable { public class MiniAdoptionDiary implements Serializable {
@TableId(value = "id", type = IdType.AUTO) @TableId(value = "id", type = IdType.AUTO)
@Schema(description = "笔记ID") @Schema(description = "领养日记主键ID")
private Long id; private Long id;
@ -37,11 +37,11 @@ public class MiniAdoptionDiary implements Serializable {
private Long miniUserId; private Long miniUserId;
@TableField("title") @TableField("title")
@Schema(description = "记标题") @Schema(description = "领养日记标题")
private String title; private String title;
@TableField("content") @TableField("content")
@Schema(description = "记正文内容") @Schema(description = "领养日记正文内容")
private String content; private String content;
@TableField("visibility") @TableField("visibility")

94
src/main/java/com/youlai/boot/mini/model/entity/MiniAdoptionDiaryMedia.java

@ -0,0 +1,94 @@
package com.youlai.boot.mini.model.entity;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
@Getter
@Setter
@ToString
@Accessors(chain = true)
@TableName("mini_adoption_diary_media")
@Schema(description = "领养日记资源表")
public class MiniAdoptionDiaryMedia implements Serializable {
@TableId(value = "id", type = IdType.AUTO)
@Schema(description = "领养日记媒体主键id")
private Long id;
@TableField("uuid")
@Schema(description = "uuid唯一标识,前后端用这个进行数据交互")
private String uuid;
@TableField("diary_id")
@Schema(description = "领养日记ID")
private Long diaryId;
@TableField("media_type")
@Schema(description = "媒体类型,image-图片,video-视频")
private String mediaType;
@TableField("source_url")
@Schema(description = "资源URL")
private String sourceUrl;
@TableField("storage_key")
@Schema(description = "对象存储中的key")
private String storageKey;
@TableField("thumbnail_url")
@Schema(description = "缩略图URL(视频需要)")
private String thumbnailUrl;
@TableField("width")
@Schema(description = "宽度(像素)")
private Integer width;
@TableField("height")
@Schema(description = "高度(像素)")
private Integer height;
@TableField("duration")
@Schema(description = "时长(秒,视频用)")
private Integer duration;
@TableField("create_time")
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@TableField("create_timestamp")
@Schema(description = "创建时间毫秒级时间戳")
private Long createTimestamp;
@TableField("create_by")
@Schema(description = "创建人ID")
private Long createBy;
@TableField("update_time")
@Schema(description = "更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
@TableField("update_timestamp")
@Schema(description = "更新时间毫秒级时间戳")
private Long updateTimestamp;
@TableField("update_by")
@Schema(description = "修改人ID")
private Long updateBy;
@TableField("is_deleted")
@Schema(description = "逻辑删除标识(0-未删除 1-已删除)")
private Boolean deleted;
}

29
src/main/java/com/youlai/boot/mini/model/form/AdoptionDiaryForm.java

@ -1,9 +1,36 @@
package com.youlai.boot.mini.model.form; package com.youlai.boot.mini.model.form;
import com.youlai.boot.common.annotation.EnumValid;
import com.youlai.boot.mini.model.enums.VisibilityEnum;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data; import lombok.Data;
import org.hibernate.validator.constraints.Length;
import java.util.List;
@Data @Data
@Schema(description = "评论点赞请求参数") @Schema(description = "领养日记表单对象")
public class AdoptionDiaryForm { public class AdoptionDiaryForm {
@NotNull(message = "关联的动物ID不能为空")
@Schema(description = "关联的流浪动物ID", requiredMode = Schema.RequiredMode.REQUIRED)
private Long strayAnimalId;
@NotBlank(message = "日记标题不能为空")
@Length(max = 200, message = "标题不能超过200个字符")
@Schema(description = "领养日记标题", example = "我家猫猫到家的第一个月", requiredMode = Schema.RequiredMode.REQUIRED)
private String title;
@Schema(description = "领养日记正文内容", example = "今天是猫猫到家的第30天,已经完全适应新家了~")
private String content;
@NotBlank(message = "可见性范围不能为空")
@EnumValid(enumClass = VisibilityEnum.class, message = "可见性范围不合法")
@Schema(description = "可见性范围:public-公开,private-仅自己,friends-仅好友", example = "public")
private String visibility;
@Schema(description = "上传的媒体资源URL列表")
private List<String> mediaUrlList;
} }

17
src/main/java/com/youlai/boot/mini/model/vo/AdoptionDiaryDetailsVO.java

@ -0,0 +1,17 @@
package com.youlai.boot.mini.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class AdoptionDiaryDetailsVO {
@Schema(description = "图片信息", example = "[]")
private List<MiniAdoptionDiaryMediaVO> images;
@Schema(description = "视频信息", example = "[]")
private List<MiniAdoptionDiaryMediaVO> videos;
}

63
src/main/java/com/youlai/boot/mini/model/vo/AdoptionDiaryVO.java

@ -1,7 +1,70 @@
package com.youlai.boot.mini.model.vo; package com.youlai.boot.mini.model.vo;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import java.util.Date;
@Data @Data
public class AdoptionDiaryVO { public class AdoptionDiaryVO {
@Schema(description = "领养日记ID", hidden = true)
private Long id;
@Schema(description = "作者uuid")
private String authorUuid;
@Schema(description = "作者昵称")
private String authorName;
@Schema(description = "作者头像")
private String authorAvatar;
@Schema(description = "领养日记UUID", requiredMode = Schema.RequiredMode.REQUIRED)
private String diaryUuid;
@Schema(description = "关联的流浪动物UUID")
private String animalUuid;
@Schema(description = "关联的流浪动物名称")
private String animalName;
@Schema(description = "封面图片url")
private String firstImageUrl;
@Schema(description = "日记标题", requiredMode = Schema.RequiredMode.REQUIRED)
private String title;
@Schema(description = "日记内容摘要")
private String content;
@Schema(description = "可见性范围:public-公开,private-仅自己,friends-仅好友", example = "public")
private String visibility;
@Schema(description = "浏览数")
private Integer viewCount;
@Schema(description = "点赞数")
private Integer likeCount;
@Schema(description = "评论数")
private Integer commentCount;
@Schema(description = "收藏数")
private Integer collectCount;
@Schema(description = "当前用户是否已点赞")
private Boolean isLiked;
@Schema(description = "当前用户是否收藏")
private Boolean isCollected;
@Schema(description = "创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createTime;
@Schema(description = "审核状态:0通过,1审核中,2审核未通过", example = "0")
private Integer auditStatus;
} }

35
src/main/java/com/youlai/boot/mini/model/vo/MiniAdoptionDiaryMediaVO.java

@ -0,0 +1,35 @@
package com.youlai.boot.mini.model.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Data
public class MiniAdoptionDiaryMediaVO {
@Schema(type = "string", description = "资源ID")
private String diaryMediaUuid;
@Schema(type = "string", description = "领养日记UUID", example = "0677d62d63ec693bf1bd6dab8a877dc1", requiredMode = Schema.RequiredMode.REQUIRED)
private String diaryUuid;
@Schema(description = "媒体类型,image-图片,video-视频")
private String mediaType;
@Schema(description = "资源URL")
private String sourceUrl;
@Schema(description = "对象存储中的key")
private String storageKey;
@Schema(description = "缩略图URL(视频需要)")
private String thumbnailUrl;
@Schema(description = "宽度(像素)")
private Integer width;
@Schema(description = "高度(像素)")
private Integer height;
@Schema(description = "时长(秒,视频用)")
private Integer duration;
}

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

@ -1,5 +1,6 @@
package com.youlai.boot.mini.service; package com.youlai.boot.mini.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryDTO; import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryDTO;
import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryMediaDTO; import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryMediaDTO;
@ -19,7 +20,7 @@ public interface AdoptionDiaryService extends IService<MiniAdoptionDiary> {
List<String> saveFile(List<MultipartFile> images, List<MultipartFile> videos); List<String> saveFile(List<MultipartFile> images, List<MultipartFile> videos);
SaveStrayAnimalVO saveAdoptionDiary(@Valid AdoptionDiaryForm formData); String saveAdoptionDiary(@Valid AdoptionDiaryForm formData);
void updateAdoptionDiary(String diaryUuid, AdoptionDiaryForm formData); void updateAdoptionDiary(String diaryUuid, AdoptionDiaryForm formData);
@ -31,8 +32,8 @@ public interface AdoptionDiaryService extends IService<MiniAdoptionDiary> {
void delete(DeleteAdoptionDiaryDTO deleteAdoptionDiaryDTO); void delete(DeleteAdoptionDiaryDTO deleteAdoptionDiaryDTO);
List<AdoptionDiaryVO> getSelfCreatedPage(OwnAdoptionDiaryQuery queryParams); IPage<AdoptionDiaryVO> getSelfCreatedPage(OwnAdoptionDiaryQuery queryParams);
StrayAnimalDetailsVO getDetails(String animalUuid, Long userId); // AdoptionDiaryVO getDetails(String diaryUuid, Long userId);
} }

352
src/main/java/com/youlai/boot/mini/service/impl/AdoptionDiaryServiceImpl.java

@ -1,64 +1,404 @@
package com.youlai.boot.mini.service.impl; package com.youlai.boot.mini.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.common.exception.MsgException;
import com.youlai.boot.common.util.FileUtils;
import com.youlai.boot.common.util.JavaVCUtils;
import com.youlai.boot.common.util.RandomNumberUtils;
import com.youlai.boot.file.service.impl.AliyunFileService;
import com.youlai.boot.framework.security.util.SecurityUtils;
import com.youlai.boot.mini.mapper.MiniAdoptionDiaryMapper; import com.youlai.boot.mini.mapper.MiniAdoptionDiaryMapper;
import com.youlai.boot.mini.mapper.MiniAdoptionDiaryMediaMapper;
import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryDTO; import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryDTO;
import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryMediaDTO; import com.youlai.boot.mini.model.dto.DeleteAdoptionDiaryMediaDTO;
import com.youlai.boot.mini.model.dto.EditVisibilityDTO; import com.youlai.boot.mini.model.dto.EditVisibilityDTO;
import com.youlai.boot.mini.model.entity.MiniAdoptionDiary; import com.youlai.boot.mini.model.entity.MiniAdoptionDiary;
import com.youlai.boot.mini.model.entity.MiniAdoptionDiaryMedia;
import com.youlai.boot.mini.model.enums.AnimalNoteMediaTypeEnum;
import com.youlai.boot.mini.model.form.AdoptionDiaryForm; import com.youlai.boot.mini.model.form.AdoptionDiaryForm;
import com.youlai.boot.mini.model.query.OwnAdoptionDiaryQuery; import com.youlai.boot.mini.model.query.OwnAdoptionDiaryQuery;
import com.youlai.boot.mini.model.vo.AdoptionDiaryVO; import com.youlai.boot.mini.model.vo.AdoptionDiaryVO;
import com.youlai.boot.mini.model.vo.SaveStrayAnimalVO;
import com.youlai.boot.mini.service.AdoptionDiaryService; import com.youlai.boot.mini.service.AdoptionDiaryService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.UUID;
@Slf4j
@Service @Service
@RequiredArgsConstructor
public class AdoptionDiaryServiceImpl extends ServiceImpl<MiniAdoptionDiaryMapper, MiniAdoptionDiary> implements AdoptionDiaryService { public class AdoptionDiaryServiceImpl extends ServiceImpl<MiniAdoptionDiaryMapper, MiniAdoptionDiary> implements AdoptionDiaryService {
private final AliyunFileService aliyunFileService;
private final MiniAdoptionDiaryMediaMapper miniAdoptionDiaryMediaMapper;
private final static String OSS_THUMBNAIL_DIR = "adoption_diary/thumbnail/";
private final static String OSS_IMAGE_DIR = "adoption_diary/image/";
private final static String OSS_VIDEO_DIR = "adoption_diary/video/";
@Value("${oss.aliyun.endpoint}")
private String endpoint;
@Value("${oss.aliyun.bucket-name}")
private String bucketName;
public String getDefaultCoverHost() {
return "https://" + bucketName + "." + endpoint;
}
@Override @Override
public List<String> saveFile(List<MultipartFile> images, List<MultipartFile> videos) { public List<String> saveFile(List<MultipartFile> images, List<MultipartFile> videos) {
return List.of(); long currentTimestamp = System.currentTimeMillis();
List<String> urlList = new ArrayList<>();
// 处理图片
if (CollUtil.isNotEmpty(images)) {
for (MultipartFile image : images) {
try {
String objectName = OSS_IMAGE_DIR
+ currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8)
+ "."
+ FilenameUtils.getExtension(image.getOriginalFilename());
String url = aliyunFileService.uploadFile(objectName, image.getInputStream());
MiniAdoptionDiaryMedia media = new MiniAdoptionDiaryMedia();
media.setUuid(UUID.randomUUID().toString());
media.setMediaType(AnimalNoteMediaTypeEnum.IMAGE.name().toLowerCase());
media.setSourceUrl(url);
media.setStorageKey(objectName);
BufferedImage imageInfo = ImageIO.read(image.getInputStream());
media.setWidth(imageInfo.getWidth());
media.setHeight(imageInfo.getHeight());
media.setCreateTimestamp(currentTimestamp);
media.setCreateTime(new Date(currentTimestamp));
media.setCreateBy(SecurityUtils.getUserId());
int result = miniAdoptionDiaryMediaMapper.insert(media);
if (result > 0) {
urlList.add(url);
}
} catch (Exception e) {
log.error("领养日记图片上传失败", e);
}
}
}
// 处理视频 (如果有)
if (CollUtil.isNotEmpty(videos)) {
String tmpPath = System.getProperty("user.dir") + "/tmp";
for (MultipartFile video : videos) {
try {
String fileName = currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String objectName = OSS_VIDEO_DIR
+ fileName
+ "."
+ FilenameUtils.getExtension(video.getOriginalFilename());
String url = aliyunFileService.uploadFile(objectName, video.getInputStream());
MiniAdoptionDiaryMedia media = new MiniAdoptionDiaryMedia();
media.setUuid(UUID.randomUUID().toString());
media.setMediaType(AnimalNoteMediaTypeEnum.VIDEO.name().toLowerCase());
media.setSourceUrl(url);
media.setStorageKey(objectName);
media.setCreateTimestamp(currentTimestamp);
media.setCreateTime(new Date(currentTimestamp));
media.setCreateBy(SecurityUtils.getUserId());
//时长
FileUtils.saveFile(video, tmpPath, fileName);
String videoPath = tmpPath + File.separator + fileName;
double duration = JavaVCUtils.getVideoDuration(videoPath);
media.setDuration((int) Math.ceil(duration));
//缩略图
BufferedImage thumbnail = JavaVCUtils.getVideoThumbnail(videoPath, 1);
String thumbnailFileName = currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String thumbnailObjectName = OSS_THUMBNAIL_DIR
+ thumbnailFileName
+ ".png";
String thumbnailUrl = aliyunFileService.uploadFile(thumbnailObjectName,
FileUtils.bufferedImageToInputStream(thumbnail, "png"));
media.setThumbnailUrl(thumbnailUrl);
int result = miniAdoptionDiaryMediaMapper.insert(media);
if (result > 0) {
urlList.add(url);
}
FileUtils.delete(videoPath);
} catch (Exception e) {
log.error("领养日记视频上传失败", e);
}
}
}
return urlList;
} }
@Override @Override
public SaveStrayAnimalVO saveAdoptionDiary(AdoptionDiaryForm formData) { @Transactional(rollbackFor = Exception.class)
return null; public String saveAdoptionDiary(AdoptionDiaryForm formData) {
long currentTimestamp = System.currentTimeMillis();
Long userId = SecurityUtils.getUserId();
// 1. 保存领养日记基本信息
MiniAdoptionDiary diary = new MiniAdoptionDiary();
diary.setUuid(UUID.randomUUID().toString());
diary.setMiniUserId(userId);
diary.setStrayAnimalId(formData.getStrayAnimalId());
diary.setTitle(formData.getTitle());
diary.setContent(formData.getContent());
diary.setVisibility(formData.getVisibility());
diary.setViewCount(0);
diary.setLikeCount(0);
diary.setCommentCount(0);
diary.setCollectCount(0);
diary.setCreateBy(userId);
diary.setCreateTime(new Date(currentTimestamp));
diary.setCreateTimestamp(currentTimestamp);
diary.setDeleted(false);
save(diary);
// 2. 关联之前上传的媒体文件
if (CollUtil.isNotEmpty(formData.getMediaUrlList())) {
LambdaUpdateWrapper<MiniAdoptionDiaryMedia> wrapper = new LambdaUpdateWrapper<>();
wrapper.in(MiniAdoptionDiaryMedia::getSourceUrl, formData.getMediaUrlList())
.isNull(MiniAdoptionDiaryMedia::getDiaryId)
.set(MiniAdoptionDiaryMedia::getDiaryId, diary.getId());
miniAdoptionDiaryMediaMapper.update(null, wrapper);
}
// 3.返回领养日记uuid
return diary.getUuid();
} }
@Override @Override
public void updateAdoptionDiary(String diaryUuid, AdoptionDiaryForm formData) { public void updateAdoptionDiary(String diaryUuid, AdoptionDiaryForm formData) {
MiniAdoptionDiary diary = lambdaQuery().eq(MiniAdoptionDiary::getUuid, diaryUuid).one();
if (diary == null) {
return;
}
long currentTimestamp = System.currentTimeMillis();
// 更新基本信息
diary.setTitle(formData.getTitle());
diary.setContent(formData.getContent());
diary.setUpdateBy(SecurityUtils.getUserId());
diary.setUpdateTime(new Date(currentTimestamp));
diary.setUpdateTimestamp(currentTimestamp);
updateById(diary);
// 关联新的媒体文件
if (CollUtil.isNotEmpty(formData.getMediaUrlList())) {
LambdaUpdateWrapper<MiniAdoptionDiaryMedia> wrapper = new LambdaUpdateWrapper<>();
wrapper.in(MiniAdoptionDiaryMedia::getSourceUrl, formData.getMediaUrlList())
.isNull(MiniAdoptionDiaryMedia::getDiaryId)
.set(MiniAdoptionDiaryMedia::getDiaryId, diary.getId());
miniAdoptionDiaryMediaMapper.update(null, wrapper);
}
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void deleteMediaSource(DeleteAdoptionDiaryMediaDTO deleteAdoptionDiaryMediaDTO) { public void deleteMediaSource(DeleteAdoptionDiaryMediaDTO deleteAdoptionDiaryMediaDTO) {
List<String> diaryMediaUuidList = deleteAdoptionDiaryMediaDTO.getDiaryMediaUuidList();
Long userId = SecurityUtils.getUserId();
// 校验领养日记是否存在
MiniAdoptionDiary diary = lambdaQuery()
.eq(MiniAdoptionDiary::getUuid, deleteAdoptionDiaryMediaDTO.getDiaryUuid())
.eq(MiniAdoptionDiary::getDeleted, false)
.one();
if (diary == null) {
throw new MsgException("领养日记不存在");
}
// 查询要删除的媒体资源
LambdaQueryWrapper<MiniAdoptionDiaryMedia> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.in(MiniAdoptionDiaryMedia::getUuid, diaryMediaUuidList)
.eq(MiniAdoptionDiaryMedia::getDiaryId, diary.getId())
.eq(MiniAdoptionDiaryMedia::getDeleted, false);
List<MiniAdoptionDiaryMedia> mediaList = miniAdoptionDiaryMediaMapper.selectList(queryWrapper);
if (CollectionUtils.isNotEmpty(mediaList)) {
// 删除阿里云OSS源文件
List<String> storageKeyList = mediaList.stream()
.map(MiniAdoptionDiaryMedia::getStorageKey)
.toList();
aliyunFileService.deleteMultiFile(storageKeyList);
long currentTimestamp = System.currentTimeMillis();
// 逻辑删除数据库记录
miniAdoptionDiaryMediaMapper.update(
null,
new LambdaUpdateWrapper<MiniAdoptionDiaryMedia>()
.in(MiniAdoptionDiaryMedia::getUuid, diaryMediaUuidList)
.eq(MiniAdoptionDiaryMedia::getDiaryId, diary.getId())
.set(MiniAdoptionDiaryMedia::getDeleted, true)
.set(MiniAdoptionDiaryMedia::getUpdateTimestamp, currentTimestamp)
.set(MiniAdoptionDiaryMedia::getUpdateTime, new Date(currentTimestamp))
.set(MiniAdoptionDiaryMedia::getUpdateBy, userId)
);
}
} }
@Override @Override
public void saveMediaSource(String diaryUuid, List<MultipartFile> images, List<MultipartFile> videos) { public void saveMediaSource(String diaryUuid, List<MultipartFile> images, List<MultipartFile> videos) {
MiniAdoptionDiary diary = lambdaQuery().eq(MiniAdoptionDiary::getUuid, diaryUuid).one();
if (diary == null) {
return;
}
long currentTimestamp = System.currentTimeMillis();
// 处理图片
if (CollUtil.isNotEmpty(images)) {
for (MultipartFile image : images) {
try {
String objectName = OSS_IMAGE_DIR
+ currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8)
+ "."
+ FilenameUtils.getExtension(image.getOriginalFilename());
String url = aliyunFileService.uploadFile(objectName, image.getInputStream());
MiniAdoptionDiaryMedia media = new MiniAdoptionDiaryMedia();
media.setUuid(UUID.randomUUID().toString());
media.setDiaryId(diary.getId());
media.setMediaType(AnimalNoteMediaTypeEnum.IMAGE.name().toLowerCase());
media.setSourceUrl(url);
media.setStorageKey(objectName);
BufferedImage imageInfo = ImageIO.read(image.getInputStream());
media.setWidth(imageInfo.getWidth());
media.setHeight(imageInfo.getHeight());
media.setCreateTimestamp(currentTimestamp);
media.setCreateTime(new Date(currentTimestamp));
media.setCreateBy(SecurityUtils.getUserId());
miniAdoptionDiaryMediaMapper.insert(media);
} catch (Exception e) {
log.error("领养日记补充图片上传失败", e);
}
}
}
// 处理视频
if (CollUtil.isNotEmpty(videos)) {
String tmpPath = System.getProperty("user.dir") + "/tmp";
for (MultipartFile video : videos) {
try {
String fileName = currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String objectName = OSS_VIDEO_DIR
+ fileName
+ "."
+ FilenameUtils.getExtension(video.getOriginalFilename());
String url = aliyunFileService.uploadFile(objectName, video.getInputStream());
MiniAdoptionDiaryMedia media = new MiniAdoptionDiaryMedia();
media.setUuid(UUID.randomUUID().toString());
media.setDiaryId(diary.getId());
media.setMediaType(AnimalNoteMediaTypeEnum.VIDEO.name().toLowerCase());
media.setSourceUrl(url);
media.setStorageKey(objectName);
media.setCreateTimestamp(currentTimestamp);
media.setCreateTime(new Date(currentTimestamp));
media.setCreateBy(SecurityUtils.getUserId());
// 时长
FileUtils.saveFile(video, tmpPath, fileName);
String videoPath = tmpPath + File.separator + fileName;
double duration = JavaVCUtils.getVideoDuration(videoPath);
media.setDuration((int) Math.ceil(duration));
// 缩略图
BufferedImage thumbnail = JavaVCUtils.getVideoThumbnail(videoPath, 1);
String thumbnailFileName = currentTimestamp + RandomNumberUtils.createRandomLowerLetterAndNumber(8);
String thumbnailObjectName = OSS_THUMBNAIL_DIR
+ thumbnailFileName
+ ".png";
String thumbnailUrl = aliyunFileService.uploadFile(thumbnailObjectName,
FileUtils.bufferedImageToInputStream(thumbnail, "png"));
media.setThumbnailUrl(thumbnailUrl);
miniAdoptionDiaryMediaMapper.insert(media);
FileUtils.delete(videoPath);
} catch (Exception e) {
log.error("领养日记补充视频上传失败", e);
}
}
}
} }
@Override @Override
@Transactional(rollbackFor = Exception.class)
public void updateVisibility(String diaryUuid, EditVisibilityDTO editVisibilityDTO) { public void updateVisibility(String diaryUuid, EditVisibilityDTO editVisibilityDTO) {
Long userId = SecurityUtils.getUserId();
// 校验领养日记是否存在,且是当前用户创建的
MiniAdoptionDiary diary = lambdaQuery()
.eq(MiniAdoptionDiary::getUuid, diaryUuid)
.eq(MiniAdoptionDiary::getMiniUserId, userId)
.eq(MiniAdoptionDiary::getDeleted, false)
.one();
if (diary == null) {
throw new MsgException("领养日记不存在");
}
// 更新可见范围
LambdaUpdateWrapper<MiniAdoptionDiary> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.eq(MiniAdoptionDiary::getId, diary.getId())
.set(MiniAdoptionDiary::getVisibility, editVisibilityDTO.getVisibility())
.set(MiniAdoptionDiary::getUpdateTime, new Date())
.set(MiniAdoptionDiary::getUpdateTimestamp, System.currentTimeMillis())
.set(MiniAdoptionDiary::getUpdateBy, userId);
update(updateWrapper);
} }
@Override @Override
public void delete(DeleteAdoptionDiaryDTO deleteAdoptionDiaryDTO) { public void delete(DeleteAdoptionDiaryDTO deleteAdoptionDiaryDTO) {
LambdaUpdateWrapper<MiniAdoptionDiary> updateWrapper = new LambdaUpdateWrapper<>();
updateWrapper.in(MiniAdoptionDiary::getUuid, deleteAdoptionDiaryDTO.getDiaryUuidList())
.set(MiniAdoptionDiary::getDeleted, 1);
update(null, updateWrapper);
} }
@Override @Override
public List<AdoptionDiaryVO> getSelfCreatedPage(OwnAdoptionDiaryQuery queryParams) { public IPage<AdoptionDiaryVO> getSelfCreatedPage(OwnAdoptionDiaryQuery queryParams) {
return List.of(); Long userId = SecurityUtils.getUserId();
queryParams.setMiniUserId(userId);
queryParams.setCreatorId(userId);
int pageNum = queryParams.getPageNum();
int pageSize = queryParams.getPageSize();
Page<AdoptionDiaryVO> page = new Page<>(pageNum, pageSize);
IPage<AdoptionDiaryVO> result = baseMapper.getDiaryPage(page, queryParams);
// 处理默认封面
if (result.getTotal() > 0) {
result.getRecords().forEach(item -> {
if (cn.hutool.core.util.StrUtil.isBlank(item.getFirstImageUrl())) {
// 领养日记默认封面图
item.setFirstImageUrl(getDefaultCoverHost() + "/default_diary.png");
}
});
}
return result;
} }
// @Override
// public AdoptionDiaryVO getDetails(String diaryUuid, Long userId) {
// AdoptionDiaryVO diaryVO = miniAdoptionDiaryMapper.getDiaryDetails(diaryUuid, userId);
// if (diaryVO != null && cn.hutool.core.util.StrUtil.isBlank(diaryVO.getFirstImageUrl())) {
// diaryVO.setFirstImageUrl(getDefaultCoverHost() + "/default_diary.png");
// }
// return diaryVO;
// }
} }

137
src/main/resources/mapper/mini/MiniAdoptionDiaryMapper.xml

@ -5,5 +5,142 @@
<mapper namespace="com.youlai.boot.mini.mapper.MiniAdoptionDiaryMapper"> <mapper namespace="com.youlai.boot.mini.mapper.MiniAdoptionDiaryMapper">
<select id="getDiaryPage" resultType="com.youlai.boot.mini.model.vo.AdoptionDiaryVO" databaseId="mysql">
WITH first_image AS (
SELECT
m.diary_id,
m.source_url,
ROW_NUMBER() OVER (
PARTITION BY m.diary_id
ORDER BY m.id ASC
) AS rn
FROM mini_adoption_diary_media m
WHERE m.media_type = 'image'
AND m.is_deleted = 0
)
SELECT
d.id,
d.uuid AS diaryUuid,
sa.uuid AS animalUuid,
sa.animal_name AS animalName,
d.title,
LEFT(d.content, 100) AS content,
d.visibility,
d.view_count AS viewCount,
d.like_count AS likeCount,
d.comment_count AS commentCount,
d.collect_count AS collectCount,
d.create_time AS createTime,
d.audit_status AS auditStatus,
u.uuid AS authorUuid,
u.nickname AS authorName,
u.avatar AS authorAvatar,
fi.source_url AS firstImageUrl,
<if test="query.miniUserId != null">
-- 当前用户是否点赞
EXISTS (
SELECT 1
FROM mini_adoption_diary_like l
WHERE l.diary_id = d.id
AND l.mini_user_id = #{query.miniUserId}
AND l.is_deleted = 0
) AS isLiked,
-- 当前用户是否收藏
EXISTS (
SELECT 1
FROM mini_adoption_diary_collect c
WHERE c.diary_id = d.id
AND c.mini_user_id = #{query.miniUserId}
AND c.is_deleted = 0
) AS isCollected,
</if>
<if test="query.miniUserId == null">
0 AS isLiked,
0 AS isCollected,
</if>
d.create_timestamp
FROM mini_adoption_diary d
INNER JOIN sys_user u ON d.mini_user_id = u.id AND u.is_deleted = 0
LEFT JOIN mini_stray_animal sa ON d.stray_animal_id = sa.id AND sa.is_deleted = 0
LEFT JOIN first_image fi ON fi.diary_id = d.id AND fi.rn = 1
<where>
d.is_deleted = 0
AND d.mini_user_id = #{query.creatorId}
<!-- 关键词搜索 -->
<if test="query.keyword != null and query.keyword != ''">
AND (d.title LIKE CONCAT('%', #{query.keyword}, '%') OR d.content LIKE CONCAT('%', #{query.keyword}, '%'))
</if>
<!-- 可见性筛选 -->
<if test="query.visibility != null and query.visibility != ''">
AND d.visibility = #{query.visibility}
</if>
<!-- 时间范围 -->
<if test="query.createStartTimestamp != null">
AND d.create_timestamp >= #{query.createStartTimestamp}
</if>
<if test="query.createEndTimestamp != null">
AND #{query.createEndTimestamp} >= d.create_timestamp
</if>
<!-- 审核状态筛选 -->
<if test="query.auditStatus != null">
AND d.audit_status = #{query.auditStatus}
</if>
</where>
ORDER BY d.create_timestamp DESC
</select>
<select id="getDiaryDetails" resultType="com.youlai.boot.mini.model.vo.AdoptionDiaryVO">
SELECT
d.id,
d.uuid AS diaryUuid,
sa.uuid AS animalUuid,
sa.animal_name AS animalName,
d.title,
d.content,
d.visibility,
d.view_count AS viewCount,
d.like_count AS likeCount,
d.comment_count AS commentCount,
d.collect_count AS collectCount,
d.create_time AS createTime,
d.audit_status AS auditStatus,
u.uuid AS authorUuid,
u.nickname AS authorName,
u.avatar AS authorAvatar,
(
SELECT source_url FROM mini_adoption_diary_media
WHERE diary_id = d.id AND media_type = 'image' AND is_deleted = 0
ORDER BY id ASC LIMIT 1
) AS firstImageUrl,
<if test="miniUserId != null">
-- 当前用户是否点赞
EXISTS (
SELECT 1
FROM mini_adoption_diary_like l
WHERE l.diary_id = d.id
AND l.mini_user_id = #{miniUserId}
AND l.is_deleted = 0
) AS isLiked,
-- 当前用户是否收藏
EXISTS (
SELECT 1
FROM mini_adoption_diary_collect c
WHERE c.diary_id = d.id
AND c.mini_user_id = #{miniUserId}
AND c.is_deleted = 0
) AS isCollected,
</if>
<if test="miniUserId == null">
0 AS isLiked,
0 AS isCollected,
</if>
-- 可扩展返回所有媒体资源列表,这里先返回首图即可,需要的话可以单独加接口返回所有媒体
d.create_timestamp
FROM mini_adoption_diary d
INNER JOIN sys_user u ON d.mini_user_id = u.id AND u.is_deleted = 0
LEFT JOIN mini_stray_animal sa ON d.stray_animal_id = sa.id AND sa.is_deleted = 0
WHERE d.uuid = #{diaryUuid}
AND d.is_deleted = 0
</select>
</mapper> </mapper>

9
src/main/resources/mapper/mini/MiniAdoptionDiaryMediaMapper.xml

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.youlai.boot.mini.mapper.MiniAdoptionDiaryMediaMapper">
</mapper>
Loading…
Cancel
Save