Commit a7cdce49 by xlx

feat(system): 添加应用管理功能模块

- 移除所有模块的banner.txt文件
- 新增BaseDTO基类包含创建和更新时间字段
- 重命名BaseIdDto为BaseIdDTO
- 创建BasicApp实体类用于应用管理
- 实现BasicAppController提供分页、详情和保存接口
- 添加BasicAppConvertor转换器处理对象映射
- 创建BasicAppMapper数据访问接口
- 定义BasicAppPageReq和BasicAppPageVO分页参数和结果类
- 实现BasicAppService业务逻辑包含分页查询和保存功能
- 创建BasicAppSetting实体用于应用设置
- 实现BasicAppSettingController和BasicAppSettingService
- 定义BasicAppViewVO详情视图对象
- 在file模块配置中添加数据库和Redis连接配置
- 修改system模块bootstrap.yml中的API文档扫描路径
- 移除file模块中的旧文件上传工具类和配置
- 更新auth模块登录控制器请求路径
- 在file模块中集成X文件存储组件并移除旧文件服务实现
- 更新file模块pom.xml移除Minio依赖配置
parent bf67c4d3
Showing with 864 additions and 762 deletions
......@@ -20,21 +20,21 @@ import com.matchtech.system.api.factory.RemoteFileFallbackFactory;
@FeignClient(contextId = "remoteFileService", value = ServiceNameConstants.FILE_SERVICE, fallbackFactory = RemoteFileFallbackFactory.class)
public interface RemoteFileService
{
/**
* 上传文件
*
* @param file 文件信息
* @return 结果
*/
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public R<SysFile> upload(@RequestPart(value = "file") MultipartFile file);
/**
* 删除文件
*
* @param fileUrl 文件地址
* @return 结果
*/
@DeleteMapping(value = "/delete", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public R<Boolean> delete(@RequestParam("fileUrl") String fileUrl);
// /**
// * 上传文件
// *
// * @param file 文件信息
// * @return 结果
// */
// @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
// public R<SysFile> upload(@RequestPart(value = "file") MultipartFile file);
//
// /**
// * 删除文件
// *
// * @param fileUrl 文件地址
// * @return 结果
// */
// @DeleteMapping(value = "/delete", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
// public R<Boolean> delete(@RequestParam("fileUrl") String fileUrl);
}
......@@ -25,17 +25,18 @@ public class RemoteFileFallbackFactory implements FallbackFactory<RemoteFileServ
log.error("文件服务调用失败:{}", throwable.getMessage());
return new RemoteFileService()
{
@Override
public R<SysFile> upload(MultipartFile file)
{
return R.fail("上传文件失败:" + throwable.getMessage());
}
@Override
public R<Boolean> delete(String fileUrl)
{
return R.fail("删除文件失败:" + throwable.getMessage());
}
// @Override
// public R<SysFile> upload(MultipartFile file)
// {
// return R.fail("上传文件失败:" + throwable.getMessage());
// }
//
// @Override
// public R<Boolean> delete(String fileUrl)
// {
// return R.fail("删除文件失败:" + throwable.getMessage());
// }
//
};
}
}
......@@ -23,7 +23,7 @@ import org.springframework.web.bind.annotation.RestController;
@Tag(name = "系统登录")
@RestController
@RequestMapping(value = "a/sys/")
@RequestMapping(value = "/a/sys/")
public class LocalLoginController extends BaseController {
@Autowired
......
package com.matchtech.common.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* @author lixl
*/
@Data
public class BaseDTO implements Serializable {
private static final long serialVersionUID = 1L;
private String id;
/**
* 创建时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
private Date createTime;
/**
* 创建者
*
*/
private String createUserId;
/**
* 创建人姓名
*/
private String createUser;
/**
* 最后更新时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh", timezone = "GMT+8")
private Date updateTime;
/**
* 更新者
*
*/
private String updateUserId;
/**
* 修改人姓名
*/
private String updateUser;
}
\ No newline at end of file
......@@ -10,7 +10,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BaseIdDto {
public class BaseIdDTO {
@Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
private String id;
......
......@@ -47,19 +47,32 @@
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Minio -->
<!-- &lt;!&ndash; matchtech Api System &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.matchtech</groupId>-->
<!-- <artifactId>matchtech-api-system</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-spring</artifactId>
<version>2.1.0</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.16.1</version>
</dependency>
<!-- matchtech Api System -->
<dependency>
<groupId>com.matchtech</groupId>
<artifactId>matchtech-api-system</artifactId>
<artifactId>matchtech-common-mybatis</artifactId>
</dependency>
<dependency>
<groupId>com.matchtech</groupId>
<artifactId>matchtech-common-core</artifactId>
</dependency>
</dependencies>
<build>
......
package com.matchtech.file;
import org.dromara.x.file.storage.spring.EnableFileStorage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
......@@ -9,7 +10,8 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
*
* @author matchtech
*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class })
@SpringBootApplication(scanBasePackages = {"com.matchtech"})
@EnableFileStorage
public class MatchtechFileApplication
{
public static void main(String[] args)
......
package com.matchtech.file.config;
import java.util.HashMap;
import java.util.Map;
import jakarta.servlet.DispatcherType;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.matchtech.file.filter.RefererFilter;
/**
* Filter配置
*
* @author matchtech
*/
@Configuration
public class FilterConfig
{
/**
* 资源映射路径 前缀
*/
@Value("${file.prefix}")
public String localFilePrefix;
@Value("${referer.allowed-domains}")
private String allowedDomains;
@SuppressWarnings({"rawtypes", "unchecked"})
@Bean
@ConditionalOnProperty(value = "referer.enabled", havingValue = "true")
public FilterRegistrationBean refererFilterRegistration()
{
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setDispatcherTypes(DispatcherType.REQUEST);
registration.setFilter(new RefererFilter());
registration.addUrlPatterns(localFilePrefix + "/*");
registration.setName("refererFilter");
registration.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE);
Map<String, String> initParameters = new HashMap<String, String>();
initParameters.put("allowedDomains", allowedDomains);
registration.setInitParameters(initParameters);
return registration;
}
}
package com.matchtech.file.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.minio.MinioClient;
/**
* Minio 配置信息
*
* @author matchtech
*/
@Configuration
@ConfigurationProperties(prefix = "minio")
public class MinioConfig
{
/**
* 服务地址
*/
private String url;
/**
* 用户名
*/
private String accessKey;
/**
* 密码
*/
private String secretKey;
/**
* 存储桶名称
*/
private String bucketName;
public String getUrl()
{
return url;
}
public void setUrl(String url)
{
this.url = url;
}
public String getAccessKey()
{
return accessKey;
}
public void setAccessKey(String accessKey)
{
this.accessKey = accessKey;
}
public String getSecretKey()
{
return secretKey;
}
public void setSecretKey(String secretKey)
{
this.secretKey = secretKey;
}
public String getBucketName()
{
return bucketName;
}
public void setBucketName(String bucketName)
{
this.bucketName = bucketName;
}
@Bean
public MinioClient getMinioClient()
{
return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
}
}
package com.matchtech.file.config;
import java.io.File;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 通用映射配置
*
* @author matchtech
*/
@Configuration
public class ResourcesConfig implements WebMvcConfigurer
{
/**
* 上传文件存储在本地的根路径
*/
@Value("${file.path}")
private String localFilePath;
/**
* 资源映射路径 前缀
*/
@Value("${file.prefix}")
public String localFilePrefix;
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry)
{
/** 本地文件上传路径 */
registry.addResourceHandler(localFilePrefix + "/**")
.addResourceLocations("file:" + localFilePath + File.separator);
}
/**
* 开启跨域
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
// 设置允许跨域的路由
registry.addMapping(localFilePrefix + "/**")
// 设置允许跨域请求的域名
.allowedOrigins("*")
// 设置允许的方法
.allowedMethods("GET");
}
}
\ No newline at end of file
package com.matchtech.file.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.matchtech.common.core.web.controller.BaseController;
import com.matchtech.common.dto.BaseIdDTO;
import com.matchtech.common.dto.page.resp.ApiResponseEntity;
import com.matchtech.common.dto.page.resp.ApiResponseUtils;
import com.matchtech.file.domain.SysFileDto;
import com.matchtech.file.service.SysFileService;
import com.matchtech.file.service.SysFileUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
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.RestController;
import org.springframework.web.multipart.MultipartFile;
import com.matchtech.common.core.domain.R;
import com.matchtech.common.core.utils.StringUtils;
import com.matchtech.common.core.utils.file.FileUtils;
import com.matchtech.file.service.ISysFileService;
import com.matchtech.system.api.domain.SysFile;
/**
* 文件请求处理
*
* @author matchtech
*/
@Tag(name = "系统文件管理")
@RestController
public class SysFileController
{
private static final Logger log = LoggerFactory.getLogger(SysFileController.class);
@RequestMapping(value = "${matchtech.adminPath}/sys/file")
public class SysFileController extends BaseController {
@Autowired
private ISysFileService sysFileService;
private SysFileService sysFileService;
@Autowired
private SysFileUtil sysFileUtil;
/**
* 文件上传请求
*/
@PostMapping("upload")
public R<SysFile> upload(MultipartFile file)
{
try
{
// 上传并返回访问地址
String url = sysFileService.uploadFile(file);
SysFile sysFile = new SysFile();
sysFile.setName(FileUtils.getName(url));
sysFile.setUrl(url);
return R.ok(sysFile);
}
catch (Exception e)
{
log.error("上传文件失败", e);
return R.fail(e.getMessage());
}
@Operation(summary = "统一文件上传")
@PostMapping("uploadFile")
public ApiResponseEntity<SysFileDto> uploadFile(MultipartFile file) {
SysFileDto data = sysFileUtil.uploadFile(file);
return ApiResponseUtils.success(data);
}
/**
* 文件删除请求
*/
@DeleteMapping("delete")
public R<Boolean> delete(String fileUrl)
{
try
{
if (!FileUtils.validateFilePath(fileUrl))
{
throw new Exception(StringUtils.format("资源文件({})非法,不允许删除。 ", fileUrl));
}
sysFileService.deleteFile(fileUrl);
return R.ok();
}
catch (Exception e)
{
log.error("删除文件失败", e);
return R.fail(e.getMessage());
}
@Operation(summary = "根据ID获取图片路径")
@PostMapping("view")
public ApiResponseEntity<SysFileDto> uploadFile(@RequestBody BaseIdDTO baseIdDto) {
SysFileDto data = sysFileService.view(baseIdDto.getId());
return ApiResponseUtils.success(data);
}
}
package com.matchtech.file.convertors;
import com.matchtech.file.domain.SysFileDto;
import com.matchtech.file.domain.SysFileEntity;
import org.dromara.x.file.storage.core.FileInfo;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.factory.Mappers;
@Mapper
public interface SysFileConvertor {
SysFileConvertor INSTANCE = Mappers.getMapper(SysFileConvertor.class);
SysFileDto convertorToSysFileDto(SysFileEntity sysFileEntity);
SysFileDto convertorToSysFileDto(FileInfo sysFileEntity);
}
\ No newline at end of file
package com.matchtech.file.domain;
import lombok.Data;
@Data
public class SysFileDto {
private String id; //id
private String originalName; //文件原始名称
private String fileName; //文件名称
private String mine; //文件格式
private String url; //文件地址
private String remarks; //备注
private String platform; //平台
private String basePath; //基础路径
private String fullPath; //完整路径
}
package com.matchtech.file.domain;
import com.baomidou.mybatisplus.annotation.TableName;
import com.matchtech.common.mybatis.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_file")
public class SysFileEntity extends BaseEntity {
private String originalName; //文件原始名称
private String fileName; //文件名称
private String mine; //文件格式
private String url; //文件地址
private String remarks; //备注
private String platform; //平台
private String basePath; //基础路径
}
package com.matchtech.file.filter;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
/**
* 防盗链过滤器
*
* @author matchtech
*/
public class RefererFilter implements Filter
{
/**
* 允许的域名列表
*/
public List<String> allowedDomains;
@Override
public void init(FilterConfig filterConfig) throws ServletException
{
String domains = filterConfig.getInitParameter("allowedDomains");
this.allowedDomains = Arrays.asList(domains.split(","));
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
String referer = req.getHeader("Referer");
// 如果Referer为空,拒绝访问
if (referer == null || referer.isEmpty())
{
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer header is required");
return;
}
// 检查Referer是否在允许的域名列表中
boolean allowed = false;
for (String domain : allowedDomains)
{
if (referer.contains(domain))
{
allowed = true;
break;
}
}
// 根据检查结果决定是否放行
if (allowed)
{
chain.doFilter(request, response);
}
else
{
resp.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied: Referer '" + referer + "' is not allowed");
}
}
@Override
public void destroy()
{
}
}
\ No newline at end of file
package com.matchtech.file.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.matchtech.file.domain.SysFileEntity;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SysFileMapper extends BaseMapper<SysFileEntity> {
}
package com.matchtech.file.service;
import org.springframework.web.multipart.MultipartFile;
/**
* 文件上传接口
*
* @author matchtech
*/
public interface ISysFileService
{
/**
* 文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
public String uploadFile(MultipartFile file) throws Exception;
/**
* 文件删除接口
*
* @param fileUrl 文件访问URL
* @throws Exception
*/
public void deleteFile(String fileUrl) throws Exception;
}
package com.matchtech.file.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.matchtech.common.core.utils.StringUtils;
import com.matchtech.common.core.utils.file.FileUtils;
import com.matchtech.file.utils.FileUploadUtils;
/**
* 本地文件存储
*
* @author matchtech
*/
@Primary
@Service
public class LocalSysFileServiceImpl implements ISysFileService
{
/**
* 资源映射路径 前缀
*/
@Value("${file.prefix}")
public String localFilePrefix;
/**
* 域名或本机访问地址
*/
@Value("${file.domain}")
public String domain;
/**
* 上传文件存储在本地的根路径
*/
@Value("${file.path}")
private String localFilePath;
/**
* 本地文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public String uploadFile(MultipartFile file) throws Exception
{
String name = FileUploadUtils.upload(localFilePath, file);
String url = domain + localFilePrefix + name;
return url;
}
/**
* 本地文件删除接口
*
* @param fileUrl 文件访问URL
* @throws Exception
*/
@Override
public void deleteFile(String fileUrl) throws Exception
{
String localFile = StringUtils.substringAfter(fileUrl, localFilePrefix);
FileUtils.deleteFile(localFilePath + localFile);
}
}
package com.matchtech.file.service;
import java.io.InputStream;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.nacos.common.utils.IoUtils;
import com.matchtech.common.core.utils.StringUtils;
import com.matchtech.file.config.MinioConfig;
import com.matchtech.file.utils.FileUploadUtils;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
/**
* Minio 文件存储
*
* @author matchtech
*/
@Service
public class MinioSysFileServiceImpl implements ISysFileService
{
@Autowired
private MinioConfig minioConfig;
@Autowired
private MinioClient client;
/**
* Minio文件上传接口
*
* @param file 上传的文件
* @return 访问地址
* @throws Exception
*/
@Override
public String uploadFile(MultipartFile file) throws Exception
{
InputStream inputStream = null;
try
{
String fileName = FileUploadUtils.extractFilename(file);
inputStream = file.getInputStream();
PutObjectArgs args = PutObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(fileName)
.stream(inputStream, file.getSize(), -1)
.contentType(file.getContentType())
.build();
client.putObject(args);
return minioConfig.getUrl() + "/" + minioConfig.getBucketName() + "/" + fileName;
}
catch (Exception e)
{
throw new RuntimeException("Minio Failed to upload file", e);
}
finally
{
IoUtils.closeQuietly(inputStream);
}
}
/**
* Minio文件删除接口
*
* @param fileUrl 文件访问URL
* @throws Exception
*/
@Override
public void deleteFile(String fileUrl) throws Exception
{
try
{
String minioFile = StringUtils.substringAfter(fileUrl, minioConfig.getBucketName());
client.removeObject(RemoveObjectArgs.builder().bucket(minioConfig.getBucketName()).object(minioFile).build());
}
catch (Exception e)
{
throw new RuntimeException("Minio Failed to delete file", e);
}
}
}
package com.matchtech.file.service;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.matchtech.file.convertors.SysFileConvertor;
import com.matchtech.file.domain.SysFileDto;
import com.matchtech.file.domain.SysFileEntity;
import com.matchtech.file.mapper.SysFileMapper;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.recorder.FileRecorder;
import org.dromara.x.file.storage.core.upload.FilePartInfo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.File;
import java.util.List;
@Service
@RequiredArgsConstructor
public class SysFileService extends ServiceImpl<SysFileMapper, SysFileEntity> implements FileRecorder {
@Value("${dromara.x-file-storage.local-plus[0].storage-path}")
private String tempPath;
public String getPath(String business) {
//没有业务编码时,直接放置默认文件夹
if (StringUtils.isEmpty(business)) {
business = "file";
}
String path = tempPath + DateUtil.year(DateUtil.date()) + DateUtil.month(DateUtil.date())+ "/";
File dir = new File(path);
if (!dir.exists()) {
dir.mkdirs();
}
return path;
}
public SysFileDto view(String id) {
SysFileEntity sysFile = getById(id);
SysFileDto data = SysFileConvertor.INSTANCE.convertorToSysFileDto(sysFile);
//String fullUrl = localDomain + sysFile.getBasePath() + sysFile.getFileName();
//data.setFullPath(fullUrl);
return data;
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean save(FileInfo fileInfo) {
SysFileEntity sysFile = new SysFileEntity();
sysFile.setOriginalName(fileInfo.getOriginalFilename());
sysFile.setFileName(fileInfo.getFilename());
sysFile.setMine(fileInfo.getExt());
sysFile.setUrl(fileInfo.getUrl());
sysFile.setPlatform(fileInfo.getPlatform());
sysFile.setBasePath(fileInfo.getBasePath());
this.save(sysFile);
fileInfo.setId(sysFile.getId());
return Boolean.TRUE;
}
@Override
public void update(FileInfo fileInfo) {
}
@Override
public FileInfo getByUrl(String url) {
SysFileEntity sysFile = this.lambdaQuery().eq(SysFileEntity::getUrl, url).one();
FileInfo fileInfo = new FileInfo();
fileInfo.setId(sysFile.getId());
fileInfo.setUrl(sysFile.getUrl());
fileInfo.setFilename(sysFile.getFileName());
fileInfo.setOriginalFilename(sysFile.getOriginalName());
fileInfo.setBasePath(sysFile.getBasePath());
fileInfo.setPlatform(sysFile.getPlatform());
return fileInfo;
}
@Override
public boolean delete(String url) {
List<SysFileEntity> list = this.lambdaQuery().eq(SysFileEntity::getUrl, url).list();
list.forEach(sysFile -> {
this.removeById(sysFile);
});
return true;
}
@Override
public void saveFilePart(FilePartInfo filePartInfo) {
}
@Override
public void deleteFilePartByUploadId(String uploadId) {
}
}
package com.matchtech.file.service;
import com.matchtech.file.convertors.SysFileConvertor;
import com.matchtech.file.domain.SysFileDto;
import com.matchtech.file.domain.SysFileEntity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.x.file.storage.core.FileInfo;
import org.dromara.x.file.storage.core.FileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@Component
@Slf4j
@RequiredArgsConstructor
public class SysFileUtil {
@Autowired
private FileStorageService fileStorageService;//注入实列
@Autowired
private SysFileService sysFileService;
public SysFileDto uploadFile(MultipartFile file) {
FileInfo fileInfo = fileStorageService.of(file).upload();
SysFileDto data = SysFileConvertor.INSTANCE.convertorToSysFileDto(fileInfo);
return data;
}
public SysFileDto uploadFile(File file) {
//fileStorageService.download(fileInfo.getUrl()).outputStream("C:\\Users\\lixl\\Desktop\\test.xlsx");
FileInfo fileInfo = fileStorageService.of(file).upload();
SysFileDto data = SysFileConvertor.INSTANCE.convertorToSysFileDto(fileInfo);
return data;
}
@Transactional(rollbackFor = Exception.class)
public void deleteByFileId(String fileId) {
SysFileEntity sysFile = sysFileService.getById(fileId);
if(sysFile != null){
try {
fileStorageService.delete(sysFile.getUrl());
}catch (Exception e){
log.info("文件不存在,{}",sysFile.getUrl());
}
}
}
}
package com.matchtech.file.utils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.Objects;
import org.apache.commons.io.FilenameUtils;
import org.springframework.web.multipart.MultipartFile;
import com.matchtech.common.core.exception.file.FileException;
import com.matchtech.common.core.exception.file.FileNameLengthLimitExceededException;
import com.matchtech.common.core.exception.file.FileSizeLimitExceededException;
import com.matchtech.common.core.exception.file.InvalidExtensionException;
import com.matchtech.common.core.utils.DateUtils;
import com.matchtech.common.core.utils.StringUtils;
import com.matchtech.common.core.utils.file.FileTypeUtils;
import com.matchtech.common.core.utils.file.MimeTypeUtils;
import com.matchtech.common.core.utils.uuid.Seq;
/**
* 文件上传工具类
*
* @author matchtech
*/
public class FileUploadUtils
{
/**
* 默认大小 50M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;
/**
* 默认的文件名最大长度 100
*/
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
/**
* 根据文件路径上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @return 文件名称
* @throws IOException
*/
public static final String upload(String baseDir, MultipartFile file) throws IOException
{
try
{
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
}
catch (FileException fe)
{
throw new IOException(fe.getDefaultMessage(), fe);
}
catch (Exception e)
{
throw new IOException(e.getMessage(), e);
}
}
/**
* 文件上传
*
* @param baseDir 相对应用的基目录
* @param file 上传的文件
* @param allowedExtension 上传文件类型
* @return 返回上传成功的文件名
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws FileNameLengthLimitExceededException 文件名太长
* @throws IOException 比如读写文件出错时
* @throws InvalidExtensionException 文件校验异常
*/
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
InvalidExtensionException
{
int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
{
throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
}
assertAllowed(file, allowedExtension);
String fileName = extractFilename(file);
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
file.transferTo(Paths.get(absPath));
return getPathFileName(fileName);
}
/**
* 编码文件名
*/
public static final String extractFilename(MultipartFile file)
{
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), FileTypeUtils.getExtension(file));
}
private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
{
File desc = new File(uploadDir + File.separator + fileName);
if (!desc.exists())
{
if (!desc.getParentFile().exists())
{
desc.getParentFile().mkdirs();
}
}
return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
}
private static final String getPathFileName(String fileName) throws IOException
{
String pathFileName = "/" + fileName;
return pathFileName;
}
/**
* 文件大小校验
*
* @param file 上传的文件
* @throws FileSizeLimitExceededException 如果超出最大大小
* @throws InvalidExtensionException 文件校验异常
*/
public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
throws FileSizeLimitExceededException, InvalidExtensionException
{
long size = file.getSize();
if (size > DEFAULT_MAX_SIZE)
{
throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
}
String fileName = file.getOriginalFilename();
String extension = FileTypeUtils.getExtension(file);
if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
{
if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
{
throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
fileName);
}
else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
{
throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
fileName);
}
else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
{
throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
fileName);
}
else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
{
throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
fileName);
}
else
{
throw new InvalidExtensionException(allowedExtension, extension, fileName);
}
}
}
/**
* 判断MIME类型是否是允许的MIME类型
*
* @param extension 上传文件类型
* @param allowedExtension 允许上传文件类型
* @return true/false
*/
public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
{
for (String str : allowedExtension)
{
if (str.equalsIgnoreCase(extension))
{
return true;
}
}
return false;
}
}
\ No newline at end of file
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_ __ _ _
(_) / _|(_)| |
_ __ _ _ ___ _ _ _ ______ | |_ _ | | ___
| '__|| | | | / _ \ | | | || ||______|| _|| || | / _ \
| | | |_| || (_) || |_| || | | | | || || __/
|_| \__,_| \___/ \__, ||_| |_| |_||_| \___|
__/ |
|___/
\ No newline at end of file
......@@ -23,3 +23,61 @@ spring:
# 共享配置
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
datasource:
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@139.9.72.99:1521:ORCL?currentSchema=LOWPARTS&allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: lowparts
password: lowparts2025
druid:
initial-size: 5
min-idle: 5
maxActive: 20
maxWait: 60000
connectTimeout: 30000
socketTimeout: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,slf4j
connectionProperties: druid.stat.mergeSql\=true;druid.stat.slowSqlMillis\=5000
redis:
host: localhost
port: 6379
# mybatis配置
mybatis-plus:
configuration:
map-underscore-to-camel-case: true
auto-mapping-behavior: full
use-generated-keys: true
mapper-locations: classpath:mapper/**/*.xml
type-aliases-package: com.matchtech.system.entity
# =======================文件上传===================
dromara:
x-file-storage: #文件存储配置
default-platform: local-plus-1 #默认使用的存储平台
thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】
local-plus:
- platform: local-plus-1 # 存储平台标识
enable-storage: true #启用存储
enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)
domain: http://127.0.0.1:9999/file/file/ # 访问域名,例如:“http://127.0.0.1:8030/file/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名
base-path: local-plus/ # 基础路径
path-patterns: /file/** # 访问路径
storage-path: /home/projects/file/Temp/ # 存储路径
aliyun-oss:
- platform: aliyun-oss-1 # 存储平台标识
enable-storage: true # 启用存储
access-key: ??
secret-key: ??
end-point: ??
bucket-name: ??
domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
base-path: test/ # 基础路径
# =======================文件上传===================
\ No newline at end of file
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_ _ _
(_) (_) | |
_ __ _ _ ___ _ _ _ ______ _ ___ | |__
| '__|| | | | / _ \ | | | || ||______| | | / _ \ | '_ \
| | | |_| || (_) || |_| || | | || (_) || |_) |
|_| \__,_| \___/ \__, ||_| | | \___/ |_.__/
__/ | _/ |
|___/ |__/
\ No newline at end of file
package com.matchtech.system.controller;
import com.matchtech.common.core.web.controller.BaseController;
import com.matchtech.common.dto.BaseIdDTO;
import com.matchtech.common.dto.page.PageReqDto;
import com.matchtech.common.dto.page.PageResult;
import com.matchtech.common.dto.page.resp.ApiResponseEntity;
import com.matchtech.system.convertors.BasicAppConvertor;
import com.matchtech.system.domain.vo.BasicAppPageReq;
import com.matchtech.system.domain.vo.BasicAppPageVO;
import com.matchtech.system.domain.vo.BasicAppViewVO;
import com.matchtech.system.service.BasicAppService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
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.RestController;
/**
* <p>
* 应用管理 前端控制器
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@RestController
@RequestMapping("${matchtech.adminPath}/basic-app")
@Tag(name = "应用管理")
@RequiredArgsConstructor
public class BasicAppController extends BaseController {
private final BasicAppService basicAppService;
@PostMapping("/page")
@Operation(summary = "应用管理分页")
public ApiResponseEntity<PageResult<BasicAppPageVO>> page(@RequestBody PageReqDto<BasicAppPageReq> pageReq) {
PageResult<BasicAppPageVO> pageResult = basicAppService.getPage(pageReq);
return ApiResponseEntity.success(pageResult);
}
@PostMapping("/view")
@Operation(summary = "应用管理详情")
public ApiResponseEntity<BasicAppViewVO> view(@RequestBody BaseIdDTO req) {
BasicAppViewVO pageResult = basicAppService.view(req.getId());
return ApiResponseEntity.success(pageResult);
}
@PostMapping("/save")
@Operation(summary = "应用管理保存")
public ApiResponseEntity<BasicAppViewVO> save(@RequestBody BasicAppViewVO req) {
basicAppService.edit(req);
return ApiResponseEntity.success();
}
}
package com.matchtech.system.controller;
import com.matchtech.common.core.web.controller.BaseController;
import com.matchtech.system.service.BasicAppSettingService;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* <p>
* 应用管理设置 前端控制器
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@RestController
@RequestMapping("${matchtech.adminPath}/basic-app-setting")
@Tag(name = "应用管理设置")
@RequiredArgsConstructor
public class BasicAppSettingController extends BaseController{
private final BasicAppSettingService basicAppSettingService;
}
......@@ -7,7 +7,7 @@ import com.matchtech.common.dto.page.resp.ApiResponseEntity;
import com.matchtech.common.dto.page.resp.ApiResponseUtils;
import com.matchtech.common.core.utils.StringUtils;
import com.matchtech.common.core.web.controller.BaseController;
import com.matchtech.common.dto.BaseIdDto;
import com.matchtech.common.dto.BaseIdDTO;
import com.matchtech.system.api.model.LoginUser;
import com.matchtech.system.entity.SysUserEntity;
import com.matchtech.system.service.SysUserService;
......@@ -33,7 +33,7 @@ public class SysUserController extends BaseController {
@Operation(summary = "用户详情")
@PostMapping("/detail")
@Schema(description = "用户详情")
public ApiResponseEntity<SysUserEntity> detail(@RequestBody BaseIdDto baseIdDto) {
public ApiResponseEntity<SysUserEntity> detail(@RequestBody BaseIdDTO baseIdDto) {
return ApiResponseUtils.success(sysUserService.getById(baseIdDto.getId()));
}
......
package com.matchtech.system.convertors;
import com.matchtech.common.dto.login.SysUserDetailVo;
import com.matchtech.common.dto.page.PageResult;
import com.matchtech.system.domain.vo.BasicAppPageVO;
import com.matchtech.system.domain.vo.BasicAppViewVO;
import com.matchtech.system.entity.BasicApp;
import com.matchtech.system.entity.SysUserEntity;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
/**
* @author lixl
*/
@Mapper
public interface BasicAppConvertor {
BasicAppConvertor INSTANCE = Mappers.getMapper(BasicAppConvertor.class);
PageResult<BasicAppPageVO> toPage(PageResult<BasicApp> basicAppPageResult);
BasicAppViewVO toView(BasicApp basicApp);
BasicApp toEnt(BasicAppViewVO req);
}
......@@ -9,19 +9,6 @@ import org.mapstruct.factory.Mappers;
public interface SysUserConvertor {
SysUserConvertor INSTANCE = Mappers.getMapper(SysUserConvertor.class);
//@Mapping(source = "companyId", target = "hahaId")
// SysUserExportDto convertorToSysUserDto(SysUserEntity user);
// SysUserEntity convertorToSysUserEntity(SysUserAddDto sysUserAddDto);
// SysUserEntity convertorToSysUserEntity(SysUserEditDto sysUserEditDto);
SysUserDetailVo convertorToSysUserDetailVo(SysUserEntity sysUser);
// List<SysUserExportDto> convertorToSysUserExportDtoList(List<SysUserEntity> user);
// List<SysUserListVo> convertorToSysUserVoList(List<SysUserEntity> user);
// CurrentUserDTO toCurrentUserDTO(SysUserEntity sysUserEntity);
}
package com.matchtech.system.domain.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.matchtech.common.dto.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author lixl
*/
@Data
@Schema(title="BasicAppPageReq", description="应用管理分页参数")
public class BasicAppPageReq {
@Schema(description = "应用名称")
private String code;
@Schema(description = "显示名称")
private String name;
}
package com.matchtech.system.domain.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.matchtech.common.dto.BaseDTO;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author lixl
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(title="BasicAppPageVO", description="应用管理分页VO")
public class BasicAppPageVO extends BaseDTO {
@Schema(description = "应用名称")
private String code;
@Schema(description = "显示名称")
private String name;
@Schema(description = "图标ID")
private String iconFileId;
@Schema(description = "描述")
private String remark;
@Schema(description = "状态 1-正常 0-其他")
private String status;
}
package com.matchtech.system.domain.vo;
import com.baomidou.mybatisplus.annotation.TableField;
import com.matchtech.common.dto.BaseDTO;
import com.matchtech.system.entity.BasicAppSetting;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* @author lixl
*/
@Data
@EqualsAndHashCode(callSuper = true)
@Schema(title="BasicAppViewVO", description="应用管理详情VO")
public class BasicAppViewVO extends BaseDTO {
@Schema(description = "应用名称")
private String code;
@Schema(description = "显示名称")
private String name;
@Schema(description = "图标ID")
private String iconFileId;
@Schema(description = "描述")
private String remark;
@Schema(description = "状态 1-正常 0-其他")
private String status;
@Schema(description = "应用设置")
private List<BasicAppSetting> basicAppSettingList;
}
package com.matchtech.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.matchtech.common.mybatis.domain.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 应用管理
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("BASIC_APP")
@Schema(title="BasicApp对象", description="应用管理")
public class BasicApp extends BaseEntity {
@Schema(description = "应用名称")
@TableField("CODE")
private String code;
@Schema(description = "显示名称")
@TableField("NAME")
private String name;
@Schema(description = "图标ID")
@TableField("ICON_FILE_ID")
private String iconFileId;
@Schema(description = "描述")
@TableField("REMARK")
private String remark;
@Schema(description = "状态 1-正常 0-其他")
@TableField("STATUS")
private String status;
}
package com.matchtech.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.matchtech.common.mybatis.domain.BaseEntity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* <p>
* 应用管理设置
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("BASIC_APP_SETTING")
@Schema(title="BasicAppSetting对象", description="应用管理设置")
public class BasicAppSetting extends BaseEntity {
@Schema(description = "前端模块")
@TableField("FRONT_MODULE")
private String frontModule;
@Schema(description = "前端路径")
@TableField("FRONT_URL")
private String frontUrl;
@Schema(description = "应用管理表ID")
@TableField("BASIC_APP_ID")
private String basicAppId;
}
package com.matchtech.system.mapper;
import com.matchtech.common.mybatis.BaseMapperX;
import com.matchtech.system.entity.BasicApp;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 应用管理 Mapper 接口
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@Mapper
public interface BasicAppMapper extends BaseMapperX<BasicApp> {
}
package com.matchtech.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.matchtech.system.entity.BasicAppSetting;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 应用管理设置 Mapper 接口
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@Mapper
public interface BasicAppSettingMapper extends BaseMapper<BasicAppSetting> {
}
package com.matchtech.system.service;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.matchtech.common.dto.BaseIdDTO;
import com.matchtech.common.dto.page.PageReqDto;
import com.matchtech.common.dto.page.PageResult;
import com.matchtech.common.mybatis.LambdaQueryWrapperX;
import com.matchtech.common.mybatis.domain.BaseEntity;
import com.matchtech.system.convertors.BasicAppConvertor;
import com.matchtech.system.domain.vo.BasicAppPageReq;
import com.matchtech.system.domain.vo.BasicAppPageVO;
import com.matchtech.system.domain.vo.BasicAppViewVO;
import com.matchtech.system.entity.BasicApp;
import com.matchtech.system.entity.BasicAppSetting;
import com.matchtech.system.mapper.BasicAppMapper;
import com.matchtech.system.mapper.BasicAppSettingMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
/**
* <p>
* 应用管理 服务实现类
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@Service
@RequiredArgsConstructor
public class BasicAppService extends ServiceImpl<BasicAppMapper, BasicApp> {
private final BasicAppSettingMapper basicAppSettingMapper;
public PageResult<BasicAppPageVO> getPage(PageReqDto<BasicAppPageReq> pageReq) {
BasicAppPageReq search = pageReq.getSearch();
LambdaQueryWrapperX<BasicApp> basicOrgLambdaQueryWrapperX = new LambdaQueryWrapperX<BasicApp>()
.likeIfPresent(BasicApp::getCode, search.getCode())
.likeIfPresent(BasicApp::getName, search.getName())
.orderByDesc(BaseEntity::getUpdateTime);
PageResult<BasicApp> basicAppPageResult = baseMapper.selectPage(pageReq, basicOrgLambdaQueryWrapperX);
PageResult<BasicAppPageVO> res = BasicAppConvertor.INSTANCE.toPage(basicAppPageResult);
return res;
}
public BasicAppViewVO view(String id) {
BasicApp basicApp = this.getById(id);
if(basicApp == null){
return null;
}
BasicAppViewVO basicAppViewVO = BasicAppConvertor.INSTANCE.toView(basicApp);
List<BasicAppSetting> basicAppSettingList = basicAppSettingMapper.selectList(Wrappers.lambdaQuery(BasicAppSetting.class).eq(BasicAppSetting::getBasicAppId, id));
basicAppViewVO.setBasicAppSettingList(basicAppSettingList);
return basicAppViewVO;
}
@Transactional
public void edit(BasicAppViewVO req) {
BasicApp basicApp = BasicAppConvertor.INSTANCE.toEnt(req);
this.saveOrUpdate(basicApp);
List<BasicAppSetting> basicAppSettingList = req.getBasicAppSettingList();
if(CollectionUtil.isEmpty(basicAppSettingList)){
basicAppSettingMapper.delete(Wrappers.lambdaQuery(BasicAppSetting.class).eq(BasicAppSetting::getBasicAppId, basicApp.getId()));
}else {
Set<String> settingIdSet = basicAppSettingList.stream().map(BaseEntity::getId).collect(Collectors.toSet());
settingIdSet.removeIf(Objects::isNull);
basicAppSettingMapper.delete(Wrappers.lambdaQuery(BasicAppSetting.class)
.eq(BasicAppSetting::getBasicAppId, basicApp.getId())
.notIn(CollectionUtil.isNotEmpty(settingIdSet), BasicAppSetting::getId, settingIdSet));
}
basicAppSettingMapper.insertOrUpdate(basicAppSettingList);
}
}
package com.matchtech.system.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.matchtech.system.entity.BasicAppSetting;
import com.matchtech.system.mapper.BasicAppSettingMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
* <p>
* 应用管理设置 服务实现类
* </p>
*
* @author MATCHTECH
* @since 2026-01-05
*/
@Service
@RequiredArgsConstructor
public class BasicAppSettingService extends ServiceImpl<BasicAppSettingMapper, BasicAppSetting>{
}
Spring Boot Version: ${spring-boot.version}
Spring Application Name: ${spring.application.name}
_ _
(_) | |
_ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___
| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \
| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | |
|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_|
__/ | __/ |
|___/ |___/
\ No newline at end of file
......@@ -43,6 +43,6 @@ springdoc:
path: /v3/api-docs
group-configs:
- group: 'default'
paths-to-match: '/order/**'
packages-to-scan: com.macro.cloud.controller
paths-to-match: '/system/**'
packages-to-scan: com.matchtech.system.controller
default-flat-param-object: false
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment