8个文件已修改
34个文件已添加
1 文件已重命名
New file |
| | |
| | | package cn.lili.controller.lmk; |
| | | |
| | | import cn.lili.group.Update; |
| | | import cn.lili.group.Add; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import lombok.RequiredArgsConstructor; |
| | | import java.util.List; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import javax.validation.constraints.NotEmpty; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import cn.lili.modules.lmk.service.VideoService; |
| | | import cn.lili.base.Result; |
| | | import cn.lili.modules.lmk.domain.form.VideoForm; |
| | | import cn.lili.modules.lmk.domain.query.VideoQuery; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | /** |
| | | * 视频内容 前端控制器 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @Api(value = "视频内容", tags = "视频内容管理") |
| | | @RestController |
| | | @RequestMapping("/buyer/lmk/video") |
| | | public class VideoController { |
| | | |
| | | private final VideoService videoService; |
| | | |
| | | @PostMapping("/publish") |
| | | @ApiOperation(value = "发布视频", notes = "发布视频") |
| | | public Result publish(@RequestBody @Validated({Add.class}) VideoForm form) { |
| | | return videoService.publish(form); |
| | | } |
| | | |
| | | @PutMapping |
| | | @ApiOperation(value = "修改", notes = "修改") |
| | | public Result update(@RequestBody @Validated(Update.class) VideoForm form) { |
| | | return videoService.update(form); |
| | | } |
| | | |
| | | @DeleteMapping("/{id}") |
| | | @ApiOperation(value = "ID删除", notes = "ID删除") |
| | | public Result removeById(@PathVariable("id") String id) { |
| | | return videoService.removeById(id); |
| | | } |
| | | |
| | | @DeleteMapping("/batch") |
| | | @ApiOperation(value = "批量删除", notes = "批量删除") |
| | | public Result remove(@RequestBody @NotEmpty(message = "请选择数据") List<String> ids) { |
| | | return videoService.remove(ids); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @ApiOperation(value = "分页", notes = "分页") |
| | | public Result page(VideoQuery query) { |
| | | return videoService.page(query); |
| | | } |
| | | |
| | | @GetMapping("/{id}") |
| | | @ApiOperation(value = "详情", notes = "详情") |
| | | public Result detail(@PathVariable("id") Integer id) { |
| | | return videoService.detail(id); |
| | | } |
| | | |
| | | @GetMapping("/list") |
| | | @ApiOperation(value = "列表", notes = "列表") |
| | | public Result list() { |
| | | return videoService.all(); |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.controller.lmk; |
| | | |
| | | import cn.lili.base.Result; |
| | | import cn.lili.group.Update; |
| | | import cn.lili.modules.lmk.domain.form.VideoForm; |
| | | import cn.lili.modules.lmk.domain.query.VideoQuery; |
| | | import cn.lili.modules.lmk.domain.query.WxVideoTagQuery; |
| | | import cn.lili.modules.lmk.service.VideoService; |
| | | import cn.lili.modules.lmk.service.VideoTagService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | import javax.validation.constraints.NotEmpty; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 视频标签 前端控制器 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @Api(value = "视频标签", tags = "视频标签") |
| | | @RestController |
| | | @RequestMapping("/buyer/lmk/video/tag") |
| | | public class VideoTagController { |
| | | |
| | | private final VideoTagService videoTagService; |
| | | |
| | | @GetMapping("/recommend") |
| | | @ApiOperation(value = "推荐标签", notes = "推荐标签") |
| | | public Result recommend(WxVideoTagQuery query) { |
| | | return videoTagService.recommend(query); |
| | | } |
| | | |
| | | } |
File was renamed from buyer-api/src/test/java/cn/lili/buyer/test/cart/FileTest.java |
| | |
| | | @Slf4j |
| | | @ExtendWith(SpringExtension.class) |
| | | @SpringBootTest |
| | | class FileTest { |
| | | class LmkFileTest { |
| | | |
| | | |
| | | @Autowired |
New file |
| | |
| | | package cn.lili.controller.lmk; |
| | | |
| | | import cn.lili.base.Result; |
| | | import cn.lili.modules.lmk.service.LmkFileService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.apache.ibatis.annotations.Delete; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.web.bind.annotation.*; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import javax.validation.constraints.NotEmpty; |
| | | import javax.validation.constraints.NotNull; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 文件信息 前端控制器 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @Api(value = "文件管理", tags = "文件管理") |
| | | @RestController("lmkFileController") |
| | | @RequestMapping("/common/lmk/file") |
| | | public class LmkFileController { |
| | | |
| | | private final LmkFileService lmkFileService; |
| | | |
| | | /** |
| | | * 单文件上传(返回有过期时间的链接) |
| | | * |
| | | * @param file |
| | | * @return |
| | | */ |
| | | @PostMapping("/upload") |
| | | @ApiOperation(value = "单文件上传(返回有过期时间的链接)") |
| | | public Result upload(@RequestPart("file") @NotNull MultipartFile file) { |
| | | return lmkFileService.uploadObject(file); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 多文件上传 |
| | | * |
| | | * @param files |
| | | * @return |
| | | */ |
| | | @PostMapping("/multi/upload") |
| | | @ApiOperation(value = "多文件上传(返回有过期时间的链接)") |
| | | public Result uploads(@RequestPart("files") @NotEmpty List<MultipartFile> files) { |
| | | return lmkFileService.uploadObjects(files); |
| | | } |
| | | |
| | | /** |
| | | * 删除某个文件 |
| | | * |
| | | * @param fileKey oss文件名 |
| | | * @return |
| | | */ |
| | | @Delete("/delete/{file_key}") |
| | | @ApiOperation(value = "删除某个文件") |
| | | public Result deleteObject(@PathVariable(value = "file_key") String fileKey) { |
| | | return lmkFileService.deleteObject(fileKey); |
| | | } |
| | | |
| | | /** |
| | | * 批量删除文件 |
| | | * |
| | | * @param fileKeys |
| | | * @return |
| | | */ |
| | | @Delete("/delete/files") |
| | | @ApiOperation(value = "批量删除文件") |
| | | public Result deleteObjects(@RequestBody @NotEmpty List<String> fileKeys) { |
| | | return lmkFileService.deleteObjects(fileKeys); |
| | | } |
| | | |
| | | /** |
| | | * 下载文件 |
| | | * |
| | | * @param fileKey |
| | | * @return |
| | | */ |
| | | @GetMapping("/download/{file_key}") |
| | | @ApiOperation(value = "下载文件") |
| | | public void downloadFile(@PathVariable(value = "file_key") String fileKey, HttpServletResponse response) { |
| | | lmkFileService.downloadObject(fileKey, response); |
| | | } |
| | | |
| | | /** |
| | | * 预览文件 |
| | | * |
| | | * @param fileKey |
| | | * @return |
| | | */ |
| | | @GetMapping("/preview/{file_key}") |
| | | @ApiOperation(value = "获取文件预览url(链接存在时效)") |
| | | public Result getPreviewUrl(@PathVariable(value = "file_key") String fileKey) { |
| | | return Result.ok().data(lmkFileService.getPreviewUrl(fileKey)); |
| | | } |
| | | |
| | | |
| | | @GetMapping("/sts") |
| | | @ApiOperation(value = "获取STS访问令牌", notes = "前端做直传") |
| | | public Result getSTSToken() { |
| | | return Result.ok().data(lmkFileService.getSTSToken()); |
| | | } |
| | | } |
| | |
| | | port: 8891 |
| | | logpath: ./xxl-job/executor |
| | | logretentiondays: 7 |
| | | |
| | | # 腾讯cos-sts配置 |
| | | cos: |
| | | secretId: AKIDYyBCzb1FOPGx0fCXfdOwJVWM1TjqmW3N # 腾讯ARM用户的secretId |
| | | secretKey: DD1b1LWVIvPlusAOYjnfKm150jO0NYWH # 腾讯ARM用户的secretKey |
| | | durationSeconds: 1800 # STS临时访问凭证有效期,单位秒,默认1800s,主账号最长2小时,子账号(ARM用户)36小时 |
| | | bucket: lmk-1308069279 |
| | | region: ap-chengdu |
| | | urlExpireMinute: 360 # 预签名url有效时间(分钟) |
| | | actions: # sts的权限 |
| | | - cos:ListMultipartUploads |
| | | - cos:GetBucket |
| | | - cos:GetObject |
| | | - cos:GetObjectTagging |
| | | - cos:GetSymlink |
| | | - cos:HeadObject |
| | | - cos:ListParts |
| | | - cos:AbortMultipartUpload |
| | | - cos:AppendObject |
| | | - cos:CompleteMultipartUpload |
| | | - cos:InitiateMultipartUpload |
| | | - cos:PostObject |
| | | - cos:PutObject |
| | | - cos:UploadPart |
| | | - cos:DeleteObject |
| | | - cos:PutObjectTagging |
| | | resources: # 能操作哪些资源 |
| | | - qcs::cos:ap-chengdu:uid/1308069279:lmk-1308069279/* |
| | |
| | | <packaging>jar</packaging> |
| | | |
| | | <dependencies> |
| | | <!-- 腾讯cos对象存储服务 --> |
| | | <dependency> |
| | | <groupId>com.qcloud</groupId> |
| | | <artifactId>cos_api</artifactId> |
| | | <version>${tx-cos.version}</version> |
| | | </dependency> |
| | | <dependency> |
| | | <groupId>com.qcloud</groupId> |
| | | <artifactId>cos-sts_api</artifactId> |
| | | <version>3.1.0</version> |
| | | </dependency> |
| | | |
| | | |
| | | |
| | | <dependency> |
| | | <groupId>com.qiniu</groupId> |
| | | <artifactId>qiniu-java-sdk</artifactId> |
| | |
| | | </dependencies> |
| | | |
| | | |
| | | </project> |
| | | </project> |
New file |
| | |
| | | package cn.lili.common.exception; |
| | | |
| | | /** |
| | | * 基础非检查异常 |
| | | * @author 29443 |
| | | * @version 1.0 |
| | | * @date 2022/4/25 |
| | | */ |
| | | public class BaseException extends RuntimeException { |
| | | |
| | | private String msg; |
| | | |
| | | private Integer code; |
| | | |
| | | public BaseException(String msg, Throwable cause) { |
| | | super(msg, cause); |
| | | } |
| | | |
| | | public BaseException(String msg) { |
| | | super(msg); |
| | | } |
| | | |
| | | public BaseException(String msg, Integer code) { |
| | | this.msg = msg; |
| | | this.code = code; |
| | | } |
| | | |
| | | public String getMsg() { |
| | | return msg; |
| | | } |
| | | |
| | | public Integer getCode() { |
| | | return code; |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.common.exception; |
| | | |
| | | /** |
| | | * @author 29443 |
| | | * @version 1.0 |
| | | * @date 2022/4/25 |
| | | */ |
| | | public class FileFormatNotSupport extends BaseException { |
| | | |
| | | private String suffix; |
| | | |
| | | public FileFormatNotSupport(String msg, Throwable cause) { |
| | | super(msg, cause); |
| | | } |
| | | |
| | | public FileFormatNotSupport(String msg) { |
| | | super(msg); |
| | | } |
| | | |
| | | public FileFormatNotSupport(String msg, String suffix) { |
| | | super(msg); |
| | | this.suffix = suffix; |
| | | } |
| | | |
| | | public FileFormatNotSupport(String msg, Integer code) { |
| | | super(msg, code); |
| | | } |
| | | |
| | | public String getSuffix() { |
| | | return suffix; |
| | | } |
| | | } |
| | |
| | | public class UserContext { |
| | | |
| | | /** |
| | | * 根据request获取用户id |
| | | * |
| | | * @return 授权用户 |
| | | */ |
| | | public static String getCurrentUserId() { |
| | | if (RequestContextHolder.getRequestAttributes() != null) { |
| | | HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); |
| | | String accessToken = request.getHeader(SecurityEnum.HEADER_TOKEN.getValue()); |
| | | return getAuthUser(accessToken).getId(); |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 根据request获取用户信息 |
| | | * |
| | | * @return 授权用户 |
New file |
| | |
| | | package cn.lili.cos; |
| | | |
| | | import org.springframework.boot.context.properties.ConfigurationProperties; |
| | | import org.springframework.context.annotation.Configuration; |
| | | |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 读取配置文件关于cos的配置 |
| | | * |
| | | * @author:xp |
| | | * @date:2025/5/16 16:23 |
| | | */ |
| | | @Configuration |
| | | @ConfigurationProperties(prefix = "cos") |
| | | public class COSConfigProperty { |
| | | |
| | | /** 腾讯ARM用户的secretId */ |
| | | private String secretId; |
| | | |
| | | /** 腾讯ARM用户的secretKey */ |
| | | private String secretKey; |
| | | |
| | | /** STS临时访问凭证有效期,单位秒,默认1800s,主账号最长2小时,子账号(ARM用户)36小时 */ |
| | | private Integer durationSeconds; |
| | | |
| | | /** bucket所在的地域 */ |
| | | private String region; |
| | | |
| | | /** bucket名称 */ |
| | | private String bucket; |
| | | |
| | | /** 预签名url过期时间(分钟) */ |
| | | private Integer urlExpireMinute; |
| | | |
| | | /** sts的权限 */ |
| | | private String[] actions; |
| | | |
| | | /** sts能操作的资源 */ |
| | | private String[] resources; |
| | | |
| | | public String getSecretId() { |
| | | return secretId; |
| | | } |
| | | |
| | | public void setSecretId(String secretId) { |
| | | this.secretId = secretId; |
| | | } |
| | | |
| | | public String getSecretKey() { |
| | | return secretKey; |
| | | } |
| | | |
| | | public void setSecretKey(String secretKey) { |
| | | this.secretKey = secretKey; |
| | | } |
| | | |
| | | public Integer getDurationSeconds() { |
| | | return durationSeconds; |
| | | } |
| | | |
| | | public void setDurationSeconds(Integer durationSeconds) { |
| | | this.durationSeconds = durationSeconds; |
| | | } |
| | | |
| | | public String getRegion() { |
| | | return region; |
| | | } |
| | | |
| | | public void setRegion(String region) { |
| | | this.region = region; |
| | | } |
| | | |
| | | public String getBucket() { |
| | | return bucket; |
| | | } |
| | | |
| | | public void setBucket(String bucket) { |
| | | this.bucket = bucket; |
| | | } |
| | | |
| | | public String[] getActions() { |
| | | return actions; |
| | | } |
| | | |
| | | public void setActions(String[] actions) { |
| | | this.actions = actions; |
| | | } |
| | | |
| | | public String[] getResources() { |
| | | return resources; |
| | | } |
| | | |
| | | public void setResources(String[] resources) { |
| | | this.resources = resources; |
| | | } |
| | | |
| | | public Integer getUrlExpireMinute() { |
| | | return urlExpireMinute; |
| | | } |
| | | |
| | | public void setUrlExpireMinute(Integer urlExpireMinute) { |
| | | this.urlExpireMinute = urlExpireMinute; |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.cos; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * sts临时访问凭证对象 |
| | | * @author:xp |
| | | * @date:2025/5/16 16:33 |
| | | */ |
| | | @Data |
| | | @ApiModel("STS临时访问凭证") |
| | | public class CosSTS { |
| | | |
| | | @ApiModelProperty("临时密钥id") |
| | | private String tmpSecretId; |
| | | |
| | | @ApiModelProperty("临时密钥key") |
| | | private String tmpSecretKey; |
| | | |
| | | @ApiModelProperty("sts-token") |
| | | private String sessionToken; |
| | | |
| | | @ApiModelProperty("sts起效时间") |
| | | private Long stsStartTime; |
| | | |
| | | @ApiModelProperty("sts失效时间") |
| | | private Long stsEndTime; |
| | | |
| | | @ApiModelProperty("bucket") |
| | | private String bucket; |
| | | |
| | | @ApiModelProperty("region") |
| | | private String region; |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.entity; |
| | | |
| | | import cn.lili.mybatis.BaseEntity; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import java.io.Serializable; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 文件信息 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Data |
| | | @TableName("lmk_file") |
| | | public class LmkFile extends BaseEntity { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableField("file_key") |
| | | /** 文件唯一标识 */ |
| | | private String fileKey; |
| | | |
| | | @TableField("file_type") |
| | | /** 文件类型 */ |
| | | private String fileType; |
| | | |
| | | @TableField("file_size") |
| | | /** 文件大小 */ |
| | | private Long fileSize; |
| | | |
| | | @TableField("original_filename") |
| | | /** 文件原始名 */ |
| | | private String originalFileName; |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.entity; |
| | | |
| | | import cn.lili.mybatis.BaseEntity; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import java.io.Serializable; |
| | | import java.time.LocalDateTime; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 视频内容 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Data |
| | | @TableName("lmk_video") |
| | | public class Video extends BaseEntity { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableField("author_id") |
| | | /** 作者id */ |
| | | private String authorId; |
| | | |
| | | @TableField("cover_url") |
| | | /** 图片封面 */ |
| | | private String coverUrl; |
| | | |
| | | @TableField("video_file_key") |
| | | /** 视频地址 */ |
| | | private String videoFileKey; |
| | | |
| | | @TableField("video_fit") |
| | | /** 视频填充模式 */ |
| | | private String videoFit; |
| | | |
| | | @TableField("title") |
| | | /** 视频标题 */ |
| | | private String title; |
| | | |
| | | @TableField("goods_id") |
| | | /** 商品id */ |
| | | private String goodsId; |
| | | |
| | | @TableField("goods_view_num") |
| | | /** 商品查看次数 */ |
| | | private Long goodsViewNum; |
| | | |
| | | @TableField("goods_order_num") |
| | | /** 商品下单次数 */ |
| | | private Long goodsOrderNum; |
| | | |
| | | @TableField("recommend") |
| | | /** 是否推荐 */ |
| | | private Boolean recommend; |
| | | |
| | | @TableField("status") |
| | | /** 状态 */ |
| | | private String status; |
| | | |
| | | @TableField("play_num") |
| | | /** 播放量 */ |
| | | private Long playNum; |
| | | |
| | | @TableField("collect_num") |
| | | /** 收藏数 */ |
| | | private Long collectNum; |
| | | |
| | | @TableField("comment_num") |
| | | /** 评论数 */ |
| | | private Long commentNum; |
| | | |
| | | @TableField("weight") |
| | | /** 权重 */ |
| | | private Double weight; |
| | | |
| | | @TableField("audit_pass_time") |
| | | /** 审核通过时间 */ |
| | | private LocalDateTime auditPassTime; |
| | | |
| | | |
| | | } |
| | |
| | | /** 创建方式 */ |
| | | private String createType; |
| | | |
| | | @TableField("use_num") |
| | | /** 视频引用次数 */ |
| | | private Long useNum; |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.entity; |
| | | |
| | | import cn.lili.mybatis.BaseEntity; |
| | | import cn.lili.mybatis.BaseIdEntity; |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.baomidou.mybatisplus.annotation.TableName; |
| | | import java.io.Serializable; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 视频标签中间表 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Data |
| | | @TableName("lmk_video_tag_ref") |
| | | public class VideoTagRef extends BaseIdEntity { |
| | | |
| | | private static final long serialVersionUID = 1L; |
| | | |
| | | @TableField("video_id") |
| | | /** 视频id */ |
| | | private String videoId; |
| | | |
| | | @TableField("video_tag_id") |
| | | /** 视频标签id */ |
| | | private String videoTagId; |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.form; |
| | | |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | /** |
| | | * 小程序直传,需要把上传的文件信息传到后端保存 |
| | | * |
| | | * @author:xp |
| | | * @date:2025/5/19 15:17 |
| | | */ |
| | | @Data |
| | | @Validated |
| | | @ApiModel("小程序直传文件信息") |
| | | public class FileInfoForm { |
| | | |
| | | @ApiModelProperty("文件标识") |
| | | private String fileKey; |
| | | |
| | | @ApiModelProperty("文件类型") |
| | | private String fileType; |
| | | |
| | | @ApiModelProperty("文件大小") |
| | | private Long fileSize; |
| | | |
| | | @ApiModelProperty("文件原始名") |
| | | private String originalFileName; |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.form; |
| | | |
| | | import cn.lili.group.Update; |
| | | import cn.lili.group.Add; |
| | | import cn.lili.base.AbsForm; |
| | | import cn.lili.modules.lmk.domain.entity.Video; |
| | | import org.hibernate.validator.constraints.Length; |
| | | import org.springframework.beans.BeanUtils; |
| | | |
| | | import javax.validation.Valid; |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | import org.springframework.lang.NonNull; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.Date; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 视频内容表单 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Data |
| | | @ApiModel(value = "Video表单", description = "视频内容表单") |
| | | public class VideoForm extends AbsForm { |
| | | |
| | | |
| | | @NotBlank(message = "视频不能为空", groups = {Add.class, Update.class}) |
| | | @ApiModelProperty("视频") |
| | | private String videoFileKey; |
| | | |
| | | @NotBlank(message = "标题不能为空", groups = {Add.class, Update.class}) |
| | | @ApiModelProperty("标题") |
| | | private String title; |
| | | |
| | | @ApiModelProperty("视频标签") |
| | | @Length(max = 5, message = "最多只能添加五个标签") |
| | | private List<WxVideoTagForm> tags = new ArrayList<>(2); |
| | | |
| | | // @NotBlank(message = "商品id不能为空", groups = {Add.class, Update.class}) |
| | | @ApiModelProperty("商品id") |
| | | private String goodsId; |
| | | |
| | | @ApiModelProperty("视频填充模式") |
| | | private String videoFit; |
| | | |
| | | @ApiModelProperty("文件信息") |
| | | @Valid |
| | | private FileInfoForm fileInfo; |
| | | |
| | | public static Video getEntityByForm(@NonNull VideoForm form, Video entity) { |
| | | if(entity == null) { |
| | | entity = new Video(); |
| | | } |
| | | BeanUtils.copyProperties(form, entity); |
| | | return entity; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.form; |
| | | |
| | | import cn.lili.base.AbsForm; |
| | | import cn.lili.group.Add; |
| | | import cn.lili.group.Update; |
| | | import cn.lili.modules.lmk.domain.entity.VideoTag; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.lang.NonNull; |
| | | |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | |
| | | /** |
| | | * 视频标签表单 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-13 |
| | | */ |
| | | @Data |
| | | @ApiModel(value = "VideoTag表单", description = "视频标签表单") |
| | | public class WxVideoTagForm extends AbsForm { |
| | | |
| | | @ApiModelProperty("标签名称") |
| | | private String tagName; |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.query; |
| | | |
| | | import cn.lili.base.AbsQuery; |
| | | import java.util.List; |
| | | import org.springframework.lang.NonNull; |
| | | import javax.validation.constraints.NotBlank; |
| | | import javax.validation.constraints.NotNull; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 视频内容查询 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Data |
| | | @ApiModel(value = "Video查询参数", description = "视频内容查询参数") |
| | | public class VideoQuery extends AbsQuery { |
| | | } |
| | | |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.query; |
| | | |
| | | import cn.lili.base.AbsQuery; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 视频标签查询 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-13 |
| | | */ |
| | | @Data |
| | | @ApiModel(value = "VideoTag查询参数", description = "视频标签查询参数") |
| | | public class WxVideoTagQuery { |
| | | |
| | | @ApiModelProperty("标签名称") |
| | | private String tagName; |
| | | |
| | | @ApiModelProperty("搜索类型:HOT(热门标签)、SEARCH(根据输入的标签名称搜索)") |
| | | private String searchType = "HOT"; |
| | | |
| | | } |
| | | |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.vo; |
| | | |
| | | import cn.lili.base.AbsVo; |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import lombok.experimental.Accessors; |
| | | import org.springframework.lang.NonNull; |
| | | import org.springframework.beans.BeanUtils; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | | * 文件信息展示 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Data |
| | | @Accessors(chain = true) |
| | | @ApiModel(value = "文件信息响应数据", description = "文件信息响应数据") |
| | | public class LmkFileVO extends AbsVo { |
| | | |
| | | /** |
| | | * 临时访问链接 |
| | | */ |
| | | @ApiModelProperty("临时访问链接") |
| | | private String url; |
| | | |
| | | /** |
| | | * fileKey数据库保存的值 |
| | | */ |
| | | @ApiModelProperty("文件标识") |
| | | private String fileKey; |
| | | |
| | | /** |
| | | * 文件名 |
| | | */ |
| | | @ApiModelProperty("文件原始名") |
| | | private String originalName; |
| | | |
| | | public static LmkFileVO getVoByEntity(@NonNull LmkFile entity, LmkFileVO vo) { |
| | | if(vo == null) { |
| | | vo = new LmkFileVO(); |
| | | } |
| | | BeanUtils.copyProperties(entity, vo); |
| | | return vo; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.domain.vo; |
| | | |
| | | import cn.lili.base.AbsVo; |
| | | import cn.lili.modules.lmk.domain.entity.Video; |
| | | import java.util.List; |
| | | import org.springframework.lang.NonNull; |
| | | import org.springframework.beans.BeanUtils; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | | import lombok.Data; |
| | | import java.util.Date; |
| | | |
| | | /** |
| | | * 视频内容展示 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Data |
| | | @ApiModel(value = "视频内容响应数据", description = "视频内容响应数据") |
| | | public class VideoVO extends AbsVo { |
| | | |
| | | /** 作者id */ |
| | | @ApiModelProperty("作者id") |
| | | private String authorId; |
| | | |
| | | /** 图片封面 */ |
| | | @ApiModelProperty("图片封面") |
| | | private String coverUrl; |
| | | |
| | | /** 视频地址 */ |
| | | @ApiModelProperty("视频地址") |
| | | private String videoFileKey; |
| | | |
| | | /** 视频填充模式 */ |
| | | @ApiModelProperty("视频填充模式") |
| | | private String videoFit; |
| | | |
| | | /** 视频标题 */ |
| | | @ApiModelProperty("视频标题") |
| | | private String title; |
| | | |
| | | /** 商品id */ |
| | | @ApiModelProperty("商品id") |
| | | private String goodsId; |
| | | |
| | | /** 商品查看次数 */ |
| | | @ApiModelProperty("商品查看次数") |
| | | private Long goodsViewNum; |
| | | |
| | | /** 商品下单次数 */ |
| | | @ApiModelProperty("商品下单次数") |
| | | private Long goodsOrderNum; |
| | | |
| | | /** 是否推荐 */ |
| | | @ApiModelProperty("是否推荐") |
| | | private Boolean recommend; |
| | | |
| | | /** 状态 */ |
| | | @ApiModelProperty("状态") |
| | | private String status; |
| | | |
| | | /** 播放量 */ |
| | | @ApiModelProperty("播放量") |
| | | private Long playNum; |
| | | |
| | | /** 收藏数 */ |
| | | @ApiModelProperty("收藏数") |
| | | private Long collectNum; |
| | | |
| | | /** 评论数 */ |
| | | @ApiModelProperty("评论数") |
| | | private Long commentNum; |
| | | |
| | | /** 权重 */ |
| | | @ApiModelProperty("权重") |
| | | private double weight; |
| | | |
| | | /** 审核通过时间 */ |
| | | @ApiModelProperty("审核通过时间") |
| | | private Date auditPassTime; |
| | | |
| | | public static VideoVO getVoByEntity(@NonNull Video entity, VideoVO vo) { |
| | | if(vo == null) { |
| | | vo = new VideoVO(); |
| | | } |
| | | BeanUtils.copyProperties(entity, vo); |
| | | return vo; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.enums.general; |
| | | |
| | | |
| | | import java.util.Arrays; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * oss文件分类目录,文件类型白名单 |
| | | * @author 29443 |
| | | * |
| | | */ |
| | | |
| | | public enum FileTypeEnum { |
| | | |
| | | IMAGE("image", "图片", Arrays.asList("jpg", "png", "jpeg", "gif", "bmp", "webp", "tiff", "svg", "ico", "psd", "raw")), |
| | | |
| | | VIDEO("video", "视频", Arrays.asList("mp4", "avi", "rmvb", "mov", "wmv", "flv", "mkv", "mpeg", "mpg", "m4v", "3gp", "webm", "vob", "swf")), |
| | | |
| | | RADIO("radio", "音频", Arrays.asList("mp3", "wma", "wav", "mpeg-4", "cd", "m4a", "aac", "flac", "ogg", "aiff", "ape", "midi", "amr", "ra")), |
| | | |
| | | TEXT("text", "文本文件", Arrays.asList("txt", "xls", "xlsx", "doc", "docx", "pdf", "ppt", "pptx", "csv", "rtf", "odt", "ods", "odp", "epub", "mobi", "pages", "numbers", "key")), |
| | | |
| | | ZIP("zip", "压缩文件", Arrays.asList("zip", "rar", "7z", "tar", "gz", "bz2", "xz", "iso", "dmg", "pkg", "cab", "z", "lz", "lzma", "lzo")), |
| | | ; |
| | | |
| | | /** |
| | | * 类型 |
| | | */ |
| | | private final String type; |
| | | |
| | | /** |
| | | * 类型对应的后缀 |
| | | */ |
| | | private final List<String> suffixs; |
| | | |
| | | /** |
| | | * 描述 |
| | | */ |
| | | private final String desc; |
| | | |
| | | FileTypeEnum(String type, String desc, List<String> suffixs) { |
| | | this.type = type; |
| | | this.suffixs = suffixs; |
| | | this.desc = desc; |
| | | } |
| | | |
| | | public String getType() { |
| | | return type; |
| | | } |
| | | |
| | | public List<String> getSuffixs() { |
| | | return suffixs; |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.enums.general; |
| | | |
| | | import lombok.Getter; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | |
| | | /** |
| | | * 视频标签来源 |
| | | * |
| | | * @author:xp |
| | | * @date:2025/5/14 10:30 |
| | | */ |
| | | @Getter |
| | | public enum VideoStatusEnum { |
| | | |
| | | AUDITING("99", "审核中"), |
| | | PUBLISHED("1", "已发布"), |
| | | DISABLE("0", "已下架"), |
| | | REJECT("-1", "审核未通过"), |
| | | ; |
| | | |
| | | private final String value; |
| | | |
| | | |
| | | private final String desc; |
| | | |
| | | VideoStatusEnum(String value, String desc) { |
| | | this.value = value; |
| | | this.desc = desc; |
| | | } |
| | | |
| | | /** |
| | | * 获取含义 |
| | | * |
| | | * @param value |
| | | * @return |
| | | */ |
| | | public static String getDescByValue(String value) { |
| | | if (StringUtils.isBlank(value)) { |
| | | return null; |
| | | } |
| | | for (VideoStatusEnum e : VideoStatusEnum.values()){ |
| | | if (value.equals(e.getValue())) { |
| | | return e.getDesc(); |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.mapper; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import cn.lili.modules.lmk.domain.vo.LmkFileVO; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | /** |
| | | * 文件信息 Mapper 接口 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Mapper |
| | | public interface LmkFileMapper extends BaseMapper<LmkFile> { |
| | | |
| | | /** |
| | | * 查找文件信息 |
| | | * |
| | | * @param fileKey |
| | | * @return |
| | | */ |
| | | LmkFile getByFileKey(String fileKey); |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.mapper; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.Video; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import cn.lili.modules.lmk.domain.vo.VideoVO; |
| | | import cn.lili.modules.lmk.domain.form.VideoForm; |
| | | import cn.lili.modules.lmk.domain.query.VideoQuery; |
| | | import java.util.List; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | import org.apache.ibatis.annotations.Param; |
| | | |
| | | /** |
| | | * 视频内容 Mapper 接口 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Mapper |
| | | public interface VideoMapper extends BaseMapper<Video> { |
| | | |
| | | /** |
| | | * id查找视频内容 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | VideoVO getById(Integer id); |
| | | |
| | | /** |
| | | * 分页 |
| | | */ |
| | | IPage getPage(IPage page, @Param("query") VideoQuery query); |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.mapper; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.VideoTagRef; |
| | | import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | | /** |
| | | * 视频标签中间表 Mapper 接口 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Mapper |
| | | public interface VideoTagRefMapper extends BaseMapper<VideoTagRef> { |
| | | |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.service; |
| | | |
| | | import cn.lili.base.Result; |
| | | import cn.lili.cos.CosSTS; |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import cn.lili.modules.lmk.domain.form.FileInfoForm; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 文件信息 服务类 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | public interface LmkFileService extends IService<LmkFile> { |
| | | |
| | | /** |
| | | * 上传单个文件 |
| | | * |
| | | * @param file |
| | | * @return |
| | | */ |
| | | Result uploadObject(MultipartFile file); |
| | | |
| | | /** |
| | | * 上传多个文件 |
| | | * |
| | | * @param files |
| | | * @return |
| | | */ |
| | | Result uploadObjects(List<MultipartFile> files); |
| | | |
| | | /** |
| | | * 删除单个文件 |
| | | * |
| | | * @param fileKey |
| | | * @return |
| | | */ |
| | | Result deleteObject(String fileKey); |
| | | |
| | | /** |
| | | * 删除多个文件 |
| | | * |
| | | * @param fileKeys |
| | | * @return |
| | | */ |
| | | Result deleteObjects(List<String> fileKeys); |
| | | |
| | | /** |
| | | * 下载文件 |
| | | * |
| | | * @param fileKey |
| | | * @param response |
| | | * @return |
| | | */ |
| | | void downloadObject(String fileKey, HttpServletResponse response); |
| | | |
| | | /** |
| | | * 预览文件 |
| | | * |
| | | * @param fileKey |
| | | * @return |
| | | */ |
| | | String getPreviewUrl(String fileKey); |
| | | |
| | | /** |
| | | * 获取sts临时访问凭证 |
| | | * |
| | | * @return |
| | | */ |
| | | CosSTS getSTSToken(); |
| | | |
| | | /** |
| | | * 保存文件信息 |
| | | * |
| | | * @param fileInfo |
| | | */ |
| | | void addByForm(FileInfoForm fileInfo); |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.service; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.Video; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import cn.lili.base.Result; |
| | | import cn.lili.modules.lmk.domain.form.VideoForm; |
| | | import cn.lili.modules.lmk.domain.query.VideoQuery; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 视频内容 服务类 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | public interface VideoService extends IService<Video> { |
| | | |
| | | /** |
| | | * 添加 |
| | | * @param form |
| | | * @return |
| | | */ |
| | | Result add(VideoForm form); |
| | | |
| | | /** |
| | | * 修改 |
| | | * @param form |
| | | * @return |
| | | */ |
| | | Result update(VideoForm form); |
| | | |
| | | /** |
| | | * 批量删除 |
| | | * @param ids |
| | | * @return |
| | | */ |
| | | Result remove(List<String> ids); |
| | | |
| | | /** |
| | | * id删除 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | Result removeById(String id); |
| | | |
| | | /** |
| | | * 分页查询 |
| | | * @param query |
| | | * @return |
| | | */ |
| | | Result page(VideoQuery query); |
| | | |
| | | /** |
| | | * 根据id查找 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | Result detail(Integer id); |
| | | |
| | | /** |
| | | * 列表 |
| | | * @return |
| | | */ |
| | | Result all(); |
| | | |
| | | /** |
| | | * 发布视频 |
| | | * |
| | | * @param form |
| | | * @return |
| | | */ |
| | | Result publish(VideoForm form); |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.service; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.VideoTagRef; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | |
| | | /** |
| | | * 视频标签中间表 服务类 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | public interface VideoTagRefService extends IService<VideoTagRef> { |
| | | |
| | | |
| | | } |
| | |
| | | package cn.lili.modules.lmk.service; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.VideoTag; |
| | | import cn.lili.modules.lmk.domain.query.WxVideoTagQuery; |
| | | import com.baomidou.mybatisplus.extension.service.IService; |
| | | import cn.lili.base.Result; |
| | | import cn.lili.modules.lmk.domain.form.VideoTagForm; |
| | |
| | | * @return |
| | | */ |
| | | Result all(); |
| | | |
| | | /** |
| | | * 推荐标签 |
| | | * |
| | | * @param query |
| | | * @return |
| | | */ |
| | | Result recommend(WxVideoTagQuery query); |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.service.impl; |
| | | |
| | | import cn.lili.base.Result; |
| | | import cn.lili.common.exception.ServiceException; |
| | | import cn.lili.cos.CosSTS; |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import cn.lili.modules.lmk.domain.form.FileInfoForm; |
| | | import cn.lili.modules.lmk.domain.vo.LmkFileVO; |
| | | import cn.lili.modules.lmk.mapper.LmkFileMapper; |
| | | import cn.lili.modules.lmk.service.LmkFileService; |
| | | import cn.lili.utils.COSUtil; |
| | | import cn.lili.utils.FileUtil; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Propagation; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.util.List; |
| | | |
| | | /** |
| | | * 文件信息 服务实现类 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class LmkFileServiceImpl extends ServiceImpl<LmkFileMapper, LmkFile> implements LmkFileService { |
| | | |
| | | private final LmkFileMapper lmkFileMapper; |
| | | private final COSUtil cosUtil; |
| | | |
| | | |
| | | @Override |
| | | public Result uploadObject(MultipartFile file) { |
| | | LmkFile fileInfo = FileUtil.getFileInfo(file); |
| | | try { |
| | | cosUtil.upload(file.getInputStream(), fileInfo); |
| | | lmkFileMapper.insert(fileInfo); |
| | | } catch (IOException e) { |
| | | e.printStackTrace(); |
| | | throw new ServiceException("上传异常,请重试"); |
| | | } |
| | | String url = cosUtil.getPreviewUrl(fileInfo.getFileKey()); |
| | | LmkFileVO fileVo = new LmkFileVO().setUrl(url).setFileKey(fileInfo.getFileKey()); |
| | | return Result.ok("上传成功").data(fileVo); |
| | | } |
| | | |
| | | @Override |
| | | public Result uploadObjects(List<MultipartFile> files) { |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | public Result deleteObject(String fileKey) { |
| | | cosUtil.deleteFile(fileKey); |
| | | return Result.ok("删除成功"); |
| | | } |
| | | |
| | | @Override |
| | | public Result deleteObjects(List<String> fileKeys) { |
| | | cosUtil.deleteFiles(fileKeys); |
| | | return Result.ok("删除成功"); |
| | | } |
| | | |
| | | @Override |
| | | public void downloadObject(String fileKey, HttpServletResponse response) { |
| | | cosUtil.download(fileKey, response); |
| | | } |
| | | |
| | | @Override |
| | | public String getPreviewUrl(String fileKey) { |
| | | return cosUtil.getPreviewUrl(fileKey); |
| | | } |
| | | |
| | | @Override |
| | | public CosSTS getSTSToken() { |
| | | return cosUtil.getSTS(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(propagation = Propagation.REQUIRED) |
| | | public void addByForm(FileInfoForm fileInfo) { |
| | | LmkFile file = new LmkFile(); |
| | | BeanUtils.copyProperties(fileInfo, file); |
| | | baseMapper.insert(file); |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.service.impl; |
| | | |
| | | import cn.lili.common.security.context.UserContext; |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import cn.lili.modules.lmk.domain.entity.VideoTag; |
| | | import cn.lili.modules.lmk.domain.entity.VideoTagRef; |
| | | import cn.lili.modules.lmk.enums.general.TagCreateTypeEnum; |
| | | import cn.lili.modules.lmk.enums.general.VideoStatusEnum; |
| | | import cn.lili.modules.lmk.service.LmkFileService; |
| | | import cn.lili.modules.lmk.service.VideoTagRefService; |
| | | import cn.lili.modules.lmk.service.VideoTagService; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import cn.lili.modules.lmk.domain.entity.Video; |
| | | import cn.lili.modules.lmk.mapper.VideoMapper; |
| | | import cn.lili.modules.lmk.service.VideoService; |
| | | import cn.lili.base.Result; |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import cn.lili.modules.lmk.domain.form.VideoForm; |
| | | import cn.lili.modules.lmk.domain.vo.VideoVO; |
| | | import cn.lili.modules.lmk.domain.query.VideoQuery; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.stereotype.Service; |
| | | import lombok.RequiredArgsConstructor; |
| | | import cn.lili.utils.PageUtil; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.util.Assert; |
| | | |
| | | import java.util.List; |
| | | import java.util.Objects; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 视频内容 服务实现类 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class VideoServiceImpl extends ServiceImpl<VideoMapper, Video> implements VideoService { |
| | | |
| | | private final VideoMapper videoMapper; |
| | | private final VideoTagService videoTagService; |
| | | private final VideoTagRefService videoTagRefService; |
| | | private final LmkFileService lmkFileService; |
| | | |
| | | /** |
| | | * 添加 |
| | | * @param form |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result add(VideoForm form) { |
| | | Video entity = VideoForm.getEntityByForm(form, null); |
| | | baseMapper.insert(entity); |
| | | return Result.ok("添加成功"); |
| | | } |
| | | |
| | | /** |
| | | * 修改 |
| | | * @param form |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result update(VideoForm form) { |
| | | Video entity = baseMapper.selectById(form.getId()); |
| | | |
| | | // 为空抛IllegalArgumentException,做全局异常处理 |
| | | Assert.notNull(entity, "记录不存在"); |
| | | BeanUtils.copyProperties(form, entity); |
| | | baseMapper.updateById(entity); |
| | | return Result.ok("修改成功"); |
| | | } |
| | | |
| | | /** |
| | | * 批量删除 |
| | | * @param ids |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result remove(List<String> ids) { |
| | | baseMapper.deleteBatchIds(ids); |
| | | return Result.ok("删除成功"); |
| | | } |
| | | |
| | | /** |
| | | * id删除 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result removeById(String id) { |
| | | baseMapper.deleteById(id); |
| | | return Result.ok("删除成功"); |
| | | } |
| | | |
| | | /** |
| | | * 分页查询 |
| | | * @param query |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result page(VideoQuery query) { |
| | | IPage<VideoVO> page = PageUtil.getPage(query, VideoVO.class); |
| | | baseMapper.getPage(page, query); |
| | | return Result.ok().data(page.getRecords()).total(page.getTotal()); |
| | | } |
| | | |
| | | /** |
| | | * 根据id查找 |
| | | * @param id |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result detail(Integer id) { |
| | | VideoVO vo = baseMapper.getById(id); |
| | | Assert.notNull(vo, "记录不存在"); |
| | | return Result.ok().data(vo); |
| | | } |
| | | |
| | | /** |
| | | * 列表 |
| | | * @return |
| | | */ |
| | | @Override |
| | | public Result all() { |
| | | List<Video> entities = baseMapper.selectList(null); |
| | | List<VideoVO> vos = entities.stream() |
| | | .map(entity -> VideoVO.getVoByEntity(entity, null)) |
| | | .collect(Collectors.toList()); |
| | | return Result.ok().data(vos); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Result publish(VideoForm form) { |
| | | // 1.保存视频 |
| | | Video video = VideoForm.getEntityByForm(form, null); |
| | | video.setAuthorId(UserContext.getCurrentUserId()); |
| | | video.setStatus(VideoStatusEnum.AUDITING.getValue()); |
| | | baseMapper.insert(video); |
| | | // 2.处理标签 |
| | | List<VideoTagRef> videoTagRefs = form.getTags().stream().map(tag -> { |
| | | VideoTagRef videoTagRef = new VideoTagRef(); |
| | | videoTagRef.setVideoId(video.getId()); |
| | | if (StringUtils.isBlank(tag.getId())) { |
| | | VideoTag videoTag = new LambdaQueryChainWrapper<>(videoTagService.getBaseMapper()) |
| | | .eq(VideoTag::getTagName, tag.getTagName()) |
| | | .one(); |
| | | if (Objects.nonNull(videoTag)) { |
| | | videoTagRef.setVideoTagId(videoTag.getId()); |
| | | } else { |
| | | videoTag = new VideoTag(); |
| | | videoTag.setTagName(tag.getTagName()); |
| | | videoTag.setCreateType(TagCreateTypeEnum.USER.getValue()); |
| | | videoTagService.save(videoTag); |
| | | videoTagRef.setVideoTagId(videoTag.getId()); |
| | | } |
| | | } else { |
| | | videoTagRef.setVideoTagId(tag.getId()); |
| | | } |
| | | return videoTagRef; |
| | | }).collect(Collectors.toList()); |
| | | videoTagRefService.saveBatch(videoTagRefs); |
| | | // 3.保存视频文件信息 |
| | | lmkFileService.addByForm(form.getFileInfo()); |
| | | return Result.ok("发布成功,视频审核中~"); |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.modules.lmk.service.impl; |
| | | |
| | | import cn.lili.modules.lmk.domain.entity.VideoTagRef; |
| | | import cn.lili.modules.lmk.mapper.VideoTagRefMapper; |
| | | import cn.lili.modules.lmk.service.VideoTagRefService; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.stereotype.Service; |
| | | |
| | | /** |
| | | * 视频标签中间表 服务实现类 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-19 |
| | | */ |
| | | @Service |
| | | @RequiredArgsConstructor |
| | | public class VideoTagRefServiceImpl extends ServiceImpl<VideoTagRefMapper, VideoTagRef> implements VideoTagRefService { |
| | | |
| | | private final VideoTagRefMapper videoTagRefMapper; |
| | | |
| | | |
| | | } |
| | |
| | | package cn.lili.modules.lmk.service.impl; |
| | | |
| | | import cn.lili.modules.lmk.domain.query.WxVideoTagQuery; |
| | | import cn.lili.modules.lmk.enums.general.TagCreateTypeEnum; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | | import cn.lili.modules.lmk.domain.entity.VideoTag; |
| | | import cn.lili.modules.lmk.mapper.VideoTagMapper; |
| | | import cn.lili.modules.lmk.service.VideoTagService; |
| | | import cn.lili.base.Result; |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | | import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; |
| | | import cn.lili.modules.lmk.domain.form.VideoTagForm; |
| | | import cn.lili.modules.lmk.domain.vo.VideoTagVO; |
| | |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.util.Assert; |
| | | |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.stream.Collectors; |
| | | |
| | |
| | | .collect(Collectors.toList()); |
| | | return Result.ok().data(vos); |
| | | } |
| | | |
| | | |
| | | @Override |
| | | public Result recommend(WxVideoTagQuery query) { |
| | | List<VideoTagVO> tags = new ArrayList<>(3); |
| | | switch (query.getSearchType()) { |
| | | case "HOT": |
| | | // TODO 热门标签通过定时任务统计表lmk_video_tag_ref数量到lmk_video_tag中 |
| | | tags = new LambdaQueryChainWrapper<>(baseMapper) |
| | | .orderByDesc(VideoTag::getUseNum) |
| | | .last("limit 3") |
| | | .list().stream().map(entity -> { |
| | | return VideoTagVO.getVoByEntity(entity, null); |
| | | }).collect(Collectors.toList()); |
| | | case "SEARCH": |
| | | tags = new LambdaQueryChainWrapper<>(baseMapper) |
| | | .orderByDesc(VideoTag::getUseNum) |
| | | .like(VideoTag::getTagName, query.getTagName()) |
| | | .last("limit 3") |
| | | .list().stream().map(entity -> { |
| | | return VideoTagVO.getVoByEntity(entity, null); |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | return Result.ok().data(tags); |
| | | } |
| | | } |
New file |
| | |
| | | package cn.lili.utils; |
| | | |
| | | import cn.lili.cos.COSConfigProperty; |
| | | import cn.lili.cos.CosSTS; |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import com.qcloud.cos.COSClient; |
| | | import com.qcloud.cos.ClientConfig; |
| | | import com.qcloud.cos.auth.BasicSessionCredentials; |
| | | import com.qcloud.cos.exception.CosClientException; |
| | | import com.qcloud.cos.exception.CosServiceException; |
| | | import com.qcloud.cos.http.HttpMethodName; |
| | | import com.qcloud.cos.model.*; |
| | | import com.qcloud.cos.region.Region; |
| | | import com.tencent.cloud.CosStsClient; |
| | | import com.tencent.cloud.Policy; |
| | | import com.tencent.cloud.Response; |
| | | import com.tencent.cloud.Statement; |
| | | import com.tencent.cloud.cos.util.Jackson; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.apache.commons.collections4.CollectionUtils; |
| | | import org.springframework.stereotype.Component; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.*; |
| | | import java.net.URL; |
| | | import java.net.URLEncoder; |
| | | import java.util.*; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * @author:xp |
| | | * @date:2025/5/16 16:31 |
| | | */ |
| | | @Component |
| | | @RequiredArgsConstructor |
| | | public class COSUtil { |
| | | |
| | | private final COSConfigProperty cosConfigProperty; |
| | | |
| | | /** |
| | | * 获取sts临时访问凭证 |
| | | * |
| | | * @return |
| | | */ |
| | | public CosSTS getSTS() { |
| | | TreeMap<String, Object> config = new TreeMap<String, Object>(); |
| | | try { |
| | | config.put("secretId", cosConfigProperty.getSecretId()); |
| | | config.put("secretKey", cosConfigProperty.getSecretKey()); |
| | | |
| | | // 初始化 policy |
| | | Policy policy = new Policy(); |
| | | |
| | | // 设置域名: |
| | | // 如果您使用了腾讯云 cvm,可以设置内部域名 |
| | | //config.put("host", "sts.internal.tencentcloudapi.com"); |
| | | |
| | | // 临时密钥有效时长,单位是秒,默认 1800 秒,目前主账号最长 2 小时(即 7200 秒),子账号最长 36 小时(即 129600)秒 |
| | | config.put("durationSeconds", cosConfigProperty.getDurationSeconds()); |
| | | // 换成您的 bucket |
| | | config.put("bucket", cosConfigProperty.getBucket()); |
| | | // 换成 bucket 所在地区 |
| | | config.put("region", cosConfigProperty.getRegion()); |
| | | |
| | | // 开始构建一条 statement |
| | | Statement statement = new Statement(); |
| | | // 声明设置的结果是允许操作 |
| | | statement.setEffect("allow"); |
| | | /** |
| | | * 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。 |
| | | * 权限列表请参见 https://cloud.tencent.com/document/product/436/31923 |
| | | * 规则为 {project}:{interfaceName} |
| | | * project : 产品缩写 cos相关授权为值为cos,数据万象(数据处理)相关授权值为ci |
| | | * 授权所有接口用*表示,例如 cos:*,ci:* |
| | | * 添加一批操作权限 : |
| | | */ |
| | | statement.addActions(cosConfigProperty.getActions()); |
| | | |
| | | /** |
| | | * 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径 |
| | | * 资源表达式规则分对象存储(cos)和数据万象(ci)两种 |
| | | * 数据处理、审核相关接口需要授予ci资源权限 |
| | | * cos : qcs::cos:{region}:uid/{appid}:{bucket}/{path} |
| | | * ci : qcs::ci:{region}:uid/{appid}:bucket/{bucket}/{path} |
| | | * 列举几种典型的{path}授权场景: |
| | | * 1、允许访问所有对象:"*" |
| | | * 2、允许访问指定的对象:"a/a1.txt", "b/b1.txt" |
| | | * 3、允许访问指定前缀的对象:"a*", "a/*", "b/*" |
| | | * 如果填写了“*”,将允许用户访问所有资源;除非业务需要,否则请按照最小权限原则授予用户相应的访问权限范围。 |
| | | * |
| | | * 示例:授权examplebucket-1250000000 bucket目录下的所有资源给cos和ci 授权两条Resource |
| | | */ |
| | | statement.addResources(cosConfigProperty.getResources()); |
| | | |
| | | // 把一条 statement 添加到 policy |
| | | // 可以添加多条 |
| | | policy.addStatement(statement); |
| | | // 将 Policy 示例转化成 String,可以使用任何 json 转化方式,这里是本 SDK 自带的推荐方式 |
| | | config.put("policy", Jackson.toJsonPrettyString(policy)); |
| | | |
| | | Response response = CosStsClient.getCredential(config); |
| | | System.out.println(response.credentials.tmpSecretId); |
| | | System.out.println(response.credentials.tmpSecretKey); |
| | | System.out.println(response.credentials.sessionToken); |
| | | |
| | | CosSTS cosSTS = new CosSTS(); |
| | | cosSTS.setTmpSecretId(response.credentials.tmpSecretId); |
| | | cosSTS.setTmpSecretKey(response.credentials.tmpSecretKey); |
| | | cosSTS.setSessionToken(response.credentials.sessionToken); |
| | | Date now = new Date(); |
| | | cosSTS.setStsStartTime(now.getTime() / 1000); |
| | | // 预留30s的请求时间,防止给小程序的结束时间超过实际的结束时间 |
| | | cosSTS.setStsEndTime(cosSTS.getStsStartTime() + cosConfigProperty.getDurationSeconds() - 30); |
| | | cosSTS.setBucket(cosConfigProperty.getBucket()); |
| | | cosSTS.setRegion(cosConfigProperty.getRegion()); |
| | | return cosSTS; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new IllegalArgumentException("get sts error"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 初始化cos客户端 |
| | | * |
| | | * @return COSClient cos客户端 |
| | | */ |
| | | public COSClient initClient() { |
| | | CosSTS sts = this.getSTS(); |
| | | BasicSessionCredentials cred = new BasicSessionCredentials(sts.getTmpSecretId(), sts.getTmpSecretKey(), sts.getSessionToken()); |
| | | // 2 设置 bucket 的地域 |
| | | // clientConfig 中包含了设置 region, https(默认 http), 超时, 代理等 set 方法, 使用可参见源码或者常见问题 Java SDK 部分 |
| | | Region region = new Region(cosConfigProperty.getRegion()); //COS_REGION 参数:配置成存储桶 bucket 的实际地域,例如 ap-beijing,更多 COS 地域的简称请参见 https://cloud.tencent.com/document/product/436/6224 |
| | | ClientConfig clientConfig = new ClientConfig(region); |
| | | // 3 生成 cos 客户端 |
| | | COSClient cosClient = new COSClient(cred, clientConfig); |
| | | return cosClient; |
| | | } |
| | | |
| | | /** |
| | | * 最简单的上传文件 |
| | | * |
| | | * @param fileInput 文件 |
| | | * @param fileInfo 文件信息 |
| | | * @return fileKey 文件路径,或者叫唯一标识 |
| | | */ |
| | | public void upload(InputStream fileInput, LmkFile fileInfo) { |
| | | COSClient cosClient = this.initClient(); |
| | | ObjectMetadata objectMetadata = new ObjectMetadata(); |
| | | objectMetadata.setContentType(fileInfo.getFileType()); |
| | | objectMetadata.setContentLength(fileInfo.getFileSize()); |
| | | |
| | | // objectMetadata.setContentDisposition("attachment;filename=" + URLEncoder.encode(fileInfo.getOriginalFilename(), "UTF-8")); |
| | | // 指定文件上传到 COS 上的路径,即对象键。例如对象键为 folder/picture.jpg,则表示将文件 picture.jpg 上传到 folder 路径下 |
| | | PutObjectRequest putObjectRequest = new PutObjectRequest(cosConfigProperty.getBucket(), fileInfo.getFileKey(), fileInput, objectMetadata); |
| | | PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest); |
| | | System.out.println(putObjectResult); |
| | | cosClient.shutdown(); |
| | | } |
| | | |
| | | /** |
| | | * 下载文件 |
| | | * |
| | | * @param fileKey 文件路径,或者叫唯一标识 |
| | | * @param response |
| | | */ |
| | | public void download(String fileKey, HttpServletResponse response) { |
| | | COSClient cosClient = this.initClient(); |
| | | GetObjectRequest getObjectRequest = new GetObjectRequest(cosConfigProperty.getBucket(), fileKey); |
| | | |
| | | try { |
| | | // 获取COS对象 |
| | | COSObject cosObject = cosClient.getObject(getObjectRequest); |
| | | |
| | | // 获取对象元数据 |
| | | ObjectMetadata metadata = cosObject.getObjectMetadata(); |
| | | String contentType = metadata.getContentType(); |
| | | long contentLength = metadata.getContentLength(); |
| | | String filename = fileKey.substring(fileKey.lastIndexOf('/') + 1); |
| | | |
| | | // 设置响应头 |
| | | response.setContentType(contentType != null ? contentType : "application/octet-stream"); |
| | | response.setContentLengthLong(contentLength); |
| | | response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(filename, "UTF-8") + "\""); |
| | | |
| | | // 获取输入流和输出流 |
| | | try (InputStream cosObjectInput = cosObject.getObjectContent(); |
| | | OutputStream responseOutputStream = response.getOutputStream()) { |
| | | |
| | | // 使用缓冲区传输数据 |
| | | byte[] buffer = new byte[4096]; |
| | | int bytesRead; |
| | | while ((bytesRead = cosObjectInput.read(buffer)) != -1) { |
| | | responseOutputStream.write(buffer, 0, bytesRead); |
| | | } |
| | | responseOutputStream.flush(); |
| | | } |
| | | } catch (CosServiceException e) { |
| | | // COS服务异常 |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("存储服务异常"); |
| | | } catch (CosClientException e) { |
| | | // COS客户端异常 |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("存储服务客户端异常"); |
| | | } catch (IOException e) { |
| | | // IO异常 |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("文件读取异常"); |
| | | } finally { |
| | | // 确保COS客户端关闭 |
| | | if (cosClient != null) { |
| | | cosClient.shutdown(); |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取在线访问文件地址 |
| | | * |
| | | * @param fileKey |
| | | * @return |
| | | */ |
| | | public String getPreviewUrl(String fileKey) { |
| | | COSClient cosClient = this.initClient(); |
| | | // 设置签名过期时间(可选), 若未进行设置则默认使用 ClientConfig 中的签名过期时间(1小时) |
| | | // 这里设置签名在半个小时后过期 |
| | | Date expirationDate = new Date(System.currentTimeMillis() + cosConfigProperty.getUrlExpireMinute() * 60 * 1000); |
| | | // 填写本次请求的参数,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的参数 |
| | | Map<String, String> params = new HashMap<String, String>(); |
| | | // 填写本次请求的头部,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的头部 |
| | | Map<String, String> headers = new HashMap<String, String>(); |
| | | // 请求的 HTTP 方法,上传请求用 PUT,下载请求用 GET,删除请求用 DELETE |
| | | HttpMethodName method = HttpMethodName.GET; |
| | | URL url = cosClient.generatePresignedUrl(cosConfigProperty.getBucket(), fileKey, expirationDate, method, headers, params); |
| | | System.out.println(url.toString()); |
| | | // 确认本进程不再使用 cosClient 实例之后,关闭即可 |
| | | cosClient.shutdown(); |
| | | return url.toString(); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 删除单个文件 |
| | | * |
| | | * @param fileKey |
| | | */ |
| | | public void deleteFile(String fileKey) { |
| | | COSClient cosClient = this.initClient(); |
| | | try { |
| | | cosClient.deleteObject(cosConfigProperty.getBucket(), fileKey); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("文件删除失败"); |
| | | } finally { |
| | | cosClient.shutdown(); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 删除多个文件 |
| | | * |
| | | * @param fileKeys |
| | | */ |
| | | public void deleteFiles(List<String> fileKeys) { |
| | | if (CollectionUtils.isEmpty(fileKeys)) { |
| | | return; |
| | | } |
| | | List<DeleteObjectsRequest.KeyVersion> keys = fileKeys.stream().map(key -> new DeleteObjectsRequest.KeyVersion(key)).collect(Collectors.toList()); |
| | | COSClient cosClient = this.initClient(); |
| | | try { |
| | | DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(cosConfigProperty.getBucket()); |
| | | deleteObjectsRequest.setKeys(keys); |
| | | cosClient.deleteObjects(deleteObjectsRequest); |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("文件删除失败"); |
| | | } finally { |
| | | cosClient.shutdown(); |
| | | } |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | package cn.lili.utils; |
| | | |
| | | import cn.lili.common.exception.FileFormatNotSupport; |
| | | import cn.lili.modules.lmk.domain.entity.LmkFile; |
| | | import cn.lili.modules.lmk.enums.general.FileTypeEnum; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.Random; |
| | | |
| | | /** |
| | | * @author 29443 |
| | | * @version 1.0 |
| | | * @date 2022/4/25 |
| | | */ |
| | | public class FileUtil { |
| | | |
| | | /** |
| | | * 获取文件后缀 |
| | | * |
| | | * @param fileName |
| | | * @return |
| | | */ |
| | | public static String getSuffix(String fileName) { |
| | | String suffix = fileName.substring(fileName.lastIndexOf('.') + 1); |
| | | return suffix; |
| | | } |
| | | |
| | | /** |
| | | * 获取该文件上传到oss哪个目录 |
| | | * |
| | | * @param suffix 文件后缀 |
| | | * @return |
| | | */ |
| | | public static String getFileType(String suffix) { |
| | | String fileType = ""; |
| | | for (FileTypeEnum type : FileTypeEnum.values()) { |
| | | if (type.getSuffixs().contains(suffix)) { |
| | | fileType = type.getType(); |
| | | return fileType; |
| | | } |
| | | } |
| | | if (StringUtils.isBlank(fileType)) { |
| | | throw new FileFormatNotSupport("文件格式" + suffix + "不支持", 500); |
| | | } |
| | | return fileType; |
| | | } |
| | | |
| | | /** |
| | | * 获取文件的信息,调用此方法默认普通上传 |
| | | * |
| | | * @param file |
| | | * @return |
| | | */ |
| | | public static LmkFile getFileInfo(MultipartFile file) { |
| | | String originalFilename = file.getOriginalFilename(); |
| | | String random = generateFileKey(); |
| | | String suffix = getSuffix(originalFilename); |
| | | String fileType = getFileType(suffix); |
| | | String fileKey = String.format("%s/%s.%s", fileType, random, suffix); |
| | | |
| | | LmkFile fileInfo = new LmkFile(); |
| | | fileInfo.setFileKey(fileKey); |
| | | fileInfo.setOriginalFileName(originalFilename); |
| | | fileInfo.setFileType(file.getContentType()); |
| | | fileInfo.setFileSize(file.getSize()); |
| | | |
| | | return fileInfo; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 获取fileKey |
| | | * |
| | | * @return |
| | | */ |
| | | public static String generateFileKey() { |
| | | SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss"); |
| | | String no = format.format(new Date()); |
| | | Random random = new Random(); |
| | | for (int i = 0; i < 5; i++) { |
| | | no += random.nextInt(10); |
| | | } |
| | | return no; |
| | | } |
| | | |
| | | } |
New file |
| | |
| | | <?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="cn.lili.modules.lmk.mapper.LmkFileMapper"> |
| | | |
| | | <!-- 通用查询映射结果 --> |
| | | <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.entity.LmkFile"> |
| | | <id column="id" property="id"/> |
| | | <result column="file_key" property="fileKey" /> |
| | | <result column="file_type" property="fileType" /> |
| | | <result column="file_size" property="fileSize" /> |
| | | <result column="original_filename" property="originalFileName" /> |
| | | </resultMap> |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | <select id="getByFileKey" resultMap="BaseResultMap"> |
| | | SELECT |
| | | LF.file_key, |
| | | LF.file_type, |
| | | LF.file_size, |
| | | LF.original_filename, |
| | | LF.deleted_flag, |
| | | LF.id |
| | | FROM |
| | | lmk_file LF |
| | | WHERE |
| | | LF.file_key = #{flieKey} AND LF.delete_flag = 0 |
| | | </select> |
| | | |
| | | |
| | | </mapper> |
New file |
| | |
| | | <?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="cn.lili.modules.lmk.mapper.VideoMapper"> |
| | | |
| | | <!-- 通用查询映射结果 --> |
| | | <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.VideoVO"> |
| | | <id column="id" property="id"/> |
| | | <result column="author_id" property="authorId" /> |
| | | <result column="cover_url" property="coverUrl" /> |
| | | <result column="video_file_key" property="videoFileKey" /> |
| | | <result column="video_fit" property="videoFit" /> |
| | | <result column="title" property="title" /> |
| | | <result column="goods_id" property="goodsId" /> |
| | | <result column="goods_view_num" property="goodsViewNum" /> |
| | | <result column="goods_order_num" property="goodsOrderNum" /> |
| | | <result column="recommend" property="recommend" /> |
| | | <result column="status" property="status" /> |
| | | <result column="play_num" property="playNum" /> |
| | | <result column="collect_num" property="collectNum" /> |
| | | <result column="comment_num" property="commentNum" /> |
| | | <result column="weight" property="weight" /> |
| | | <result column="audit_pass_time" property="auditPassTime" /> |
| | | </resultMap> |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | <select id="getById" resultMap="BaseResultMap"> |
| | | SELECT |
| | | LV.author_id, |
| | | LV.cover_url, |
| | | LV.video_fit, |
| | | LV.video_file_key, |
| | | LV.title, |
| | | LV.goods_id, |
| | | LV.goods_view_num, |
| | | LV.goods_order_num, |
| | | LV.recommend, |
| | | LV.status, |
| | | LV.play_num, |
| | | LV.collect_num, |
| | | LV.comment_num, |
| | | LV.weight, |
| | | LV.audit_pass_time, |
| | | LV.id |
| | | FROM |
| | | lmk_video LV |
| | | WHERE |
| | | LV.id = #{id} AND LV.delete_flag = 0 |
| | | </select> |
| | | |
| | | |
| | | <select id="getPage" resultMap="BaseResultMap"> |
| | | SELECT |
| | | LV.author_id, |
| | | LV.cover_url, |
| | | LV.video_fit, |
| | | LV.video_file_key, |
| | | LV.title, |
| | | LV.goods_id, |
| | | LV.goods_view_num, |
| | | LV.goods_order_num, |
| | | LV.recommend, |
| | | LV.status, |
| | | LV.play_num, |
| | | LV.collect_num, |
| | | LV.comment_num, |
| | | LV.weight, |
| | | LV.audit_pass_time, |
| | | LV.id |
| | | FROM |
| | | lmk_video LV |
| | | WHERE |
| | | LV.delete_flag = 0 |
| | | </select> |
| | | |
| | | </mapper> |
| | |
| | | <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.vo.VideoTagVO"> |
| | | <id column="id" property="id"/> |
| | | <result column="tag_name" property="tagName" /> |
| | | <result column="use_num" property="useNum" /> |
| | | <result column="create_type" property="createType"/> |
| | | <result column="update_time" property="updateTime" /> |
| | | </resultMap> |
| | |
| | | <select id="getById" resultMap="BaseResultMap"> |
| | | SELECT |
| | | LVT.tag_name, |
| | | LVT.use_num, |
| | | LVT.create_type, |
| | | LVT.update_time, |
| | | LVT.id |
| | |
| | | <select id="getPage" resultMap="BaseResultMap"> |
| | | SELECT |
| | | LVT.tag_name, |
| | | LVT.use_num, |
| | | LVT.create_type, |
| | | LVT.update_time, |
| | | LVT.id |
New file |
| | |
| | | <?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="cn.lili.modules.lmk.mapper.VideoTagRefMapper"> |
| | | |
| | | <!-- 通用查询映射结果 --> |
| | | <resultMap id="BaseResultMap" type="cn.lili.modules.lmk.domain.entity.VideoTagRef"> |
| | | <id column="id" property="id"/> |
| | | <result column="video_id" property="videoId" /> |
| | | <result column="video_tag_id" property="videoTagId" /> |
| | | </resultMap> |
| | | |
| | | |
| | | |
| | | |
| | | </mapper> |
New file |
| | |
| | | package cn.lili.controller.lmk; |
| | | |
| | | import cn.lili.group.Update; |
| | | import cn.lili.group.Add; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import org.springframework.security.access.prepost.PreAuthorize; |
| | | import lombok.RequiredArgsConstructor; |
| | | import java.util.List; |
| | | import org.springframework.validation.annotation.Validated; |
| | | import javax.validation.constraints.NotEmpty; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import cn.lili.modules.lmk.service.VideoService; |
| | | import cn.lili.base.Result; |
| | | import cn.lili.modules.lmk.domain.form.VideoForm; |
| | | import cn.lili.modules.lmk.domain.query.VideoQuery; |
| | | import lombok.RequiredArgsConstructor; |
| | | import org.springframework.web.bind.annotation.*; |
| | | |
| | | /** |
| | | * 视频内容 前端控制器 |
| | | * |
| | | * @author xp |
| | | * @since 2025-05-16 |
| | | */ |
| | | @Validated |
| | | @RequiredArgsConstructor |
| | | @Api(value = "视频内容", tags = "视频内容管理") |
| | | @RestController |
| | | @RequestMapping("/manager/lmk/video") |
| | | public class VideoController { |
| | | |
| | | private final VideoService videoService; |
| | | |
| | | @PostMapping |
| | | @ApiOperation(value = "添加", notes = "添加") |
| | | public Result add(@RequestBody @Validated(Add.class) VideoForm form) { |
| | | return videoService.add(form); |
| | | } |
| | | |
| | | @PutMapping |
| | | @ApiOperation(value = "修改", notes = "修改") |
| | | public Result update(@RequestBody @Validated(Update.class) VideoForm form) { |
| | | return videoService.update(form); |
| | | } |
| | | |
| | | @DeleteMapping("/{id}") |
| | | @ApiOperation(value = "ID删除", notes = "ID删除") |
| | | public Result removeById(@PathVariable("id") String id) { |
| | | return videoService.removeById(id); |
| | | } |
| | | |
| | | @DeleteMapping("/batch") |
| | | @ApiOperation(value = "批量删除", notes = "批量删除") |
| | | public Result remove(@RequestBody @NotEmpty(message = "请选择数据") List<String> ids) { |
| | | return videoService.remove(ids); |
| | | } |
| | | |
| | | @GetMapping("/page") |
| | | @ApiOperation(value = "分页", notes = "分页") |
| | | public Result page(VideoQuery query) { |
| | | return videoService.page(query); |
| | | } |
| | | |
| | | @GetMapping("/{id}") |
| | | @ApiOperation(value = "详情", notes = "详情") |
| | | public Result detail(@PathVariable("id") Integer id) { |
| | | return videoService.detail(id); |
| | | } |
| | | |
| | | @GetMapping("/list") |
| | | @ApiOperation(value = "列表", notes = "列表") |
| | | public Result list() { |
| | | return videoService.all(); |
| | | } |
| | | } |
| | |
| | | <cos.version>5.6.97</cos.version> |
| | | <tencentcloud.version>3.1.693</tencentcloud.version> |
| | | <kuaidi100-api.version>1.0.11</kuaidi100-api.version> |
| | | <tx-cos.version>5.6.227</tx-cos.version> |
| | | </properties> |
| | | |
| | | <modules> |
| | |
| | | </snapshots> |
| | | </repository> |
| | | </repositories> |
| | | </project> |
| | | </project> |