智能配图代码编写,新增删除修改查询功能等

This commit is contained in:
lilin 2026-07-28 18:59:04 +08:00
parent 5063540d75
commit 6b93fe145e
8 changed files with 531 additions and 0 deletions

View File

@ -0,0 +1,69 @@
package com.yfd.platform.common.utils;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* Base64 MultipartFile 的适配器实现
* 用于将前端传来的 Base64 字符串伪装成标准文件对象
*/
public class Base64MultipartFile implements MultipartFile {
private final byte[] content;
private final String name;
private final String originalFilename;
private final String contentType;
public Base64MultipartFile(byte[] content, String name, String originalFilename, String contentType) {
this.content = content;
this.name = name;
this.originalFilename = originalFilename;
this.contentType = contentType;
}
@Override
public String getName() {
return name;
}
@Override
public String getOriginalFilename() {
return originalFilename;
}
@Override
public String getContentType() {
return contentType;
}
@Override
public boolean isEmpty() {
return content == null || content.length == 0;
}
@Override
public long getSize() {
return content != null ? content.length : 0;
}
@Override
public byte[] getBytes() throws IOException {
return content;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(content);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
try (FileOutputStream fos = new FileOutputStream(dest)) {
fos.write(content);
}
}
}

View File

@ -84,6 +84,7 @@ public class SecurityConfig {
// .requestMatchers("/mapLegend/**").permitAll()
// .requestMatchers("/base/msalongb/**").permitAll()
// .requestMatchers("/base/msalongdetb/**").permitAll()
// .requestMatchers("/smartImage/**").permitAll()
.requestMatchers("/sms/**").permitAll()
.requestMatchers(HttpMethod.GET, "/").permitAll()
.requestMatchers(HttpMethod.GET,

View File

@ -202,6 +202,14 @@ public class SwaggerConfig {
.build();
}
@Bean
public GroupedOpenApi groupEnvSmartImageApi() {
return GroupedOpenApi.builder()
.group("3.11 智能配图-首页(si)")
.packagesToScan("com.yfd.platform.qgc_env.si.controller")
.build();
}

View File

@ -0,0 +1,98 @@
package com.yfd.platform.qgc_env.si.controller;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.exception.BizException;
import com.yfd.platform.common.utils.UserNameFillHelper;
import com.yfd.platform.config.ResponseResult;
import com.yfd.platform.qgc_env.si.entity.vo.SmartImageVo;
import com.yfd.platform.qgc_env.si.service.ISmartImageService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import com.yfd.platform.utils.DictCodeToNameConverter;
import com.yfd.platform.utils.SecurityUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
/**
* 智能配图控制器
*
* @author migration
*/
@RestController
@RequestMapping("/smartImage")
@Tag(name = "智能配图控制器")
public class SmartImageController {
@Resource
private ISmartImageService smartImageService;
@Resource
private UserNameFillHelper userNameFillHelper;
@Resource
private DictCodeToNameConverter dictCodeToNameConverter;
/**
* 条件过滤数据列表
*/
@Operation(summary = "条件过滤数据列表")
@PostMapping("/GetKendoList")
public ResponseResult getKendoList( @RequestBody DataSourceRequest request) {
Page<SmartImageVo> pushConfigPage = DataSourceRequestUtil.executeQuery(request, SmartImageVo.class, smartImageService);
userNameFillHelper.fillUserNames(pushConfigPage.getRecords());
return ResponseResult.successData(pushConfigPage);
}
/**
* 新增或修改
*/
@Operation(summary = "新增或修改")
@PostMapping("/save")
public ResponseResult save(@RequestBody SmartImageVo smartImage) {
if (smartImage == null) {
return ResponseResult.error("智能配图信息不能为空.");
}
if (StrUtil.isBlank(smartImage.getPeituName())) {
throw new BizException("配图名称(peituName)不能为空.");
}
if (StrUtil.isBlank(smartImage.getConfig())) {
throw new BizException("配图配置(config)不能为空.");
}
// 新增时设置创建信息
if (StrUtil.isBlank(smartImage.getId())) {
smartImage.setCreatedAt(new Date());
smartImage.setRecordUser(SecurityUtils.getUserId());
smartImage.setIsDeleted(0);
}
// 设置操作人操作时间更新信息
smartImage.setOperator(SecurityUtils.getUserId());
smartImage.setOperateTime(new Date());
smartImage.setModifyUser(SecurityUtils.getUserId());
smartImage.setModifyTime(new Date());
smartImageService.saveWithAttachment(smartImage);
return ResponseResult.successData(smartImage.getId());
}
/**
* 删除
*/
@Operation(summary = "删除")
@PostMapping("/delete")
public ResponseResult delete(@RequestBody List<String> ids) {
smartImageService.deleteByIds(ids);
return ResponseResult.success("删除成功.");
}
}

View File

@ -0,0 +1,99 @@
package com.yfd.platform.qgc_env.si.entity.vo;
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.fasterxml.jackson.annotation.JsonFormat;
import com.yfd.platform.annotation.UserIdField;
import com.yfd.platform.annotation.UserNameField;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 智能配图表
*
* @author migration
*/
@Data
@TableName("SD_SMART_IMAGE")
@Schema(description = "智能配图表")
public class SmartImageVo implements Serializable {
private static final long serialVersionUID = 1L;
@TableId(type = IdType.ASSIGN_UUID)
private String id;
/** 配图名称 */
@TableField("PEITU_NAME")
private String peituName;
/** 操作人关联SYS_USER.ID */
@TableField("OPERATOR")
@UserIdField
private String operator;
/** 操作人名称(非数据库字段) */
@TableField(exist = false)
@UserNameField
private String operatorName;
/** 配图操作时间 */
@TableField("OPERATE_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date operateTime;
/** 配图配置存储JSON格式长文本 */
@TableField("CONFIG")
private String config;
/** 图片在服务器存储的KEY */
@TableField("IMAGE_KEY")
private String imageKey;
/** 创建时间 */
@TableField("CREATED_AT")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date createdAt;
/** 创建人关联SYS_USER.ID */
@TableField("RECORD_USER")
private String recordUser;
/** 创建人名称(非数据库字段) */
@TableField(exist = false)
private String recordUserName;
/** 更新人关联SYS_USER.ID */
@TableField("MODIFY_USER")
private String modifyUser;
/** 更新时间 */
@TableField("MODIFY_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date modifyTime;
/** 是否已删除0=未删除1=已删除 */
@TableField("IS_DELETED")
private Integer isDeleted;
/** 删除人关联SYS_USER.ID */
@TableField("DELETE_USER")
private String deleteUser;
/** 删除时间 */
@TableField("DELETE_TIME")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date deleteTime;
@TableField(exist = false)
private String bsfile;
@TableField(exist = false)
private String fileName;
}

View File

@ -0,0 +1,10 @@
package com.yfd.platform.qgc_env.si.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yfd.platform.qgc_env.si.entity.vo.SmartImageVo;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SmartImageMapper extends BaseMapper<SmartImageVo> {
}

View File

@ -0,0 +1,39 @@
package com.yfd.platform.qgc_env.si.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.qgc_env.si.entity.vo.SmartImageVo;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
/**
* 智能配图表 Service 接口
*
* @author migration
*/
public interface ISmartImageService extends IService<SmartImageVo> {
/**
* 条件过滤数据列表Kendo 数据源
*
* @param dataSourceRequest 数据源请求
* @return 数据源结果
*/
DataSourceResult<SmartImageVo> getKendoList(DataSourceRequest dataSourceRequest);
/**
* 批量删除
*
* @param ids 主键ID列表
*/
void deleteByIds(List<String> ids);
/**
* 保存或更新含附件上传
*
* @param smartImage 智能配图实体
*/
void saveWithAttachment(SmartImageVo smartImage);
}

View File

@ -0,0 +1,207 @@
package com.yfd.platform.qgc_env.si.service.impl;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yfd.platform.common.DataSourceLoadOptionsBase;
import com.yfd.platform.common.DataSourceRequest;
import com.yfd.platform.common.DataSourceResult;
import com.yfd.platform.common.exception.BizException;
import com.yfd.platform.common.utils.Base64MultipartFile;
import com.yfd.platform.qgc_data.service.AttachmentUploadService;
import com.yfd.platform.qgc_env.si.entity.vo.SmartImageVo;
import com.yfd.platform.qgc_env.si.mapper.SmartImageMapper;
import com.yfd.platform.qgc_env.si.service.ISmartImageService;
import com.yfd.platform.utils.DataSourceRequestUtil;
import com.yfd.platform.utils.QgcQueryWrapperUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
/**
* 智能配图表 Service 实现类
*
* @author migration
*/
@Service
@Slf4j
public class SmartImageServiceImpl extends ServiceImpl<SmartImageMapper, SmartImageVo> implements ISmartImageService {
@Resource
private AttachmentUploadService attachmentUploadService;
@Override
public DataSourceResult<SmartImageVo> getKendoList(DataSourceRequest dataSourceRequest) {
// 1. 构建查询条件
QueryWrapper<SmartImageVo> wrapper = DataSourceRequestUtil.buildQueryWrapper(
dataSourceRequest, SmartImageVo.class);
// 默认按创建时间倒序
wrapper.orderByDesc("CREATED_AT");
// 2. 分页参数处理
DataSourceLoadOptionsBase loadOptions = dataSourceRequest == null ? null : dataSourceRequest.toDevRequest();
Page<SmartImageVo> page = loadOptions == null ? null
: (Page<SmartImageVo>) QgcQueryWrapperUtil.buildPage(loadOptions, loadOptions.getSkip(), loadOptions.getTake());
// 3. 执行查询
Page<SmartImageVo> resultPage;
if (page != null) {
resultPage = this.page(page, wrapper);
} else {
List<SmartImageVo> list = this.list(wrapper);
resultPage = new Page<>();
resultPage.setRecords(list);
resultPage.setTotal(list.size());
}
// 4. 构建结果
DataSourceResult<SmartImageVo> dataSourceResult = new DataSourceResult<>();
dataSourceResult.setData(resultPage.getRecords());
dataSourceResult.setTotal(resultPage.getTotal());
return dataSourceResult;
}
@Override
public void saveWithAttachment(SmartImageVo smartImage) {
// 3. Base64 转换为 MultipartFile
MultipartFile file = null;
if (StrUtil.isNotBlank(smartImage.getBsfile())) {
try {
file = convertBase64ToMultipartFile(smartImage.getBsfile(), smartImage.getFileName());
} catch (Exception e) {
log.error("Base64 文件转换失败", e);
throw new BizException("文件解析失败,请检查 Base64 格式是否正确");
}
}
// 如果有附件上传并获取 attachmentId
if (file != null || !file.isEmpty()) {
try {
List<MultipartFile> files = new ArrayList<>();
files.add(file);
List<String> attachmentIds = attachmentUploadService.uploadMultipartFiles(files);
if (attachmentIds != null && !attachmentIds.isEmpty()) {
//如果是一条
smartImage.setImageKey(attachmentIds.get(0));
//如果是多条
//smartImage.setImageKey(String.valueOf(attachmentIds));
}
} catch (Exception e) {
log.error("附件上传失败", e);
}
}
this.saveOrUpdate(smartImage);
}
/**
* Base64 字符串转换为 MultipartFile
*
* @param base64 Base64 字符串可带 data:image/png;base64, 前缀
* @param fileName 文件名可空
* @return MultipartFile 对象
*/
private MultipartFile convertBase64ToMultipartFile(String base64, String fileName) {
try {
// 1. 去除 Base64 前缀如果有
String[] parts = base64.split(",");
String base64Data = parts.length > 1 ? parts[1] : parts[0];
// 2. 解码为字节数组
byte[] fileBytes = Base64.getDecoder().decode(base64Data);
// 3. 处理文件名
String originalFilename = fileName;
if (StrUtil.isBlank(originalFilename)) {
// 自动检测文件扩展名
String ext = detectExtension(base64);
originalFilename = System.currentTimeMillis() + (ext != null ? "." + ext : ".bin");
}
// 4. 检测 MIME 类型
String contentType = detectContentType(base64);
if (contentType == null) {
contentType = "application/octet-stream";
}
// 5. 返回自定义 MultipartFile 实现
return new Base64MultipartFile(
fileBytes,
"file", // 表单字段名
originalFilename,
contentType
);
} catch (IllegalArgumentException e) {
log.error("Base64 解码失败,可能数据不合法", e);
throw new BizException("Base64 编码数据格式错误,请检查");
} catch (Exception e) {
log.error("转换 MultipartFile 失败", e);
throw new BizException("文件转换失败:" + e.getMessage());
}
}
/**
* 根据 Base64 前缀检测文件扩展名
*/
private String detectExtension(String base64) {
if (base64.startsWith("data:image/jpeg") || base64.startsWith("data:image/jpg")) {
return "jpg";
} else if (base64.startsWith("data:image/png")) {
return "png";
} else if (base64.startsWith("data:image/gif")) {
return "gif";
} else if (base64.startsWith("data:image/bmp")) {
return "bmp";
} else if (base64.startsWith("data:application/pdf")) {
return "pdf";
} else if (base64.startsWith("data:application/msword")) {
return "doc";
} else if (base64.startsWith("data:application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
return "docx";
}
return null; // 默认无扩展名
}
/**
* 根据 Base64 前缀检测 MIME 类型
*/
private String detectContentType(String base64) {
if (base64.startsWith("data:image/jpeg") || base64.startsWith("data:image/jpg")) {
return "image/jpeg";
} else if (base64.startsWith("data:image/png")) {
return "image/png";
} else if (base64.startsWith("data:image/gif")) {
return "image/gif";
} else if (base64.startsWith("data:image/bmp")) {
return "image/bmp";
} else if (base64.startsWith("data:application/pdf")) {
return "application/pdf";
} else if (base64.startsWith("data:application/msword")) {
return "application/msword";
} else if (base64.startsWith("data:application/vnd.openxmlformats-officedocument.wordprocessingml.document")) {
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
}
return null;
}
@Override
public void deleteByIds(List<String> ids) {
List<SmartImageVo> list = this.listByIds(ids);
if (CollectionUtils.isEmpty(list)) {
return;
}
for (SmartImageVo entity : list) {
attachmentUploadService.deleteFile(entity.getImageKey());
}
for (String id : ids) {
this.removeById(id);
}
}
}