Browse Source

refactor(project): 修复遗留bug,更新项目文档

master
wangxiang 2 years ago
parent
commit
00a79772ca
  1. 138
      README.md
  2. 15
      kicc-platform/kicc-platform-api/kicc-system-api/src/main/java/com/cloud/kicc/system/api/entity/File.java
  3. 8
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/FileController.java
  4. 14
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/RegionController.java
  5. 61
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/UserController.java
  6. 2
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/service/FileService.java
  7. 34
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/service/impl/FileServiceImpl.java
  8. 52
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/util/ObjectUtil.java
  9. 11
      kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/test/testDemo.java

138
README.md

@ -1,49 +1,107 @@ @@ -1,49 +1,107 @@
# 🚀`kicc`(康来智慧冷链) 微服务架构平台 © 长沙康来生物有限公司版权所有
<h1 align="center">
<b>
<a href="https://godolphinx.org"><img src="https://godolphinx.org/images/dolphin-platform-logo.svg" /></a><br>
</b>
</h1>
## 💡 简介
服务于医疗智慧冷链行业微服务架构平台,目前采用最新微服务技术栈搭建,支持标本箱配送,监控,地图路线规划,
努力做成中国最好的智慧冷链平台。
<p align="center"> 一个快速开发软件的平台 </p>
## 🎡 功能特点
- 主体框架:采用最新的`Spring Cloud 2021.0.1`, `Spring Boot 2.6.4`, `Spring Cloud Alibaba 2021.1`版本进行系统设计;
<p align="center">
<a href="https://godolphinx.org/"><b>Website</b></a>
<a href="https://godolphinx.org/microservice/description.html"><b>Documentation</b></a>
</p>
- 统一注册:支持`Nacos`作为注册中心,实现多配置、分群组、分命名空间、多业务模块的注册和发现功能;
<div align="center">
<a href="https://godolphinx.org">
<img src="https://img.shields.io/npm/l/vue.svg?sanitize=true">
</a>
<a href="https://gitpod.io/#https://github.com/wangxiang4/dolphin">
<img src="https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod&style=flat-square">
</a>
<a href="https://discord.gg/DREuQWrRYQ">
<img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true"/>
</a>
</div>
- 统一认证:统一`Oauth2`认证协议,并支持自定义grant_type实现手机号码登录,第三方登录集成JustAuth实现微信、支付宝等多种登录模式;
## 🐬 介绍
海豚生态计划-打造一个web端,安卓端,ios端的一个海豚开发平台生态圈,不接收任何商业化,并且完全免费开源(包含高级功能)。
- 业务监控:利用`Spring Boot Admin`来监控各个独立Service的运行状态。
## 💪 愿景
让人人都可以快速高效的开发软件
## ✨ 特性
- 主体框架:采用最新的`Spring Cloud 2021.0.1`, `Spring Boot 2.6.4`, `Spring Cloud Alibaba 2021.1`版本进行系统设计。
- 统一注册:支持`Nacos`作为注册中心,实现多配置、分群组、分命名空间、多业务模块的注册和发现功能。
- 统一认证:统一`Oauth2`认证协议,并支持自定义grant_type实现手机号码登录,第三方登录集成JustAuth实现微信、支付宝等多种登录模式。
- 业务监控:利用`Spring Boot Admin`来监控各个独立微服务运行状态。
- 内部调用:集成了`Feign`与自定义内部注解,支持内部调用。
- 业务熔断:采用`Sentinel`实现业务熔断处理,避免服务之间出现雪崩。
- 在线文档:通过接入`Knife4j`,实现在线API文档的查看与调试。
- 业务分离:采用前后端分离的框架设计,提高开发效率、降低维护成本、增强系统稳定性和灵活性。
- 多租户功能:集成`Mybatis Plus`,自定义sql执行拦截器,实现SAAS多租户。
- 消息中间件:采用`RocketMQ`,实现服务之间消息转发。
- 分布式事物方案:采用`seata`,实现多个微服务分布式事物一致。
- 分布式定时器:采用`XXL-JOB`,实现多个微服务分布式任务调度。
- 微服务网关:采用`Spring Gateway`实现流量配置动态化、API管理和路由、负载均衡和容错、解决跨域问题、鉴权,限流,熔断,防火墙等等。
- 业务熔断:采用`Sentinel`实现业务熔断处理,避免服务之间出现雪崩;
- 在线文档:通过接入`Knife4j`,实现在线API文档的查看与调试;
- 业务分离:采用前后端分离的框架设计,前端采用基于 `vben Admin``kicc-ui`
- 多租户功能:集成`Mybatis Plus`,实现SAAS多租户功能
## 🎯 文件结构
```lua
kicc -- 父项目,各模块分离,方便集成和微服务
│ ├─kicc-auth -- 认证授权中心,基于 spring security oAuth2
│ ├─kicc-common -- 公共通用模块,主模块
│ │ ├─kicc-common-bom -- 全局jar BOM标准定义
│ │ ├─kicc-common-core -- 公共工具类核心包
│ │ ├─kicc-common-data -- 数据服务核心包
│ │ ├─kicc-common-datasource -- 动态切换数据源组件
│ │ ├─kicc-common-feign -- feign-sentinel服务降级熔断、限流组件
│ │ ├─kicc-common-job -- 定时任务,基于xxl-job
│ │ ├─kicc-common-log -- 日志服务
│ │ ├─kicc-common-mock -- 单元模拟测试工具类
│ │ ├─kicc-common-rocketmq -- 阿里 rocketmq 消息中间件
│ │ ├─kicc-common-seata -- 阿里巴巴-seata分布式事务解决方案
│ │ ├─kicc-common-security -- 安全工具类
│ │ ├─kicc-common-swagger -- 接口文档
│ │─kicc-common-demo -- 组件使用案列
│ │─kicc-gateway -- 服务网关,基于 spring cloud gateway
│ │─kicc-register -- 注册配置中心
│ │─kicc-system -- 通用系统权限管理聚合模块
│ │─kicc-visual 图形化相关功能
## <img width="28" style="vertical-align:middle" src="https://godolphinx.org/images/hacktoberfest-logo.svg"> 黑客节
加入[Github HackToberFest](https://hacktoberfest.com/) 开始为此项目做出贡献.
## 🔨 开发目录
```
├─dolphin -- 父项目,各模块分离,方便微服务扩展
│ ├─doc -- 文档数据-包含项目的一些数据资料
│ ├─docker-cloud -- docker-compose容器配置
│ ├─dolphin-auth -- 认证授权中心,基于 spring security oAuth2
│ ├─dolphin-common -- 公共通用模块,主模块
│ │ ├─dolphin-common-bom -- 全局jar BOM标准定义
│ │ ├─dolphin-common-core -- 公共工具类核心包
│ │ ├─dolphin-common-data -- 数据服务核心包
│ │ ├─dolphin-common-datasource -- 动态切换数据源组件
│ │ ├─dolphin-common-feign -- feign-sentinel服务降级熔断、限流组件
│ │ ├─dolphin-common-job -- 定时任务,基于xxl-job
│ │ ├─dolphin-common-log -- 日志服务
│ │ ├─dolphin-common-mock -- 单元模拟测试工具类
│ │ ├─dolphin-common-rocketmq -- 阿里 rocketmq 消息中间件
│ │ ├─dolphin-common-seata -- 阿里巴巴-seata分布式事务解决方案
│ │ ├─dolphin-common-security -- 安全工具类
│ │ ├─dolphin-common-swagger -- 接口文档
│ │─dolphin-common-demo -- 组件使用案列
│ │ ├─dolphin-common-demo-mq -- 消息中心间演示
│ │ ├─dolphin-common-demo-seata -- 分布式事务解决方案演示
│ │─dolphin-gateway -- 服务网关,基于 spring cloud gateway
│ │─ddolphin-platform -- 微服务平台
│ │ ├─dolphin-platform-api -- 微服务api调用(添加调用的微服务api依赖库,实现调用)
│ │ │ ├─dolphin-common-api -- 通用业务模块公共api模块
│ │ │ ├─dolphin-monitor-api -- 运维监控api模块
│ │ │ ├─dolphin-system-api -- 系统api模块
│ │ │ ├─dolphin-template-api -- 新建api模块模板,只提供基础依赖
│ │ ├─dolphin-platform-biz -- 微服务业务模块
│ │ │ ├─dolphin-common-biz -- 通用业务模块
│ │ │ ├─dolphin-monitor-biz -- 运维监控业务模块
│ │ │ ├─dolphin-system-biz -- 系统业务模块
│ │ │ ├─dolphin-template-biz -- 新建业务模块模板,只提供基础依赖
│ │─dolphin-register -- 注册配置中心
│ │─dolphin-visual 可视化图形界面
│ │ ├─dolphin-rocketmq-dashboard -- RocketMQ可视化监控平台
│ │ ├─dolphin-sentinel-dashboard -- 哨兵流量控制可视化平台
│ │ ├─dolphin-spring-dashboard -- SpringBoot可视化监控平台
│ │ ├─dolphin-xxl-job-admin -- XXL-JOB可视化监控平台
```
## 🤔 一起讨论
加入我们的 [Discord](https://discord.gg/DREuQWrRYQ) 开始与大家交流。
## 🤗 我想成为开发团队的一员!
欢迎😀!我们正在寻找有才华的开发者加入我们,让海豚开发平台变得更好!如果您想加入开发团队,请联系我们,非常欢迎您加入我们!💖
## 在线一键设置
您可以使用 Gitpod,一个在线 IDE(开源免费)来在线贡献或运行示例。
[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/wangxiang4/dolphin)
## 📄 执照
[Dolphin Development Platform 是获得MIT许可](https://github.com/wangxiang4/dolphin/blob/master/LICENSE) 的开源软件 。

15
kicc-platform/kicc-platform-api/kicc-system-api/src/main/java/com/cloud/kicc/system/api/entity/File.java

@ -54,4 +54,19 @@ public class File extends CommonEntity { @@ -54,4 +54,19 @@ public class File extends CommonEntity {
*/
private Long fileSize;
/**
* 有效原始路径
*/
private String availablePath;
/**
* 视频时长
*/
private Long duration;
/**
* 媒体资源类型
*/
private String mimeType;
}

8
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/FileController.java

@ -2,6 +2,7 @@ package com.cloud.kicc.system.controller; @@ -2,6 +2,7 @@ package com.cloud.kicc.system.controller;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@ -23,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile; @@ -23,6 +24,7 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Optional;
/**
*<p>
@ -53,10 +55,12 @@ public class FileController { @@ -53,10 +55,12 @@ public class FileController {
}
@PostMapping("/upload")
public Map upload(@RequestPart("file") MultipartFile file) {
return fileService.uploadFile(file);
public File upload(@RequestPart("file") MultipartFile file,
@RequestParam(value = "ossFile", required=false) String ossFile) {
return fileService.uploadFile(file, Optional.ofNullable(ossFile).map(item -> JSONUtil.parseObj(ossFile).toBean(File.class)).orElse(null));
}
@Inner(false)
@GetMapping("/getFile/{bucket}/{fileName}")
public void getById(@PathVariable String bucket, @PathVariable String fileName, HttpServletResponse response) {

14
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/RegionController.java

@ -9,9 +9,10 @@ import com.cloud.kicc.system.api.entity.Region; @@ -9,9 +9,10 @@ import com.cloud.kicc.system.api.entity.Region;
import com.cloud.kicc.system.api.vo.ResultVo;
import com.cloud.kicc.system.service.RegionService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import com.cloud.dolphin.system.util.ObjectUtil;
import java.util.List;
/**
@ -38,15 +39,22 @@ public class RegionController { @@ -38,15 +39,22 @@ public class RegionController {
.orderByAsc(Region::getSort);
}
@ApiOperation("查询")
@GetMapping("/list")
public R list(Region region) {
List<Region> result = regionService.list(getQueryWrapper(region));
return R.ok(result, result.size());
}
@ApiOperation("懒加载查询")
@GetMapping("/lazyList")
public R lazyList(String parentId){
return R.ok(regionService.lazyList(parentId));
public R lazyList(Region region) throws IllegalAccessException {
String[] fields = {"name", "code", "beginTime", "endTime" };
List<Region> result;
if (ObjectUtil.isAnyFieldsNotNull(region, fields)) {
result = regionService.list(getQueryWrapper(region));
} else result = regionService.lazyList(region.getParentId());
return R.ok(result, result.size());
}
@Inner

61
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/controller/UserController.java

@ -8,15 +8,16 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers; @@ -8,15 +8,16 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cloud.kicc.common.core.api.R;
import com.cloud.kicc.common.core.constant.AppConstants;
import com.cloud.kicc.common.data.entity.KiccUser;
import com.cloud.kicc.common.core.exception.CheckedException;
import com.cloud.kicc.common.log.annotation.SysLog;
import com.cloud.kicc.common.security.annotation.Inner;
import com.cloud.kicc.common.security.util.SecurityUtils;
import com.cloud.kicc.system.api.entity.Menu;
import com.cloud.kicc.system.api.entity.Role;
import com.cloud.kicc.system.api.entity.User;
import com.cloud.kicc.system.api.entity.UserRole;
import com.cloud.kicc.system.api.vo.ResultVo;
import com.cloud.kicc.system.service.FileService;
import com.cloud.kicc.system.service.MenuService;
import com.cloud.kicc.system.service.RoleService;
import com.cloud.kicc.system.service.UserRoleService;
import com.cloud.kicc.system.service.UserService;
@ -29,11 +30,8 @@ import org.springframework.security.access.prepost.PreAuthorize; @@ -29,11 +30,8 @@ import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.stream.Collectors;
/**
@ -52,7 +50,7 @@ public class UserController { @@ -52,7 +50,7 @@ public class UserController {
private final UserService userService;
private final UserRoleService userRoleService;
private final RoleService roleService;
private final FileService fileService;
private final MenuService menuService;
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
private LambdaQueryWrapper<User> getQueryWrapper(User user) {
@ -124,7 +122,7 @@ public class UserController { @@ -124,7 +122,7 @@ public class UserController {
return R.ok(userService.getUserAuthority(user));
}
@SysLog("用户修改管理用户角色表")
@SysLog("用户修改")
@PutMapping("/update")
@PreAuthorize("@pms.hasPermission('user_edit')")
public R update(@RequestBody User user) {
@ -132,14 +130,6 @@ public class UserController { @@ -132,14 +130,6 @@ public class UserController {
return R.ok();
}
@SysLog("用户修改")
@PutMapping("/updateUser")
@PreAuthorize("@pms.hasPermission('user_edit')")
public R updateUser(@RequestBody User user) {
userService.updateById(user);
return R.ok();
}
@SysLog("用户删除")
@DeleteMapping("/remove/{ids:[\\w,]+}")
@PreAuthorize("@pms.hasPermission('user_del')")
@ -152,26 +142,6 @@ public class UserController { @@ -152,26 +142,6 @@ public class UserController {
return R.ok();
}
@GetMapping("/profile")
public R profile() {
KiccUser kiccUser = SecurityUtils.getUser();
if (kiccUser != null) {
ResultVo resultVo = new ResultVo();
User user = userService.getById(kiccUser.getId());
if (user != null) {
String roleNames = SecurityUtils.getRoles()
.stream().map(roleId -> roleService.getById(roleId).getName())
.collect(Collectors.joining(","));
user.setPassword(null);
resultVo.setResult(user);
resultVo.setExtend(roleNames);
}
return R.ok(resultVo);
} else {
return R.error("登录信息已过期,请重新登录");
}
}
@SysLog("用户信息修改")
@PutMapping("/updateProfile")
@PreAuthorize("@pms.hasPermission('user_edit')")
@ -184,13 +154,6 @@ public class UserController { @@ -184,13 +154,6 @@ public class UserController {
return R.ok();
}
@SysLog("用户头像修改")
@PutMapping("/updateAvatar")
@PreAuthorize("@pms.hasPermission('user_edit')")
public Map updateAvatar(@RequestParam("avatarFile") MultipartFile file) {
return fileService.uploadFile(file);
}
@SysLog("用户密码修改")
@PutMapping("/updatePwd")
@PreAuthorize("@pms.hasPermission('user_edit')")
@ -233,7 +196,19 @@ public class UserController { @@ -233,7 +196,19 @@ public class UserController {
@GetMapping("/changeTenant/{tenantIds:[\\w,]+}")
@PreAuthorize("@pms.hasPermission('user_edit')")
public R changeTenant(@PathVariable String[] tenantIds) {
String originTenantIds = SecurityUtils.getUser().getTenantId();
userService.setCurrentUserTenant(tenantIds);
try {
// 检测切换的多租户下是否已经配置好了基础数据,没配置会导致系统直接404
Set<Menu> menuSet = new HashSet();
SecurityUtils.getRoles().forEach(roleId -> menuSet.addAll(menuService.selectMenuListByRoleId(roleId)));
List<Menu> menuList = menuSet.stream().sorted(Comparator.comparingInt(Menu::getSort)).collect(Collectors.toList());
List<Menu> menus = menuService.buildMenuTree(menuList, "0");
if (menus.isEmpty()) throw new CheckedException();
} catch (Exception e) {
userService.setCurrentUserTenant(originTenantIds);
return R.error("请联系管理员,配置当前多租户下的基础数据!");
}
return R.ok();
}

2
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/service/FileService.java

@ -23,7 +23,7 @@ public interface FileService extends IService<File> { @@ -23,7 +23,7 @@ public interface FileService extends IService<File> {
* @param file
* @return
*/
Map uploadFile(MultipartFile file);
File uploadFile(MultipartFile file, File ossFile);
/**
* 读取文件

34
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/service/impl/FileServiceImpl.java

@ -1,5 +1,7 @@ @@ -1,5 +1,7 @@
package com.cloud.kicc.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
@ -41,20 +43,24 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi @@ -41,20 +43,24 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
private final OssTemplate ossTemplate;
@Override
public Map uploadFile(MultipartFile file) {
public File uploadFile(MultipartFile file, File ossFile) {
String fileName = IdUtil.simpleUUID() + StrUtil.DOT + FileUtil.extName(file.getOriginalFilename());
Map<String, String> resultMap = new HashMap<>(4);
resultMap.put("bucketName", ossProperties.getBucketName());
resultMap.put("fileName", fileName);
resultMap.put("url", String.format("/system_proxy/system/file/getFile/%s/%s", ossProperties.getBucketName(), fileName));
File defaultOssFile = new File().setFileName(fileName)
.setBucketName(ossProperties.getBucketName())
.setOriginal(file.getOriginalFilename())
.setType(FileUtil.extName(file.getOriginalFilename()))
.setFileSize(file.getSize())
.setAvailablePath(String.format("/system_proxy/system/file/getFile/%s/%s", ossProperties.getBucketName(), fileName))
.setMimeType(file.getContentType());
if(ObjectUtil.isNotEmpty(ossFile)) BeanUtil.copyProperties(ossFile, defaultOssFile, CopyOptions.create().ignoreNullValue().ignoreError());
try {
ossTemplate.putObject(ossProperties.getBucketName(), fileName, file.getContentType(), file.getInputStream());
// 文件管理数据记录,收集管理追踪文件
fileLog(file, fileName);
this.save(defaultOssFile);
} catch (Exception e) {
throw new CheckedException("上传失败");
}
return resultMap;
return defaultOssFile;
}
@Override
@ -78,18 +84,4 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi @@ -78,18 +84,4 @@ public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements Fi
}
}
/**
* 文件管理数据记录,收集管理追踪文件
* @param file 上传文件格式
* @param fileName 文件名
*/
private void fileLog(MultipartFile file, String fileName) {
this.save(new File()
.setFileName(fileName)
.setOriginal(file.getOriginalFilename())
.setFileSize(file.getSize())
.setType(FileUtil.extName(file.getOriginalFilename()))
.setBucketName(ossProperties.getBucketName()));
}
}

52
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/java/com/cloud/kicc/system/util/ObjectUtil.java

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
package com.cloud.dolphin.system.util;
import cn.hutool.core.util.StrUtil;
import lombok.experimental.UtilityClass;
import java.lang.reflect.Field;
@UtilityClass
public class ObjectUtil {
/**
* 判断对象的多个属性是否为空
*
* @param obj 对象
* @param fieldNames 属性名数组
* @return true所有属性其中一个不为空 false所有属性都为空
* @throws IllegalAccessException
*/
public static boolean isAnyFieldsNotNull(Object obj, String[] fieldNames) throws IllegalAccessException {
for (String fieldName : fieldNames) {
Field field = getField(obj, fieldName);
field.setAccessible(true);
if (field != null) {
Object fieldValue = field.get(obj);
if (fieldValue != null && StrUtil.isNotBlank(fieldValue.toString())) {
return true;
}
}
}
return false;
}
/**
* 根据属性名获取对象的属性值
*
* @param obj 对象
* @param fieldName 属性名
* @return Field对象
*/
private static Field getField(Object obj, String fieldName) {
Class<?> clazz = obj.getClass();
while (clazz != null) {
try {
return clazz.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
clazz = clazz.getSuperclass();
}
}
return null;
}
}

11
kicc-platform/kicc-platform-biz/kicc-system-biz/src/main/test/testDemo.java

@ -1,11 +0,0 @@ @@ -1,11 +0,0 @@
/**
* @Author: lizhi
* @Description:
* @Since 1.0
* @Date Created in 11:04 2022/6/29
*/
public class testDemo {
public static void main(String[] args) {
}
}
Loading…
Cancel
Save