Merge branch 'master' into feature/down_update_add_expire_seconds
# Conflicts: # oss-client/src/main/java/cn/axzo/oss/client/controller/ServerFileController.java # oss-client/src/main/java/cn/axzo/oss/client/controller/WebFileController.java # oss-http-api/src/main/java/cn/axzo/oss/http/api/ServerFileServiceApi.java # oss-integration/src/main/java/cn/axzo/oss/integration/s3/HuaWeiCloudService.java # oss-integration/src/main/java/cn/axzo/oss/integration/s3/impl/HuaWeiCloudServiceImpl.java # oss-manager-api/src/main/java/cn/axzo/oss/manager/api/FileManager.java # oss-manager/src/main/java/cn/axzo/oss/manager/impl/FileManagerImpl.java # oss-service-api/src/main/java/cn/axzo/oss/service/api/FileService.java # oss-service/src/main/java/cn/axzo/oss/service/impl/FileServiceImpl.java
This commit is contained in:
commit
19e232fccb
@ -11,7 +11,7 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
* @since 2024/1/16 15:11
|
||||
**/
|
||||
@Slf4j
|
||||
@MapperScan(basePackages = {"cn.axzo.oss.dal.mapper"})
|
||||
@MapperScan(basePackages = {"cn.axzo.oss.dal.mapper", "cn.axzo.oss.client.icon.mapper"})
|
||||
@EnableFeignClients(basePackages = {"cn.axzo.log.platform.client"})
|
||||
@SpringBootApplication(scanBasePackages = {"cn.axzo.oss"})
|
||||
public class Bootstrap {
|
||||
|
||||
@ -5,10 +5,18 @@ import cn.axzo.framework.auth.domain.ContextInfo;
|
||||
import cn.axzo.oss.common.utils.BeanConvertUtil;
|
||||
import cn.axzo.oss.http.api.ServerFileServiceApi;
|
||||
import cn.axzo.oss.http.model.*;
|
||||
import cn.axzo.oss.manager.api.dto.request.FindFileKeyDto;
|
||||
import cn.axzo.oss.manager.api.dto.request.FindFileUrlDto;
|
||||
import cn.axzo.oss.manager.api.dto.request.ServerFileDeleteDto;
|
||||
import cn.axzo.oss.manager.api.dto.request.ServerFileDownloadDto;
|
||||
import cn.axzo.oss.manager.api.dto.request.ServerFileUploadDto;
|
||||
import cn.axzo.oss.manager.api.dto.response.ServerFileDownloadResponse;
|
||||
import cn.axzo.oss.manager.api.dto.request.*;
|
||||
import cn.axzo.oss.service.api.FileService;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import feign.Response;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -17,6 +25,8 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.validation.Valid;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
||||
@ -6,15 +6,20 @@ import cn.axzo.framework.auth.domain.ContextInfo;
|
||||
import cn.axzo.framework.auth.domain.ContextInfoHolder;
|
||||
import cn.axzo.oss.client.vo.*;
|
||||
import cn.axzo.oss.common.enums.ChannelTypeEnum;
|
||||
import cn.axzo.oss.common.enums.FileDownloadTypeEnum;
|
||||
import cn.axzo.oss.common.enums.FileUploadTypeEnum;
|
||||
import cn.axzo.oss.common.enums.StorageUnitEnum;
|
||||
import cn.axzo.oss.common.exception.BizException;
|
||||
import cn.axzo.oss.common.utils.BeanConvertUtil;
|
||||
import cn.axzo.oss.http.model.TemporaryUrlAccessRes;
|
||||
import cn.axzo.oss.http.model.WebFileUploadVo;
|
||||
import cn.axzo.oss.manager.api.dto.request.*;
|
||||
import cn.axzo.oss.manager.api.dto.response.*;
|
||||
import cn.axzo.oss.service.api.FileService;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@ -38,6 +43,7 @@ import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
**/
|
||||
@RestController
|
||||
@RequestMapping("/webApi")
|
||||
@Slf4j
|
||||
public class WebFileController {
|
||||
|
||||
private static int FILE_NAME_MAX_LENGTH = 128;
|
||||
@ -265,6 +271,90 @@ public class WebFileController {
|
||||
return CommonResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* obs:流式下载
|
||||
*
|
||||
* @param dto ServerFileDownloadDto
|
||||
* @param response HttpServletResponse
|
||||
*/
|
||||
@SneakyThrows
|
||||
@GetMapping("/v1/obs/getObject")
|
||||
@CrossOrigin
|
||||
public void getObject(@Valid ServerFileDownloadDto dto, HttpServletResponse response) {
|
||||
ServerFileDownloadResponse result = fileService.getObject(dto, FileDownloadTypeEnum.STREAM_DOWNLOAD.getCode());
|
||||
try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = result.getFileStream()) {
|
||||
response.setContentType("image/jpg");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.addHeader("Content-Disposition", "attachment;filename="
|
||||
+ result.getFileName() + "." + result.getFileFormat());
|
||||
IOUtils.copy(inputStream, outputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* obs:断点续传下载
|
||||
*
|
||||
* @param dto ServerFileDownloadDto
|
||||
* @param response HttpServletResponse
|
||||
*/
|
||||
@SneakyThrows
|
||||
@GetMapping("/v1/obs/downloadFile")
|
||||
@CrossOrigin
|
||||
public void downloadFile(@Valid ServerFileDownloadDto dto, HttpServletResponse response) {
|
||||
ServerFileDownloadResponse result = fileService.getObject(dto, FileDownloadTypeEnum.CHECK_POINT_DOWNLOAD.getCode());
|
||||
try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = result.getFileStream()) {
|
||||
response.setContentType("image/jpg");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.addHeader("Content-Disposition", "attachment;filename="
|
||||
+ result.getFileName() + "." + result.getFileFormat());
|
||||
IOUtils.copy(inputStream, outputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程下载接口
|
||||
*
|
||||
* @param fileUuId 文件uuid
|
||||
* @param response HttpServletResponse
|
||||
*/
|
||||
@GetMapping("/v1/obs/downloadFileFromObs")
|
||||
public void downloadFileFromObs(@RequestParam("fileUuid") String fileUuId, HttpServletResponse response) {
|
||||
ServerFileDownloadDto dto = new ServerFileDownloadDto();
|
||||
dto.setFileKey(fileUuId);
|
||||
ServerFileDownloadResponse result = fileService.getObject(dto, FileDownloadTypeEnum.STREAM_DOWNLOAD.getCode());
|
||||
|
||||
try (OutputStream outputStream = response.getOutputStream(); InputStream inputStream = result.getFileStream()) {
|
||||
response.setHeader("content-type","application/octet-stream");
|
||||
response.setContentType("application/octet-stream");
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.addHeader("Content-Disposition", "attachment;filename=" + result.getFileName() + "." + result.getFileFormat());
|
||||
IOUtils.copy(inputStream, outputStream);
|
||||
log.info("response设置文件流成功");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过临时url访问OBS
|
||||
*
|
||||
* @param fileUuId 文件uuid
|
||||
* @return TemporaryUrlAccessRes
|
||||
*/
|
||||
@GetMapping("/v1/obs/temporaryUrlAccess")
|
||||
public CommonResponse<TemporaryUrlAccessRes> temporaryUrlAccess(@RequestParam("fileUuid") String fileUuId) {
|
||||
ServerFileDownloadDto dto = new ServerFileDownloadDto();
|
||||
dto.setFileKey(fileUuId);
|
||||
ServerFileDownloadResponse response = fileService.getObject(dto, FileDownloadTypeEnum.TEMPORARY_URL_ACCESS.getCode());
|
||||
TemporaryUrlAccessRes result = BeanConvertUtil.copyBean(response, TemporaryUrlAccessRes.class);
|
||||
log.info("下载结果, result = {}", JSONUtil.toJsonStr(result));
|
||||
return CommonResponse.success(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权给第三方下载-生成临时url
|
||||
*/
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.axzo.oss.client.icon.annotation;
|
||||
|
||||
import cn.axzo.oss.client.icon.validator.JsonStringValidator;
|
||||
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.Payload;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 自定义注解,用于判断是否是json字符串
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:49
|
||||
*/
|
||||
@Documented
|
||||
@Constraint(validatedBy = JsonStringValidator.class)
|
||||
@Target(ElementType.FIELD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface IsJsonString {
|
||||
|
||||
/**
|
||||
* 是否允许为空,默认允许
|
||||
*
|
||||
* @return true/false
|
||||
*/
|
||||
boolean allowBlank() default true;
|
||||
|
||||
String message() default "Invalid json string";
|
||||
|
||||
Class<?>[] groups() default {};
|
||||
|
||||
Class<? extends Payload>[] payload() default {};
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
package cn.axzo.oss.client.icon.controller;
|
||||
|
||||
import cn.axzo.oss.client.icon.service.IconDetailService;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailAddReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailListReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailUpdateReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailUpdateStatus;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconTypeListReq;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconDetailListResp;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.json.JSONNull;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 图标详情
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:25
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/icon")
|
||||
public class IconDetailController {
|
||||
|
||||
private final IconDetailService iconDetailService;
|
||||
|
||||
/**
|
||||
* 新增图标
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailAddReq}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public CommonResponse<Boolean> add(@RequestBody @Validated IconDetailAddReq req) {
|
||||
log.info("图标详情:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconDetailService.add(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据id查询图标详情
|
||||
*
|
||||
* @param id 图标id
|
||||
* @return 图标详情
|
||||
*/
|
||||
@GetMapping("/detailById")
|
||||
public CommonResponse<IconDetailListResp> detailById(@RequestParam("id") @NotNull(message = "图标id不能为空") Long id) {
|
||||
log.info("图标详情:id = {}", id);
|
||||
return CommonResponse.success(iconDetailService.detailById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新图标信息
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailUpdateReq}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public CommonResponse<Boolean> update(@RequestBody @Validated IconDetailUpdateReq req) {
|
||||
log.info("更新图标信息:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconDetailService.update(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新图标状态
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailUpdateStatus}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
@PostMapping("/updateStatus")
|
||||
public CommonResponse<Boolean> updateStatus(@RequestBody @Validated IconDetailUpdateStatus req) {
|
||||
log.info("更新图标状态:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconDetailService.updateStatus(req.getId(), req.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 图标列表
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailListReq}
|
||||
* @return 图标列表,按创建时间倒序 {@link IconDetailListResp}
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public CommonResponse<List<IconDetailListResp>> list(@RequestBody IconDetailListReq req) {
|
||||
log.info("图标列表:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconDetailService.list(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有图标文件格式
|
||||
*
|
||||
* @param req 图标信息 {@link IconTypeListReq}
|
||||
* @return 图标文件格式列表
|
||||
*/
|
||||
@PostMapping("/getAllTypes")
|
||||
public CommonResponse<List<String>> getAllTypes(@RequestBody IconTypeListReq req) {
|
||||
log.info("获取所有图标文件格式:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconDetailService.getAllTypes(req));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
package cn.axzo.oss.client.icon.controller;
|
||||
|
||||
import cn.axzo.oss.client.vo.FileInformationVo;
|
||||
import cn.axzo.oss.common.exception.BizException;
|
||||
import cn.axzo.oss.common.utils.BeanConvertUtil;
|
||||
import cn.axzo.oss.manager.api.dto.request.ServerFileUploadDto;
|
||||
import cn.axzo.oss.manager.api.dto.response.FileInformationResponse;
|
||||
import cn.axzo.oss.service.api.FileService;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import lombok.SneakyThrows;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static cn.axzo.oss.common.enums.CodeEnum.FILE_NAME_TOO_LONG;
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
|
||||
/**
|
||||
* 图标上传管理
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/26 10:01
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/icon")
|
||||
public class IconFileUploadController {
|
||||
|
||||
private static int FILE_NAME_MAX_LENGTH = 128;
|
||||
@Resource
|
||||
private FileService fileService;
|
||||
|
||||
/**
|
||||
* 图标上传管理
|
||||
*
|
||||
* @param appCode 应用码 (oss提供) 此处使用app
|
||||
* @param bizScene 业务场景 (在oss服务中配置) 此处使用app
|
||||
* @param serviceName 调用方服务名 此处使用web
|
||||
* @param file 文件
|
||||
* @return {@link FileInformationVo}
|
||||
*/
|
||||
@PostMapping(value = "/fileUpload", consumes = MULTIPART_FORM_DATA_VALUE)
|
||||
@CrossOrigin
|
||||
@SneakyThrows
|
||||
public CommonResponse<FileInformationVo> uploadV2(@Valid @RequestParam("appCode") String appCode,
|
||||
@Valid @RequestParam("bizScene") String bizScene,
|
||||
@Valid @RequestParam("serviceName") String serviceName,
|
||||
@Valid @RequestPart MultipartFile file) {
|
||||
|
||||
String filename = file.getOriginalFilename();
|
||||
BizException.error(filename.length() < FILE_NAME_MAX_LENGTH, FILE_NAME_TOO_LONG);
|
||||
ServerFileUploadDto fileUploadDto = ServerFileUploadDto.builder()
|
||||
.appCode(appCode)
|
||||
.bizScene(bizScene)
|
||||
.fileName(filename)
|
||||
.fileContent(file.getBytes())
|
||||
.build();
|
||||
FileInformationResponse response = fileService.uploadV2(serviceName, fileUploadDto, null);
|
||||
FileInformationVo result = BeanConvertUtil.copyBean(response, FileInformationVo.class);
|
||||
return CommonResponse.success(result);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,99 @@
|
||||
package cn.axzo.oss.client.icon.controller;
|
||||
|
||||
import cn.axzo.oss.client.icon.service.IconGroupService;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupAddReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupListReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupUpdateReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupUpdateStatusReq;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconDetailListResp;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconGroupListResp;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 图标组管理
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:27
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/icon/group")
|
||||
public class IconGroupController {
|
||||
|
||||
private final IconGroupService iconGroupService;
|
||||
|
||||
/**
|
||||
* 新增图标组
|
||||
*
|
||||
* @param req 图标组信息 {@link IconGroupAddReq}
|
||||
* @return 响应结果,成功返回true,失败返回false
|
||||
*/
|
||||
@PostMapping("/add")
|
||||
public CommonResponse<Boolean> add(@RequestBody @Validated IconGroupAddReq req) {
|
||||
log.info("新增图标组:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconGroupService.add(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询图标组详情
|
||||
*
|
||||
* @param id 图标组id
|
||||
* @return 图标组详情 {@link IconDetailListResp}
|
||||
*/
|
||||
@GetMapping("/detailById")
|
||||
public CommonResponse<IconGroupListResp> detailById(@RequestParam("id") @NotNull(message = "图标组id不能为空") Long id) {
|
||||
log.info("查询图标组详情:id = {}", id);
|
||||
return CommonResponse.success(iconGroupService.detailById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新图标组信息
|
||||
*
|
||||
* @param req 图标组信息 {@link IconGroupUpdateReq}
|
||||
* @return 响应结果,成功返回true,失败返回false
|
||||
*/
|
||||
@PostMapping("/update")
|
||||
public CommonResponse<Boolean> update(@RequestBody @Validated IconGroupUpdateReq req) {
|
||||
log.info("更新图标组信息:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconGroupService.update(req));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑图标组状态,同时将该组下所有图标状态更新
|
||||
*
|
||||
* @param req 图标组信息 {@link IconGroupUpdateStatusReq}
|
||||
* @return 响应结果,成功返回true,失败返回false
|
||||
*/
|
||||
@PostMapping("/updateStatus")
|
||||
public CommonResponse<Boolean> updateStatus(@RequestBody @Validated IconGroupUpdateStatusReq req) {
|
||||
log.info("更新图标组状态:id = {},status = {}", req.getId(), req.getStatus());
|
||||
return CommonResponse.success(iconGroupService.updateStatus(req.getId(), req.getStatus()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图标组列表
|
||||
*
|
||||
* @param req 图标组列表查询条件 {@link IconGroupListReq}
|
||||
* @return 图标组列表,按创建时间倒序 {@link IconGroupListResp}
|
||||
*/
|
||||
@PostMapping("/list")
|
||||
public CommonResponse<List<IconGroupListResp>> list(@RequestBody IconGroupListReq req) {
|
||||
log.info("获取图标组列表:req = {}", JSONUtil.toJsonStr(req));
|
||||
return CommonResponse.success(iconGroupService.list(req));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,108 @@
|
||||
package cn.axzo.oss.client.icon.entity;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 图标详情
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 15:58
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@TableName(value = "icon_detail", autoResultMap = true)
|
||||
public class IconDetail extends Model<IconDetail> {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图标组ID
|
||||
*/
|
||||
@TableField("group_id")
|
||||
private Long groupId;
|
||||
|
||||
/**
|
||||
* 图标名称
|
||||
*/
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 图标类型
|
||||
*/
|
||||
@TableField("type")
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 图标地址
|
||||
*/
|
||||
@TableField("url")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 图标存储大小
|
||||
*/
|
||||
@TableField("size")
|
||||
private String size;
|
||||
|
||||
/**
|
||||
* 尺寸-宽,单位mm
|
||||
*/
|
||||
@TableField("weight")
|
||||
private Integer weight;
|
||||
|
||||
/**
|
||||
* 尺寸-高,单位mm
|
||||
*/
|
||||
@TableField("height")
|
||||
private Integer height;
|
||||
|
||||
/**
|
||||
* 图标状态,0-未使用,1-使用中,2-已弃用,默认0
|
||||
*/
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
@TableField(value = "ext", typeHandler = FastjsonTypeHandler.class)
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* 是否删除(0:未删除;1:已删除)
|
||||
*/
|
||||
@TableField("is_delete")
|
||||
private Integer isDelete;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_at")
|
||||
private Date createAt;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_at")
|
||||
private Date updateAt;
|
||||
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
package cn.axzo.oss.client.icon.entity;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 图标组
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:11
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@TableName(value = "icon_group", autoResultMap = true)
|
||||
public class IconGroup extends Model<IconGroup> {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId(value = "id", type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 终端,例如pc,h5
|
||||
*/
|
||||
@TableField("terminal")
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 图标组,例如cms,oms,cmp
|
||||
*/
|
||||
@TableField("`group`")
|
||||
private String group;
|
||||
|
||||
/**
|
||||
* 图标组状态,0-未使用,1-使用中,2-已弃用,默认0
|
||||
*/
|
||||
@TableField("`status`")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
@TableField(value = "ext", typeHandler = FastjsonTypeHandler.class)
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* 是否删除(0:未删除;1:已删除)
|
||||
*/
|
||||
@TableField("is_delete")
|
||||
private Integer isDelete;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField("create_at")
|
||||
private Date createAt;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
@TableField("update_at")
|
||||
private Date updateAt;
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.oss.client.icon.mapper;
|
||||
|
||||
import cn.axzo.oss.client.icon.entity.IconDetail;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 图标详情Mapper
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:16
|
||||
*/
|
||||
@Mapper
|
||||
public interface IconDetailMapper extends BaseMapper<IconDetail> {
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.oss.client.icon.mapper;
|
||||
|
||||
import cn.axzo.oss.client.icon.entity.IconGroup;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 图标分组Mapper
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:18
|
||||
*/
|
||||
@Mapper
|
||||
public interface IconGroupMapper extends BaseMapper<IconGroup> {
|
||||
}
|
||||
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* axzo图标管理
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @date 2023/12/19 15:57
|
||||
* @version 1.0
|
||||
*/
|
||||
package cn.axzo.oss.client.icon;
|
||||
@ -0,0 +1,16 @@
|
||||
package cn.axzo.oss.client.icon.repository;
|
||||
|
||||
import cn.axzo.oss.client.icon.entity.IconDetail;
|
||||
import cn.axzo.oss.client.icon.mapper.IconDetailMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:19
|
||||
*/
|
||||
@Repository
|
||||
public class IconDetailRepository extends ServiceImpl<IconDetailMapper, IconDetail> {
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package cn.axzo.oss.client.icon.repository;
|
||||
|
||||
import cn.axzo.oss.client.icon.entity.IconGroup;
|
||||
import cn.axzo.oss.client.icon.mapper.IconGroupMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:23
|
||||
*/
|
||||
@Repository
|
||||
public class IconGroupRepository extends ServiceImpl<IconGroupMapper, IconGroup> {
|
||||
}
|
||||
@ -0,0 +1,67 @@
|
||||
package cn.axzo.oss.client.icon.service;
|
||||
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailAddReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailListReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailUpdateReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailUpdateStatus;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconTypeListReq;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconDetailListResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:24
|
||||
*/
|
||||
public interface IconDetailService {
|
||||
|
||||
/**
|
||||
* 新增图标
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailAddReq}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
Boolean add(IconDetailAddReq req);
|
||||
|
||||
/**
|
||||
* 更新图标信息
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailUpdateReq}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
Boolean update(IconDetailUpdateReq req);
|
||||
|
||||
/**
|
||||
* 更新图标状态
|
||||
*
|
||||
* @param id 图标id
|
||||
* @param status 状态
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
Boolean updateStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 图标列表
|
||||
*
|
||||
* @param req 图标列表请求 {@link IconDetailListReq}
|
||||
* @return 图标列表
|
||||
*/
|
||||
List<IconDetailListResp> list(IconDetailListReq req);
|
||||
|
||||
/**
|
||||
* 图标详情
|
||||
*
|
||||
* @param id 图标id
|
||||
* @return 图标详情
|
||||
*/
|
||||
IconDetailListResp detailById(Long id);
|
||||
|
||||
/**
|
||||
* 获取所有图标类型
|
||||
*
|
||||
* @param req 图标类型请求 {@link IconTypeListReq}
|
||||
* @return 图标类型
|
||||
*/
|
||||
List<String> getAllTypes(IconTypeListReq req);
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package cn.axzo.oss.client.icon.service;
|
||||
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupAddReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupListReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupUpdateReq;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconGroupListResp;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:23
|
||||
*/
|
||||
public interface IconGroupService {
|
||||
|
||||
/**
|
||||
* 添加图标组
|
||||
*
|
||||
* @param req 图标组信息 {@link IconGroupAddReq}
|
||||
* @return true:添加成功 false:添加失败
|
||||
*/
|
||||
Boolean add(IconGroupAddReq req);
|
||||
|
||||
/**
|
||||
* 修改图标组信息
|
||||
*
|
||||
* @param req 图标组信息 {@link IconGroupUpdateReq}
|
||||
* @return true:修改成功 false:修改失败
|
||||
*/
|
||||
Boolean update(IconGroupUpdateReq req);
|
||||
|
||||
/**
|
||||
* 修改图标组状态
|
||||
*
|
||||
* @param id 图标组id
|
||||
* @param status 状态:0-未使用,1-使用中,2-已弃用
|
||||
* @return true:修改成功 false:修改失败
|
||||
*/
|
||||
Boolean updateStatus(Long id, Integer status);
|
||||
|
||||
/**
|
||||
* 查询图标组列表
|
||||
*
|
||||
* @return 图标组列表 {@link IconGroupListResp}
|
||||
*/
|
||||
List<IconGroupListResp> list(IconGroupListReq req);
|
||||
|
||||
/**
|
||||
* 查询图标组详情
|
||||
*
|
||||
* @param id 图标组id
|
||||
* @return 图标组详情
|
||||
*/
|
||||
IconGroupListResp detailById(Long id);
|
||||
}
|
||||
@ -0,0 +1,228 @@
|
||||
package cn.axzo.oss.client.icon.service.impl;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.oss.client.icon.entity.IconDetail;
|
||||
import cn.axzo.oss.client.icon.entity.IconGroup;
|
||||
import cn.axzo.oss.client.icon.repository.IconDetailRepository;
|
||||
import cn.axzo.oss.client.icon.repository.IconGroupRepository;
|
||||
import cn.axzo.oss.client.icon.service.IconDetailService;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailAddReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailListReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconDetailUpdateReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconTypeListReq;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconDetailListResp;
|
||||
import cn.axzo.oss.common.enums.CodeEnum;
|
||||
import cn.axzo.oss.common.exception.BizException;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:25
|
||||
*/
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Service
|
||||
public class IconDetailServiceImpl implements IconDetailService {
|
||||
|
||||
private final IconGroupRepository iconGroupRepository;
|
||||
|
||||
private final IconDetailRepository iconDetailRepository;
|
||||
|
||||
/**
|
||||
* 新增图标
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailAddReq}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
@Override
|
||||
public Boolean add(IconDetailAddReq req) {
|
||||
// 校验图标组是否存在
|
||||
IconGroup iconGroup = iconGroupRepository.lambdaQuery()
|
||||
.eq(IconGroup::getId, req.getGroupId())
|
||||
.eq(IconGroup::getIsDelete, 0)
|
||||
.lt(IconGroup::getStatus, 2)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
BizException.error(Objects.nonNull(iconGroup), CodeEnum.ICON_GROUP_NOT_EXIST);
|
||||
// 校验图标是否已存在
|
||||
IconDetail iconDetail = iconDetailRepository.lambdaQuery()
|
||||
.eq(IconDetail::getGroupId, req.getGroupId())
|
||||
.eq(IconDetail::getName, req.getName())
|
||||
.eq(IconDetail::getIsDelete, 0)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
// 存在
|
||||
BizException.error(Objects.isNull(iconDetail), CodeEnum.ICON_EXIST);
|
||||
return iconDetailRepository.save(BeanMapper.copyBean(req, IconDetail.class, (r, i) -> {
|
||||
i.setExt(JSONUtil.toJsonStr(r.getExt()));
|
||||
// 获取图标格式
|
||||
String[] split = r.getName().split("\\.");
|
||||
if (ArrayUtil.isEmpty(split)){
|
||||
throw new ServiceException(CodeEnum.FILE_FORMAT_MAY_ERROR.getMessage());
|
||||
}
|
||||
i.setType(split[split.length-1].toLowerCase());
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改图标
|
||||
*
|
||||
* @param req 图标信息 {@link IconDetailUpdateReq}
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
@Override
|
||||
public Boolean update(IconDetailUpdateReq req) {
|
||||
IconDetail iconDetail = iconDetailRepository.getById(req.getId());
|
||||
if (Objects.isNull(iconDetail)) {
|
||||
return true;
|
||||
}
|
||||
return iconDetailRepository.lambdaUpdate()
|
||||
.eq(IconDetail::getId, req.getId())
|
||||
.set(IconDetail::getGroupId, req.getGroupId())
|
||||
.set(IconDetail::getName, req.getName())
|
||||
.set(IconDetail::getExt, JSONUtil.toJsonStr(req.getExt()))
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改图标状态
|
||||
*
|
||||
* @param id 图标id
|
||||
* @param status 状态
|
||||
* @return true:成功 false:失败
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean updateStatus(Long id, Integer status) {
|
||||
IconDetail iconDetail = iconDetailRepository.getById(id);
|
||||
if (Objects.isNull(iconDetail)) {
|
||||
return true;
|
||||
}
|
||||
// 状态未变则不修改
|
||||
if (Objects.equals(iconDetail.getStatus(), status)) {
|
||||
return true;
|
||||
}
|
||||
// 修改图标状态
|
||||
iconDetail.setStatus(status);
|
||||
iconDetailRepository.updateById(iconDetail);
|
||||
// 若修改图标状态后,该分组下所有图标均为同一状态(本次修改的目标状态),则修改图标组状态
|
||||
List<IconDetail> iconDetailList = iconDetailRepository.lambdaQuery()
|
||||
.eq(IconDetail::getIsDelete, 0)
|
||||
.eq(IconDetail::getGroupId, iconDetail.getGroupId())
|
||||
.list();
|
||||
boolean allMatch = iconDetailList.stream().allMatch(iconDetail1 -> Objects.equals(iconDetail1.getStatus(), status));
|
||||
if (!allMatch) {
|
||||
return true;
|
||||
}
|
||||
return iconGroupRepository.lambdaUpdate()
|
||||
.eq(IconGroup::getIsDelete, 0)
|
||||
.eq(IconGroup::getId, iconDetail.getGroupId())
|
||||
.set(IconGroup::getStatus, status)
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 图标列表
|
||||
*
|
||||
* @param req 图标列表查询参数 {@link IconDetailListReq}
|
||||
* @return 图标列表 {@link IconDetailListResp}
|
||||
*/
|
||||
@Override
|
||||
public List<IconDetailListResp> list(IconDetailListReq req) {
|
||||
List<String> finalTypes = null;
|
||||
if (!CollectionUtils.isEmpty(req.getTypes())) {
|
||||
finalTypes = req.getTypes().stream()
|
||||
.map(e -> e.trim().toLowerCase())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
// 查询图标列表
|
||||
List<IconDetail> iconDetailList = iconDetailRepository.lambdaQuery()
|
||||
.eq(IconDetail::getIsDelete, 0)
|
||||
.in(!CollectionUtils.isEmpty(req.getGroupIds()), IconDetail::getGroupId, req.getGroupIds())
|
||||
.in(!CollectionUtils.isEmpty(req.getIds()), IconDetail::getId, req.getIds())
|
||||
.like(StringUtils.hasText(req.getName()), IconDetail::getName, req)
|
||||
.in(!CollectionUtils.isEmpty(finalTypes), IconDetail::getType, finalTypes)
|
||||
.in(!CollectionUtils.isEmpty(req.getStatuses()), IconDetail::getStatus, req.getStatuses())
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(iconDetailList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Long> groupIds = iconDetailList.stream()
|
||||
.mapToLong(IconDetail::getGroupId)
|
||||
.distinct()
|
||||
.boxed()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 查询分组信息
|
||||
List<IconGroup> iconGroups = iconGroupRepository.listByIds(groupIds);
|
||||
BizException.error(!CollectionUtils.isEmpty(iconGroups), 500, "数据异常");
|
||||
|
||||
Map<Long, IconGroup> groupMap = iconGroups.stream().collect(Collectors.toMap(IconGroup::getId, Function.identity()));
|
||||
|
||||
return BeanMapper.copyList(iconDetailList, IconDetailListResp.class, (iconDetail, iconDetailListResp) -> {
|
||||
iconDetailListResp.setTerminal(groupMap.get(iconDetail.getGroupId()).getTerminal());
|
||||
iconDetailListResp.setGroupName(groupMap.get(iconDetail.getGroupId()).getGroup());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 图标详情
|
||||
*
|
||||
* @param id 图标id
|
||||
* @return 图标详情 {@link IconDetailListResp}
|
||||
*/
|
||||
@Override
|
||||
public IconDetailListResp detailById(Long id) {
|
||||
IconDetail iconDetail = iconDetailRepository.getById(id);
|
||||
if (Objects.isNull(iconDetail)) {
|
||||
return null;
|
||||
}
|
||||
IconGroup iconGroup = iconGroupRepository.getById(iconDetail.getGroupId());
|
||||
BizException.error(Objects.nonNull(iconGroup), 500, "数据异常");
|
||||
return BeanMapper.copyBean(iconDetail, IconDetailListResp.class, (i, r) -> {
|
||||
r.setTerminal(iconGroup.getTerminal());
|
||||
r.setGroupName(iconGroup.getGroup());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取图标所有类型
|
||||
*
|
||||
* @param req 查询参数 {@link IconTypeListReq}
|
||||
* @return 所有类型 {@link List<String>}
|
||||
*/
|
||||
@Override
|
||||
public List<String> getAllTypes(IconTypeListReq req) {
|
||||
List<IconDetail> iconDetailList = iconDetailRepository.lambdaQuery()
|
||||
.eq(IconDetail::getIsDelete, 0)
|
||||
.in(!CollectionUtils.isEmpty(req.getGroupIds()), IconDetail::getGroupId, req.getGroupIds().stream()
|
||||
.distinct()
|
||||
.collect(Collectors.toList()))
|
||||
.list();
|
||||
if (CollectionUtils.isEmpty(iconDetailList)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return iconDetailList.stream()
|
||||
.map(IconDetail::getType)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,135 @@
|
||||
package cn.axzo.oss.client.icon.service.impl;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.oss.client.icon.entity.IconDetail;
|
||||
import cn.axzo.oss.client.icon.entity.IconGroup;
|
||||
import cn.axzo.oss.client.icon.repository.IconDetailRepository;
|
||||
import cn.axzo.oss.client.icon.repository.IconGroupRepository;
|
||||
import cn.axzo.oss.client.icon.service.IconGroupService;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupAddReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupListReq;
|
||||
import cn.axzo.oss.client.icon.vo.request.IconGroupUpdateReq;
|
||||
import cn.axzo.oss.client.icon.vo.response.IconGroupListResp;
|
||||
import cn.axzo.oss.common.enums.CodeEnum;
|
||||
import cn.axzo.oss.common.exception.BizException;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:24
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class IconGroupServiceImpl implements IconGroupService {
|
||||
|
||||
private final IconGroupRepository iconGroupRepository;
|
||||
|
||||
private final IconDetailRepository iconDetailRepository;
|
||||
|
||||
/**
|
||||
* 新增图标组
|
||||
*
|
||||
* @param req 图标组信息
|
||||
* @return true:添加成功 false:添加失败
|
||||
*/
|
||||
@Override
|
||||
public Boolean add(IconGroupAddReq req) {
|
||||
// 检查该图标组是否已存在
|
||||
IconGroup iconGroup = iconGroupRepository.lambdaQuery()
|
||||
.eq(IconGroup::getTerminal, req.getTerminal())
|
||||
.eq(IconGroup::getGroup, req.getGroup())
|
||||
.eq(IconGroup::getIsDelete, 0)
|
||||
.last("limit 1")
|
||||
.one();
|
||||
// 存在
|
||||
BizException.error(Objects.isNull(iconGroup), CodeEnum.ICON_GROUP_EXIST);
|
||||
return iconGroupRepository.save(BeanMapper.copyBean(req, IconGroup.class, (r, i) -> i.setExt(JSONUtil.toJsonStr(r.getExt()))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改图标组信息
|
||||
*
|
||||
* @param req 图标组信息
|
||||
* @return true:修改成功 false:修改失败
|
||||
*/
|
||||
@Override
|
||||
public Boolean update(IconGroupUpdateReq req) {
|
||||
// 查询图标组信息
|
||||
IconGroup iconGroup = iconGroupRepository.getById(req.getId());
|
||||
if (Objects.isNull(iconGroup)) {
|
||||
return true;
|
||||
}
|
||||
return iconGroupRepository.lambdaUpdate()
|
||||
.eq(IconGroup::getId, req.getId())
|
||||
.set(IconGroup::getGroup, req.getGroup())
|
||||
.set(IconGroup::getExt, JSONUtil.toJsonStr(req.getExt()))
|
||||
.update();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改图标组状态
|
||||
*
|
||||
* @param id 图标组id
|
||||
* @param status 状态:0-未使用,1-使用中,2-已弃用
|
||||
* @return true:修改成功 false:修改失败
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Boolean updateStatus(Long id, Integer status) {
|
||||
// 查询图标组信息
|
||||
IconGroup iconGroup = iconGroupRepository.getById(id);
|
||||
if (Objects.isNull(iconGroup)) {
|
||||
return true;
|
||||
}
|
||||
// 状态未变则不修改
|
||||
if (Objects.equals(iconGroup.getStatus(), status)) {
|
||||
return true;
|
||||
}
|
||||
// 修改状态,并修改该图标组下所有图标的状态
|
||||
iconGroup.setStatus(status);
|
||||
iconDetailRepository.lambdaUpdate()
|
||||
.eq(IconDetail::getGroupId, iconGroup.getId())
|
||||
.eq(IconDetail::getIsDelete, 0)
|
||||
.set(IconDetail::getStatus, status)
|
||||
.update();
|
||||
return iconGroupRepository.updateById(iconGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询图标组列表
|
||||
*
|
||||
* @param req 图标组列表条件
|
||||
* @return 图标组列表
|
||||
*/
|
||||
@Override
|
||||
public List<IconGroupListResp> list(IconGroupListReq req) {
|
||||
List<IconGroup> iconGroups = iconGroupRepository.lambdaQuery()
|
||||
.eq(IconGroup::getIsDelete, 0)
|
||||
.in(!CollectionUtils.isEmpty(req.getTerminals()), IconGroup::getTerminal, req.getTerminals())
|
||||
.in(!CollectionUtils.isEmpty(req.getGroups()), IconGroup::getGroup, req.getGroups())
|
||||
.in(!CollectionUtils.isEmpty(req.getStatuses()), IconGroup::getStatus, req.getStatuses())
|
||||
.list();
|
||||
return BeanMapper.copyList(iconGroups, IconGroupListResp.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询图标组详情
|
||||
*
|
||||
* @param id 图标组id
|
||||
* @return 图标组详情
|
||||
*/
|
||||
@Override
|
||||
public IconGroupListResp detailById(Long id) {
|
||||
return BeanMapper.copyBean(iconGroupRepository.getById(id), IconGroupListResp.class);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
package cn.axzo.oss.client.icon.validator;
|
||||
|
||||
import cn.axzo.oss.client.icon.annotation.IsJsonString;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
|
||||
/**
|
||||
* json字符串校验器
|
||||
*
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:55
|
||||
*/
|
||||
public class JsonStringValidator implements ConstraintValidator<IsJsonString, String> {
|
||||
|
||||
private boolean allowBlank = true;
|
||||
|
||||
@Override
|
||||
public void initialize(IsJsonString constraintAnnotation) {
|
||||
allowBlank = constraintAnnotation.allowBlank();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return allowBlank;
|
||||
}
|
||||
try {
|
||||
Object o = JSON.parse(value);
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import cn.axzo.oss.client.icon.annotation.IsJsonString;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 17:32
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconDetailAddReq {
|
||||
|
||||
/**
|
||||
* 图标组ID
|
||||
*/
|
||||
@NotNull(message = "图标组id不能为空")
|
||||
private Long groupId;
|
||||
|
||||
/**
|
||||
* 图标名称
|
||||
*/
|
||||
@NotBlank(message = "图标名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 图标地址
|
||||
*/
|
||||
@NotBlank(message = "图标地址不能为空")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 图标存储大小
|
||||
*/
|
||||
@NotBlank(message = "图标存储大小不能为空")
|
||||
private String size;
|
||||
|
||||
/**
|
||||
* 尺寸-宽,单位mm@
|
||||
*/
|
||||
@Min(value = 0, message = "图标宽度不能小于0")
|
||||
@NotNull(message = "图标宽度不能为空")
|
||||
private Integer weight;
|
||||
|
||||
/**
|
||||
* 尺寸-高,单位mm
|
||||
*/
|
||||
@Min(value = 0, message = "图标高度不能小于0")
|
||||
@NotNull(message = "图标高度不能为空")
|
||||
private Integer height;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
private Map<String, String> ext;
|
||||
|
||||
}
|
||||
@ -0,0 +1,45 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 19:54
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconDetailListReq {
|
||||
|
||||
/**
|
||||
* 图标ID,多个用逗号分隔
|
||||
*/
|
||||
private List<Long> ids;
|
||||
|
||||
/**
|
||||
* 分组ID,多个用逗号分隔
|
||||
*/
|
||||
private List<Long> groupIds;
|
||||
|
||||
/**
|
||||
* 名称,模糊查询
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 类型,如:svg,png,多个用逗号分隔
|
||||
*/
|
||||
private List<String> types;
|
||||
|
||||
/**
|
||||
* 状态,0:正常,1:禁用,多个用逗号分隔
|
||||
*/
|
||||
private List<Integer> statuses;
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import cn.axzo.oss.client.icon.annotation.IsJsonString;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 18:11
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconDetailUpdateReq {
|
||||
|
||||
/**
|
||||
* 图标ID
|
||||
*/
|
||||
@NotNull(message = "图标id不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图标组ID
|
||||
*/
|
||||
@NotNull(message = "图标组id不能为空")
|
||||
private Long groupId;
|
||||
|
||||
/**
|
||||
* 图标名称
|
||||
*/
|
||||
@NotBlank(message = "图标名称不能为空")
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
private Map<String, String> ext;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 18:22
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconDetailUpdateStatus {
|
||||
|
||||
/**
|
||||
* 图标id
|
||||
*/
|
||||
@NotNull(message = "图标id不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图标状态,状态:0-未使用,1-使用中,2-已弃用
|
||||
*/
|
||||
@NotNull(message = "图标状态不能为空")
|
||||
private Integer status;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import cn.axzo.oss.client.icon.annotation.IsJsonString;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:37
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconGroupAddReq {
|
||||
|
||||
/**
|
||||
* 终端,例如pc,h5
|
||||
*/
|
||||
@NotBlank(message = "段类型不能为空")
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 图标组,例如cms,oms,cmp
|
||||
*/
|
||||
@NotBlank(message = "图标组不能为空")
|
||||
private String group;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
private JSONObject ext;
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 18:31
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconGroupListReq {
|
||||
|
||||
/**
|
||||
* 终端,pc,h5,多个用逗号分隔
|
||||
*/
|
||||
List<String> terminals;
|
||||
|
||||
/**
|
||||
* 图标组, 多个用逗号分隔
|
||||
*/
|
||||
List<String> groups;
|
||||
|
||||
/**
|
||||
* 状态,0:正常,1:禁用,多个用逗号分隔
|
||||
*/
|
||||
List<Integer> statuses;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import cn.axzo.oss.client.icon.annotation.IsJsonString;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 17:08
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconGroupUpdateReq {
|
||||
|
||||
/**
|
||||
* 图标组id
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图标组,例如cms,oms,cmp
|
||||
*/
|
||||
@NotBlank(message = "图标组名不能为空")
|
||||
private String group;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
private Map<String, String> ext;
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 16:56
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconGroupUpdateStatusReq {
|
||||
|
||||
/**
|
||||
* 图标组id
|
||||
*/
|
||||
@NotNull(message = "图标组id不能为空")
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 图标组状态,状态:0-未使用,1-使用中,2-已弃用
|
||||
*/
|
||||
@NotNull(message = "图标组状态不能为空")
|
||||
private Integer status;
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
package cn.axzo.oss.client.icon.vo.request;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 图标类型列表请求
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2024/3/11 10:39
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconTypeListReq {
|
||||
|
||||
/**
|
||||
* 分组ID,多个用逗号分隔
|
||||
*/
|
||||
private List<Long> groupIds;
|
||||
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
package cn.axzo.oss.client.icon.vo.response;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/20 19:59
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconDetailListResp {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 终端,例如pc,h5
|
||||
*/
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 图标组ID
|
||||
*/
|
||||
private Long groupId;
|
||||
|
||||
/**
|
||||
* 图标组名称
|
||||
*/
|
||||
private String groupName;
|
||||
|
||||
/**
|
||||
* 图标名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 图标类型,如svg,png
|
||||
*/
|
||||
private String type;
|
||||
|
||||
/**
|
||||
* 图标地址
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 图标存储大小,单位KB
|
||||
*/
|
||||
private String size;
|
||||
|
||||
/**
|
||||
* 尺寸-宽,单位mm
|
||||
*/
|
||||
private Integer weight;
|
||||
|
||||
/**
|
||||
* 尺寸-高,单位mm
|
||||
*/
|
||||
private Integer height;
|
||||
|
||||
/**
|
||||
* 图标状态,0-未使用,1-使用中,2-已弃用,默认0
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createAt;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
private Date updateAt;
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
package cn.axzo.oss.client.icon.vo.response;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author chenwenjian
|
||||
* @version 1.0
|
||||
* @date 2023/12/19 17:30
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class IconGroupListResp {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 终端,例如pc,h5
|
||||
*/
|
||||
private String terminal;
|
||||
|
||||
/**
|
||||
* 图标组,例如cms,oms,cmp
|
||||
*/
|
||||
private String group;
|
||||
|
||||
/**
|
||||
* 扩展信息(json)
|
||||
*/
|
||||
private String ext;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createAt;
|
||||
|
||||
/**
|
||||
* 修改时间
|
||||
*/
|
||||
private Date updateAt;
|
||||
|
||||
}
|
||||
@ -61,6 +61,12 @@ public enum CodeEnum implements EnumBase<Integer> {
|
||||
FILE_APP_IS_EMPTY(125, "app is empty"),
|
||||
BUCKET_TYPE_IS_EMPTY(126, "bucketType is empty"),
|
||||
|
||||
ICON_GROUP_EXIST(117, "图标组已存在"),
|
||||
ICON_GROUP_NOT_EXIST(118, "图标组不存在"),
|
||||
ICON_EXIST(119, "图标已存在"),
|
||||
FILE_FORMAT_MAY_ERROR(201, "文件格式可能错误")
|
||||
|
||||
|
||||
;
|
||||
|
||||
private final Integer code;
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package cn.axzo.oss.common.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 文件下载类型枚举类
|
||||
*
|
||||
* @author hucf
|
||||
* @since 2024/1/23 17:57
|
||||
**/
|
||||
@Getter
|
||||
public enum FileDownloadTypeEnum {
|
||||
STREAM_DOWNLOAD(1, "流式下载"),
|
||||
CHECK_POINT_DOWNLOAD(2, "断点续传下载"),
|
||||
TEMPORARY_URL_ACCESS(3, "通过临时url访问OBs")
|
||||
;
|
||||
private final Integer code;
|
||||
private final String message;
|
||||
|
||||
FileDownloadTypeEnum(Integer code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,10 @@
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
package cn.axzo.oss.http.api;
|
||||
|
||||
import cn.axzo.oss.http.model.TemporaryUrlAccessRes;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import feign.Response;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
/**
|
||||
* @author axzo
|
||||
* @since 2024/3/7 16:56
|
||||
**/
|
||||
@FeignClient(
|
||||
name = "oss",
|
||||
url = "http://oss:9123"
|
||||
)
|
||||
public interface DownloadFileApi {
|
||||
@GetMapping(value = "/webApi/v1/obs/downloadFileFromObs")
|
||||
CommonResponse<Response> downloadFileFromObs(@RequestParam("fileUuid") String fileUuId);
|
||||
|
||||
@GetMapping(value = "/webApi/v1/obs/temporaryUrlAccess")
|
||||
CommonResponse<TemporaryUrlAccessRes> temporaryUrlAccess(@RequestParam("fileUuid") String fileUuId);
|
||||
}
|
||||
@ -3,10 +3,14 @@ package cn.axzo.oss.http.api;
|
||||
import cn.axzo.oss.http.model.*;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import feign.Response;
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
package cn.axzo.oss.http.api;
|
||||
|
||||
import cn.axzo.oss.http.model.WebFileUploadVo;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import feign.Response;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||
|
||||
/**
|
||||
* @author wangsiqian
|
||||
* @since 2024/02/27
|
||||
*/
|
||||
@FeignClient(
|
||||
name = "oss",
|
||||
url = "http://oss:9123"
|
||||
)
|
||||
public interface WebFileServiceApi {
|
||||
/**
|
||||
* OBS:文件上传(断点续传)
|
||||
*
|
||||
* @param appCode 应用编码
|
||||
* @param bizScene 业务场景
|
||||
* @param file MultipartFile
|
||||
* @return WebFileUploadVo
|
||||
*/
|
||||
@PostMapping(value = "/webApi/v1/file2", consumes = MULTIPART_FORM_DATA_VALUE)
|
||||
CommonResponse<WebFileUploadVo> uploadObs(@Valid @RequestParam("appCode") String appCode,
|
||||
@Valid @RequestParam("bizScene") String bizScene,
|
||||
@Valid @RequestPart MultipartFile file);
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
package cn.axzo.oss.http.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author hucf
|
||||
* @since 2024/3/6 15:11
|
||||
**/
|
||||
@Data
|
||||
public class DownloadFileFromObsRequest {
|
||||
/**
|
||||
* 文件uuid
|
||||
*/
|
||||
@NotBlank(message = "文件uuid不能为空")
|
||||
private String fileKey;
|
||||
|
||||
/**
|
||||
* 图片样式
|
||||
*/
|
||||
private String style;
|
||||
|
||||
/**
|
||||
* 下载方式:1:流式下载;2:断点续传方式下载
|
||||
*/
|
||||
@NotNull(message = "下载方式不能为空")
|
||||
private Integer fileDownloadType;
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
package cn.axzo.oss.http.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* @author hucf
|
||||
* @since 2024/3/6 15:15
|
||||
**/
|
||||
@Data
|
||||
public class DownloadFileFromObsResponse {
|
||||
/**
|
||||
* 文件 URL
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 文件 Key
|
||||
*/
|
||||
private String fileKey;
|
||||
|
||||
/**
|
||||
* URL MD5
|
||||
*/
|
||||
private String urlMd5;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 文件大小
|
||||
*/
|
||||
private Long fileSize;
|
||||
|
||||
/**
|
||||
* 文件格式
|
||||
*/
|
||||
private String fileFormat;
|
||||
|
||||
/**
|
||||
* 文件流
|
||||
*/
|
||||
private InputStream fileStream;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
package cn.axzo.oss.http.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author hucf
|
||||
* @since 2024/3/11 18:21
|
||||
**/
|
||||
@Data
|
||||
public class TemporaryUrlAccessRes {
|
||||
/**
|
||||
* 文件 URL
|
||||
*/
|
||||
private String url;
|
||||
/**
|
||||
* 文件 Key
|
||||
*/
|
||||
private String fileKey;
|
||||
|
||||
/**
|
||||
* URL MD5
|
||||
*/
|
||||
private String urlMd5;
|
||||
|
||||
/**
|
||||
* 文件名称
|
||||
*/
|
||||
private String fileName;
|
||||
|
||||
/**
|
||||
* 文件大小
|
||||
*/
|
||||
private Long fileSize;
|
||||
|
||||
/**
|
||||
* 文件格式
|
||||
*/
|
||||
private String fileFormat;
|
||||
|
||||
/**
|
||||
* obs:临时url
|
||||
*/
|
||||
private String signedUrl;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package cn.axzo.oss.client.vo;
|
||||
package cn.axzo.oss.http.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@ -17,6 +17,10 @@ public interface HuaWeiCloudService {
|
||||
|
||||
String multipartUpload(String bucketName, String fileName, String appCode, InputStream srcStream);
|
||||
|
||||
InputStream getObject(String bucketName, String objectKey, Integer fileDownloadType);
|
||||
|
||||
TemporarySignatureResponse createTemporarySignature(String bucketName, String objectKey);
|
||||
|
||||
/**
|
||||
* 授权给第三方-下载
|
||||
*/
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.oss.integration.s3.impl;
|
||||
|
||||
import cn.axzo.oss.common.enums.FileDownloadTypeEnum;
|
||||
import cn.axzo.oss.common.enums.CodeEnum;
|
||||
import cn.axzo.oss.common.exception.BizException;
|
||||
import cn.axzo.oss.common.utils.JsonUtil;
|
||||
@ -8,6 +9,7 @@ import cn.axzo.oss.integration.s3.client.HuaWeiCloudObsClient;
|
||||
import cn.axzo.oss.integration.s3.config.HuaWeiCloudObsConfig;
|
||||
import cn.azxo.framework.common.utils.LogUtil;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.obs.services.ObsClient;
|
||||
import com.obs.services.exception.ObsException;
|
||||
@ -19,6 +21,7 @@ import org.springframework.stereotype.Service;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -232,6 +235,98 @@ public class HuaWeiCloudServiceImpl implements HuaWeiCloudService {
|
||||
return obsClient.uploadFile(request);
|
||||
}
|
||||
|
||||
/**
|
||||
* obs下载文件:流式下载
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param objectKey 对象名称
|
||||
* @return InputStream
|
||||
*/
|
||||
@Override
|
||||
public InputStream getObject(String bucketName, String objectKey, Integer fileDownloadType) {
|
||||
ObsClient obsClient = huaWeiCloudObsClient.getClient();
|
||||
if (FileDownloadTypeEnum.STREAM_DOWNLOAD.getCode().equals(fileDownloadType)) {
|
||||
try {
|
||||
GetObjectRequest request = new GetObjectRequest();
|
||||
request.setBucketName(bucketName);
|
||||
request.setObjectKey(objectKey);
|
||||
|
||||
ObsObject object = obsClient.getObject(request);
|
||||
log.info("下载华为云OBS文件成功");
|
||||
return object.getObjectContent();
|
||||
} catch (ObsException obsException) {
|
||||
log.warn("下载华为云OBS文件失败,HTTP Code:{}, Error Code:{}, Request ID:{}, Host ID:{}, Error Message:{}",
|
||||
obsException.getResponseCode(),
|
||||
obsException.getErrorCode(),
|
||||
obsException.getErrorRequestId(),
|
||||
obsException.getErrorHostId(),
|
||||
obsException.getErrorMessage());
|
||||
}
|
||||
} else if (FileDownloadTypeEnum.CHECK_POINT_DOWNLOAD.getCode().equals(fileDownloadType)) {
|
||||
try {
|
||||
DownloadFileRequest request = new DownloadFileRequest(bucketName, objectKey);
|
||||
// 设置下载对象的本地文件全路径,当该值为空时,默认为当前程序的运行目录。
|
||||
request.setDownloadFile("");
|
||||
// 设置分段下载时的最大并发数
|
||||
request.setTaskNum(Integer.parseInt(huaWeiCloudObsConfig.getTaskNum()));
|
||||
// 设置分段大小为10MB
|
||||
request.setPartSize(Long.parseLong(huaWeiCloudObsConfig.getPartSize()));
|
||||
// 是否开启断点续传模式
|
||||
request.setEnableCheckpoint(Boolean.parseBoolean(huaWeiCloudObsConfig.getEnableCheckPoint()));
|
||||
// 是否自动解码响应头
|
||||
request.setIsEncodeHeaders(Boolean.parseBoolean(huaWeiCloudObsConfig.getEncodeHeaders()));
|
||||
|
||||
DownloadFileResult downloadFileResult = obsClient.downloadFile(request);
|
||||
String etag = downloadFileResult.getObjectMetadata().getEtag();
|
||||
log.info("下载华为云OBS文件成功");
|
||||
} catch (NumberFormatException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (ObsException obsException) {
|
||||
log.warn("下载华为云OBS文件失败,HTTP Code:{}, Error Code:{}, Request ID:{}, Host ID:{}, Error Message:{}",
|
||||
obsException.getResponseCode(),
|
||||
obsException.getErrorCode(),
|
||||
obsException.getErrorRequestId(),
|
||||
obsException.getErrorHostId(),
|
||||
obsException.getErrorMessage());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取OBS临时url
|
||||
*
|
||||
* @param bucketName 桶名称
|
||||
* @param objectKey 对象名称
|
||||
* @return TemporarySignatureResponse
|
||||
*/
|
||||
@Override
|
||||
public TemporarySignatureResponse createTemporarySignature(String bucketName, String objectKey) {
|
||||
TemporarySignatureRequest request = new TemporarySignatureRequest();
|
||||
// 桶名称
|
||||
request.setBucketName(bucketName);
|
||||
// 对象名称
|
||||
request.setObjectKey(objectKey);
|
||||
// HTTP方法类型
|
||||
request.setMethod(HttpMethodEnum.GET);
|
||||
// 带授权信息的URL的过期时间300秒
|
||||
request.setExpires(300L);
|
||||
// 发起请求的时间
|
||||
request.setRequestDate(new Date());
|
||||
|
||||
try {
|
||||
ObsClient obsClient = huaWeiCloudObsClient.getClient();
|
||||
TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
|
||||
log.info("response = {}", JSONUtil.toJsonStr(response));
|
||||
return response;
|
||||
} catch (Exception exception) {
|
||||
log.warn("获取临时url发生异常, exception = {}", exception.getMessage());
|
||||
log.warn("异常信息:");
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权给第三方-下载
|
||||
*/
|
||||
|
||||
@ -53,6 +53,10 @@ public interface FileManager {
|
||||
|
||||
String multipartUploadFile(String bucketName, String tgtFileKey, MultipartFile file);
|
||||
|
||||
InputStream downloadObsFile(String bucketName, String objectKey, Integer fileDownloadType);
|
||||
|
||||
String getTempUrlFromOns(String bucketName, String objectKey);
|
||||
|
||||
/**
|
||||
* 根据华为云/阿里云,授权给第三方下载
|
||||
*/
|
||||
|
||||
@ -45,4 +45,9 @@ public class ServerFileDownloadResponse {
|
||||
* 文件流
|
||||
*/
|
||||
private InputStream fileStream;
|
||||
|
||||
/**
|
||||
* obs:临时url
|
||||
*/
|
||||
private String signedUrl;
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ import cn.axzo.oss.manager.api.FileManager;
|
||||
import cn.axzo.oss.manager.api.dto.PartETag;
|
||||
import cn.axzo.oss.manager.api.dto.request.MultipartUploadDto;
|
||||
import com.obs.services.model.TemporarySignatureResponse;
|
||||
import com.obs.services.model.TemporarySignatureResponse;
|
||||
import cn.axzo.oss.manager.api.vo.SignUrlUploadVo;
|
||||
import com.obs.services.model.TemporarySignatureResponse;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -131,6 +132,15 @@ public class FileManagerImpl implements FileManager {
|
||||
return partETagList;
|
||||
}
|
||||
|
||||
public InputStream downloadObsFile(String bucketName, String objectKey, Integer fileDownloadType) {
|
||||
return huaWeiCloudService.getObject(bucketName, objectKey, fileDownloadType);
|
||||
}
|
||||
|
||||
public String getTempUrlFromOns(String bucketName, String objectKey) {
|
||||
TemporarySignatureResponse response = huaWeiCloudService.createTemporarySignature(bucketName, objectKey);
|
||||
return response.getSignedUrl();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据华为云/阿里云,授权给第三方下载
|
||||
*/
|
||||
|
||||
@ -52,6 +52,8 @@ public interface FileService {
|
||||
|
||||
String getFilePath(MultipartFile file);
|
||||
|
||||
ServerFileDownloadResponse getObject(ServerFileDownloadDto dto, Integer fileDownloadType);
|
||||
|
||||
/**
|
||||
* 授权给第三方下载
|
||||
*/
|
||||
|
||||
@ -267,6 +267,9 @@ public class FileServiceImpl implements FileService {
|
||||
}
|
||||
|
||||
private FileUploadConfig getFileUploadConfig(String appCode, String bizScene, Integer channelType) {
|
||||
// 检查appCode
|
||||
checkAppCode(appCode);
|
||||
|
||||
// 通过appcode获取文件渠道桶信息
|
||||
AppChannelBucket appChannelBucket = appChannelBucketManager.getByAppCode(appCode, channelType);
|
||||
|
||||
@ -752,6 +755,40 @@ public class FileServiceImpl implements FileService {
|
||||
}
|
||||
}
|
||||
|
||||
public ServerFileDownloadResponse getObject(ServerFileDownloadDto dto, Integer fileDownloadType) {
|
||||
log.info("obs download file = {}", JsonUtil.obj2Str(dto));
|
||||
File file = null;
|
||||
String fileKey = dto.getFileKey();
|
||||
if (fileKey.contains(IS_URL)) {
|
||||
String urlMd5 = Utility.getMd5(fileKey);
|
||||
file = fileDao.getByUrlMd5(urlMd5);
|
||||
} else {
|
||||
file = fileDao.getByFileUuid(fileKey);
|
||||
}
|
||||
if (Utility.objIsNull(file)) {
|
||||
log.warn("obs download file is null, fileKey = {}", fileKey);
|
||||
BizException.error(false, CodeEnum.FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 对象名称:目录+文件名
|
||||
String objectKey = file.getDirectory() + SEPARATOR + file.getFileName();
|
||||
// 桶名称
|
||||
String bucketName = file.getBucketName();
|
||||
InputStream fileStream = null;
|
||||
String tempUrlFromOns = null;
|
||||
if (FileDownloadTypeEnum.TEMPORARY_URL_ACCESS.getCode().equals(fileDownloadType)) {
|
||||
tempUrlFromOns = fileManager.getTempUrlFromOns(bucketName, objectKey);
|
||||
} else {
|
||||
fileStream = fileManager.downloadObsFile(bucketName, objectKey, fileDownloadType);
|
||||
if (Objects.isNull(fileStream)) {
|
||||
log.warn("下载的文件流为空");
|
||||
}
|
||||
}
|
||||
ServerFileDownloadResponse response = setFileDownloadResponse(file, fileStream);
|
||||
response.setSignedUrl(tempUrlFromOns);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 授权给第三方-下载
|
||||
*/
|
||||
|
||||
Loading…
Reference in New Issue
Block a user