feat: 文件功能修改(#IC68N4),代码生成器移除,需要到ReadMe文档看下地址

This commit is contained in:
bunny 2025-05-09 16:18:10 +08:00
parent 74850cf795
commit 42b3a6d150
123 changed files with 1444 additions and 4912 deletions

View File

@ -128,7 +128,6 @@ http.authorizeHttpRequests(auth -> auth
graph TD
父工程 -->|主项目| auth-api
父工程 -->|代码生成器| generator-code
auth-api -->|启动项、控制器| service
service -->|mapper| dao
service -->|包含domain、配置等| auth-core

View File

@ -1,5 +1,6 @@
package cn.bunny.services;
import org.dromara.x.file.storage.spring.EnableFileStorage;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@ -11,6 +12,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@MapperScan("cn.bunny.services.mapper")
@ComponentScan("cn.bunny")
@EnableScheduling
@EnableFileStorage
@EnableCaching
@EnableTransactionManagement
@SpringBootApplication

View File

@ -1,4 +1,38 @@
# 生成系统需要的权限
# 文档包含配置和一些其他说明
## 文件上传配置
如果需要其他平台需要参考文档https://x-file-storage.xuyanwu.cn/#/。
因为按照要求,删除、更新操作需要实现接口,所以目前的`FileRecorder`是实现了的,在`FileDetailService`。
```yaml
# 可以配置很多但只能使用一个!!!其他平台参考官方文档
dromara:
x-file-storage: # 文件存储配置
default-platform: local-plus-1 # 默认使用的存储平台
# default-platform: minio-1 # 默认使用的存储平台
thumbnail-suffix: ".min.jpg" # 缩略图后缀,例如【.min.jpg】【.png】
local-plus:
- platform: local-plus-1 # 存储平台标识
enable-storage: true # 启用存储
enable-access: true # 启用访问(线上请使用 Nginx 配置,效率更高)
domain: ${dromara.local-plus.domain}
base-path: ${dromara.local-plus.base-path}
path-patterns: ${dromara.local-plus.path-patterns}
storage-path: ${dromara.local-plus.storage-path}
minio:
- platform: minio-1 # 存储平台标识
enable-storage: true # 启用存储
end-point: ${dromara.minio.endpointUrl}
domain: ${dromara.minio.endpointUrl}/${dromara.minio.bucket-name}
bucket-name: ${dromara.minio.bucket-name}
access-key: ${dromara.minio.accessKey}
secret-key: ${dromara.minio.secretKey}
base-path: ${dromara.minio.base-path}
```
## 生成系统需要的权限
```java
import cn.bunny.services.AuthServiceApplication;
@ -77,4 +111,59 @@ public class BuildPermissionApiTest {
});
}
}
```
## MInio权限设置
如果其他平台也需要,根据自己需求进行添加,不需要可以删除这个文件。
```java
/**
* 如果项目使用的是minio创建桶的时候需要设置公开权限
* 在这里初始化的时候会自动设置公开权限
*/
@Configuration
@ConditionalOnProperty(name = "dromara.x-file-storage.minio.bucket-name")
@Data
public class MinioConfiguration {
/* 地址 */
private String domain;
/* 访问秘钥 */
private String accessKey;
/* 私有秘钥 */
private String secretKey;
/* 桶名称 */
private String bucketName;
@Bean
public MinioClient minioClient() {
MinioClient minioClient = MinioClient.builder().endpoint(domain).credentials(accessKey, secretKey).build();
try {
// 判断桶是否存在,不存在则创建,并且可以有公开访问权限
boolean found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
if (!found) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
String publicPolicy = String.format("{\n" +
" \"Version\": \"2012-10-17\",\n" +
" \"Statement\": [\n" +
" {\n" +
" \"Effect\": \"Allow\",\n" +
" \"Principal\": \"*\",\n" +
" \"Action\": [\"s3:GetObject\"],\n" +
" \"Resource\": [\"arn:aws:s3:::%s/*\"]\n" +
" }\n" +
" ]\n" +
"}", bucketName);
minioClient.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucketName).config(publicPolicy).build());
}
} catch (Exception exception) {
exception.getStackTrace();
}
return minioClient;
}
}
```

View File

@ -1,17 +1,16 @@
package cn.bunny.services.controller.system;
package cn.bunny.services.controller.file;
import cn.bunny.services.domain.common.constant.MinioConstant;
import cn.bunny.services.domain.common.constant.FileStorageConstant;
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
import cn.bunny.services.domain.common.model.vo.result.PageResult;
import cn.bunny.services.domain.common.model.vo.result.Result;
import cn.bunny.services.domain.system.files.dto.FileUploadDto;
import cn.bunny.services.domain.system.files.dto.FilesAddDto;
import cn.bunny.services.domain.system.files.dto.FilesAddOrUpdateDto;
import cn.bunny.services.domain.system.files.dto.FilesDto;
import cn.bunny.services.domain.system.files.dto.FilesUpdateDto;
import cn.bunny.services.domain.system.files.entity.Files;
import cn.bunny.services.domain.system.files.vo.FileInfoVo;
import cn.bunny.services.domain.system.files.vo.FilesVo;
import cn.bunny.services.service.system.FilesService;
import cn.bunny.services.service.file.FilesService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
@ -23,7 +22,6 @@ import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* <p>
@ -56,14 +54,14 @@ public class FilesController {
@Operation(summary = "更新文件", description = "更新系统文件", tags = "files::update")
@PutMapping()
public Result<String> updateFiles(@Valid FilesUpdateDto dto) {
public Result<String> updateFiles(@Valid FilesAddOrUpdateDto dto) {
filesService.updateFiles(dto);
return Result.success(ResultCodeEnum.UPDATE_SUCCESS);
}
@Operation(summary = "添加文件", description = "添加系统文件", tags = "files::add")
@PostMapping()
public Result<Object> addFiles(@Valid FilesAddDto dto) {
public Result<Object> addFiles(@Valid FilesAddOrUpdateDto dto) {
filesService.addFiles(dto);
return Result.success(ResultCodeEnum.ADD_SUCCESS);
}
@ -81,17 +79,10 @@ public class FilesController {
return filesService.downloadFilesByFileId(fileId);
}
@Operation(summary = "获取所有文件类型", description = "获取所有文件类型", tags = "files::query")
@GetMapping("private/getMediaTypeList")
public Result<Set<String>> getMediaTypeList() {
Set<String> list = filesService.getMediaTypeList();
return Result.success(list);
}
@Operation(summary = "获取所有文件存储基础路径", description = "获取所有文件存储基础路径", tags = "files::query")
@GetMapping("private/getAllFilesStoragePath")
public Result<List<String>> getAllFilesStoragePath() {
Map<String, String> typeMap = MinioConstant.typeMap;
Map<String, String> typeMap = FileStorageConstant.typeMap;
List<String> list = typeMap.keySet().stream().toList();
return Result.success(list);

View File

@ -0,0 +1,69 @@
package cn.bunny.services.controller.file;
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
import cn.bunny.services.domain.common.model.vo.result.PageResult;
import cn.bunny.services.domain.common.model.vo.result.Result;
import cn.bunny.services.domain.system.files.dto.FilesParDetailDto;
import cn.bunny.services.domain.system.files.entity.FilesParDetail;
import cn.bunny.services.domain.system.files.vo.FilesParDetailVo;
import cn.bunny.services.service.file.FilesParDetailService;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>
* 文件分片信息表仅在手动分片上传时使用 前端控制器
* </p>
*
* @author Bunny
* @since 2025-05-08 23:01:19
*/
@Tag(name = "文件分片信息表,仅在手动分片上传时使用", description = "文件分片信息表,仅在手动分片上传时使用相关接口")
@RestController
@RequestMapping("/api/filesParDetail")
public class FilesParDetailController {
@Resource
private FilesParDetailService filesPardetailService;
@Operation(summary = "分页查询文件分片信息表,仅在手动分片上传时使用", description = "分页文件分片信息表,仅在手动分片上传时使用", tags = "filesParDetail::query")
@GetMapping("{page}/{limit}")
public Result<PageResult<FilesParDetailVo>> getFilesParDetailPage(
@Parameter(name = "page", description = "当前页", required = true)
@PathVariable("page") Integer page,
@Parameter(name = "limit", description = "每页记录数", required = true)
@PathVariable("limit") Integer limit,
FilesParDetailDto dto) {
Page<FilesParDetail> pageParams = new Page<>(page, limit);
PageResult<FilesParDetailVo> pageResult = filesPardetailService.getFilesParDetailPage(pageParams, dto);
return Result.success(pageResult);
}
@Operation(summary = "添加文件分片信息表,仅在手动分片上传时使用", description = "添加文件分片信息表,仅在手动分片上传时使用", tags = "filesParDetail::add")
@PostMapping()
public Result<String> addFilesParDetail(@Valid @RequestBody FilesParDetailDto dto) {
filesPardetailService.addFilesParDetail(dto);
return Result.success(ResultCodeEnum.ADD_SUCCESS);
}
@Operation(summary = "更新文件分片信息表,仅在手动分片上传时使用", description = "更新文件分片信息表,仅在手动分片上传时使用", tags = "filesParDetail::update")
@PutMapping()
public Result<String> updateFilesParDetail(@Valid @RequestBody FilesParDetailDto dto) {
filesPardetailService.updateFilesParDetail(dto);
return Result.success(ResultCodeEnum.UPDATE_SUCCESS);
}
@Operation(summary = "删除文件分片信息表,仅在手动分片上传时使用", description = "删除文件分片信息表,仅在手动分片上传时使用", tags = "filesParDetail::delete")
@DeleteMapping()
public Result<String> deleteFilesParDetail(@RequestBody List<Long> ids) {
filesPardetailService.deleteFilesParDetail(ids);
return Result.success(ResultCodeEnum.DELETE_SUCCESS);
}
}

View File

@ -31,11 +31,17 @@ bunny:
database: 0
password: "123456"
dromara:
local-plus:
# 访问域名例如“http://127.0.0.1:8030/file”注意后面要和 path-patterns 名字一样
domain: /api/local-file
# 访问路径使用本地在SpringSecurity中要配置权限如果是和我一样就不用修改了如果不是api开头上线需要配置nginx
path-patterns: /api/local-file/**
storage-path: D:/Temp # 存储路径
base-path: "" # 基础路径
minio:
endpointUrl: "http://192.168.3.137:9000" # 连接地址
accessKey: bunny # 用户名
secretKey: "12345678" # 登录密码
bucket-name: auth-admin # 指定哪个桶
backPath: "D:\\MyData\\backup"
base-path: "" # 基础路径

View File

@ -12,7 +12,9 @@ spring:
name: bunny-service
servlet:
multipart:
max-file-size: 6MB
max-file-size: 20MB
max-request-size: 20MB
resolve-lazily: true
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
@ -80,6 +82,29 @@ spring:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
# 可以配置很多但只能使用一个!!!其他平台参考官方文档
dromara:
x-file-storage: # 文件存储配置
default-platform: local-plus-1 # 默认使用的存储平台
# default-platform: minio-1 # 默认使用的存储平台
thumbnail-suffix: ".min.jpg" # 缩略图后缀,例如【.min.jpg】【.png】
local-plus:
- platform: local-plus-1 # 存储平台标识
enable-storage: true # 启用存储
enable-access: true # 启用访问(线上请使用 Nginx 配置,效率更高)
domain: ${dromara.local-plus.domain}
base-path: ${dromara.local-plus.base-path}
path-patterns: ${dromara.local-plus.path-patterns}
storage-path: ${dromara.local-plus.storage-path}
minio:
- platform: minio-1 # 存储平台标识
enable-storage: true # 启用存储
end-point: ${dromara.minio.endpointUrl}
domain: ${dromara.minio.endpointUrl}/${dromara.minio.bucket-name}
bucket-name: ${dromara.minio.bucket-name}
access-key: ${dromara.minio.accessKey}
secret-key: ${dromara.minio.secretKey}
base-path: ${dromara.minio.base-path}
mybatis-plus:
mapper-locations: classpath:mapper/**/*.xml

View File

@ -3,14 +3,6 @@
<head>
<meta charset="UTF-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<link crossorigin="anonymous" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" rel="stylesheet">
<script crossorigin="anonymous"
integrity="sha384-I7E8VVD/ismYTF4hNIPjVp/Zjvgyol6VFvRkX/vR+Vc4jQkC+hVqc2pM8ODewa9r"
src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
<script crossorigin="anonymous"
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy"
src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"></script>
<title>bunny-admin-server项目介绍</title>
<style>
body {
@ -54,6 +46,24 @@
color: white;
margin-top: 20px;
}
.btn {
padding: 9px;
background: transparent;
border: 1px solid #ccc;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
}
.btn-primary {
color: white;
background-color: #007BFF;
}
.btn-primary:hover {
background-color: #3498db;
}
</style>
</head>
<body>
@ -68,7 +78,8 @@
<ul>
<li>登录优化:使用登录策略方便以后扩展登录方式</li>
<li>邮件发送模板:邮件发送用的是模板方法模式</li>
<li>密码校验登录密码校验器改用自带的不是md5加密看起来像这样<code>$2a$10$h5BUwmMaVcEuu7Bz0TPPy.PQV8JP6CFJlbHTgT78G1s0YPIu2kfXe</code>
<li>密码校验登录密码校验器改用自带的不是md5加密看起来像这样<code>$2a$10$gD2mTVaqIjfgciN.5vQ7uemf.PYNYLFQL4BZdnYswZEjAuC543Vhe</code>
这个表示 <code>admin123</code> 的密码;重置或者登不进去就输入这个密码
</li>
<li>接口请求路径:将原本请求路径<code>/admin</code>改为<code>/api</code></li>
</ul>
@ -79,23 +90,7 @@
<div class="carousel-item active">
<img alt="验证码图片" class="d-block w-50" src="/public/checkCode" style="margin: 0 auto">
</div>
<div class="carousel-item">
<img alt="验证码图片" class="d-block w-50" src="/public/checkCode" style="margin: 0 auto">
</div>
<div class="carousel-item">
<img alt="验证码图片" class="d-block w-50" src="/public/checkCode" style="margin: 0 auto">
</div>
</div>
<button class="carousel-control-prev btn-link" data-bs-slide="prev" data-bs-target="#carouselExampleIndicators"
type="button">
<span aria-hidden="true" class="carousel-control-prev-icon"></span>
<span class="visually-hidden">Previous</span>
</button>
<button class="carousel-control-next" data-bs-slide="next" data-bs-target="#carouselExampleIndicators"
type="button">
<span aria-hidden="true" class="carousel-control-next-icon"></span>
<span class="visually-hidden">Next</span>
</button>
</div>
<h2>技术栈</h2>
@ -107,7 +102,7 @@
<a class="btn btn-primary"
target="_blank"
th:href="@{'http://localhost:'+${@environment.getProperty('server.port')}+'/swagger-ui/index.html'}">打开接口文档-swagger</a>
<a class="btn btn-success" href="http://bunny-web.site/" target="_blank">查看在线项目</a>
<a class="btn btn-primary" href="http://bunny-web.site/" target="_blank">查看在线项目</a>
<a class="btn btn-primary" href="http://localhost:7000/" target="_blank">查看本地项目</a>
</div>

View File

@ -119,6 +119,11 @@
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
</dependency>
<dependency>
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-spring</artifactId>
<version>2.2.1</version>
</dependency>
<!-- JWT -->
<dependency>

View File

@ -1,4 +1,4 @@
package cn.bunny.services.minio;
package cn.bunny.services.config;
import io.minio.BucketExistsArgs;
import io.minio.MakeBucketArgs;
@ -6,19 +6,21 @@ import io.minio.MinioClient;
import io.minio.SetBucketPolicyArgs;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 如果项目使用的是minio创建桶的时候需要设置公开权限
* 在这里初始化的时候会自动设置公开权限
* 不需要可以删除这个文件
*/
@Configuration
@ConfigurationProperties(prefix = "bunny.minio")
// 当属性有值时这个配置才生效
@ConditionalOnProperty(name = "bunny.minio.bucket-name")
@ConditionalOnProperty(name = "dromara.x-file-storage.minio.bucket-name")
@Data
public class MinioProperties {
public class MinioConfiguration {
/* 地址 */
private String endpointUrl;
private String domain;
/* 访问秘钥 */
private String accessKey;
/* 私有秘钥 */
@ -28,7 +30,7 @@ public class MinioProperties {
@Bean
public MinioClient minioClient() {
MinioClient minioClient = MinioClient.builder().endpoint(endpointUrl).credentials(accessKey, secretKey).build();
MinioClient minioClient = MinioClient.builder().endpoint(domain).credentials(accessKey, secretKey).build();
try {
// 判断桶是否存在不存在则创建并且可以有公开访问权限

View File

@ -0,0 +1,35 @@
package cn.bunny.services.domain.common.constant;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class FileStorageConstant {
public static final String FAVICON = "favicon";
public static final String AVATAR = "avatar";
public static final String MESSAGE = "message";
public static final String CAROUSEL = "carousel";
public static final String BACKUP = "backup";
public static final String IMAGES = "images";
public static final String VIDEO = "video";
public static final Map<String, String> typeMap = new HashMap<>();
static {
typeMap.put(FAVICON, "/" + FAVICON + "/");
typeMap.put(AVATAR, "/" + AVATAR + "/");
typeMap.put(MESSAGE, "/" + MESSAGE + "/");
typeMap.put(CAROUSEL, "/" + CAROUSEL + "/");
typeMap.put(BACKUP, "/" + BACKUP + "/");
typeMap.put(IMAGES, "/" + IMAGES + "/");
typeMap.put(VIDEO, "/" + VIDEO + "/");
typeMap.put("default", "/" + "default" + "/");
}
public static String getType(String type) {
String value = typeMap.get(type);
if (value != null) return value;
throw new RuntimeException("上传类型错误或缺失");
}
}

View File

@ -1,35 +0,0 @@
package cn.bunny.services.domain.common.constant;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
@Data
public class MinioConstant {
public static final String favicon = "favicon";
public static final String avatar = "avatar";
public static final String message = "message";
public static final String carousel = "carousel";
public static final String feedback = "feedback";
public static final String backup = "backup";
public static final Map<String, String> typeMap = new HashMap<>();
static {
typeMap.put(favicon, "/favicon/");
typeMap.put(avatar, "/avatar/");
typeMap.put(message, "/message/");
typeMap.put(carousel, "/carousel/");
typeMap.put(feedback, "/feedback/");
typeMap.put(backup, "/backup/");
typeMap.put("images", "/images/");
typeMap.put("video", "/video/");
typeMap.put("default", "/default/");
}
public static String getType(String type) {
String value = typeMap.get(type);
if (value != null) return value;
throw new RuntimeException("上传类型错误或缺失");
}
}

View File

@ -1,31 +0,0 @@
package cn.bunny.services.domain.common.model.dto.minio;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "MinioFilePath", title = "Minion上传返回西悉尼")
public class MinioUploadFileInfo {
@Schema(name = "filename", title = "文件名")
private String filename;
@Schema(name = "uuidFilename", title = "uuid文件名防止重复")
private String uuidFilename;
@Schema(name = "timeUuidFilename", title = "时间+uuid文件名")
private String timeUuidFilename;
@Schema(name = "filepath", title = "文件路径")
private String filepath;
@Schema(name = "bucketNameFilepath", title = "上传桶名称文件路径")
private String bucketNameFilepath;
}

View File

@ -24,4 +24,7 @@ public class FileUploadDto {
@NotBlank(message = "文件类型不能为空")
private String type;
@Schema(name = "platform", title = "指定的平台")
private String platform;
}

View File

@ -3,7 +3,6 @@ package cn.bunny.services.domain.system.files.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@ -15,7 +14,10 @@ import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Schema(name = "FilesAddDto对象", title = "添加文件", description = "添加文件")
public class FilesAddDto {
public class FilesAddOrUpdateDto {
@Schema(name = "id", title = "主键")
private Long id;
@Schema(name = "filepath", title = "文件在服务器上的存储路径")
@NotBlank(message = "存储路径不能为空")
@ -25,8 +27,10 @@ public class FilesAddDto {
@Min(value = 0L, message = "最小值为0")
private Integer downloadCount = 0;
@Schema(name = "files", title = "文件")
@NotEmpty(message = "文件不能为空")
@Schema(name = "files", title = "文件列表,添加时为列表")
private List<MultipartFile> files;
@Schema(name = "file", title = "文件,修改时为 file")
private MultipartFile file;
}

View File

@ -19,8 +19,14 @@ public class FilesDto {
@Schema(name = "filepath", title = "文件在服务器上的存储路径")
private String filepath;
@Schema(name = "fileType", title = "文件的MIME类型")
private String fileType;
@Schema(name = "contentType", title = "文件的MIME类型")
private String contentType;
@Schema(name = "ext", title = "扩展名")
private String ext;
@Schema(name = "platform", title = "存储平台")
private String platform;
@Schema(name = "downloadCount", title = "下载数量")
private Integer downloadCount;

View File

@ -0,0 +1,54 @@
package cn.bunny.services.domain.system.files.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "FilesParDetailDTO对象", title = "文件分片信息表,仅在手动分片上传时使用", description = "文件分片信息表仅在手动分片上传时使用的DTO对象")
public class FilesParDetailDto {
@Schema(name = "id", title = "分片id")
private String id;
@Schema(name = "platform", title = "存储平台")
private String platform;
@Schema(name = "uploadId", title = "上传ID仅在手动分片上传时使用")
private String uploadId;
@Schema(name = "eTag", title = "分片 ETag")
private String eTag;
@Schema(name = "partNumber", title = "分片号。每一个上传的分片都有一个分片号一般情况下取值范围是1~10000")
private Integer partNumber;
@Schema(name = "partSize", title = "文件大小,单位字节")
private Long partSize;
@Schema(name = "hashInfo", title = "哈希信息")
private String hashInfo;
@Schema(name = "createUser", title = "创建用户")
private Long createUser;
@Schema(name = "updateUser", title = "操作用户")
private Long updateUser;
@Schema(name = "createTime", title = "创建时间")
private LocalDateTime createTime;
@Schema(name = "updateTime", title = "记录文件最后修改的时间戳")
private LocalDateTime updateTime;
@Schema(name = "isDeleted", title = "文件是否被删除")
private Boolean isDeleted;
}

View File

@ -1,39 +0,0 @@
package cn.bunny.services.domain.system.files.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "FilesUpdateDto对象", title = "更新文件", description = "文件管理")
public class FilesUpdateDto {
@Schema(name = "id", title = "主键")
@NotNull(message = "id不能为空")
private Long id;
@Schema(name = "filename", title = "文件的名称")
@NotBlank(message = "文件的名称不能为空")
private String filename;
@Schema(name = "fileType", title = "文件的MIME类型")
@NotBlank(message = "文件类型不能为空")
private String fileType;
@Schema(name = "downloadCount", title = "下载数量")
@Min(value = 0L, message = "最小值为0")
private Integer downloadCount;
@Schema(name = "file", title = "文件")
private MultipartFile files;
}

View File

@ -0,0 +1,36 @@
package cn.bunny.services.domain.system.files.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.web.multipart.MultipartFile;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "UploadThumbnail对象", title = "上传图片文件")
public class UploadThumbnail {
@Schema(name = "file", title = "图片")
MultipartFile file;
@Schema(name = "preType", title = "类型(路径)")
String preType;
@Schema(name = "thumbnailSuffix", title = "缩略图后缀")
String thumbnailSuffix;
@Schema(name = "saveThFilename", title = "保存文件名称,不包含扩展名")
String saveThFilename;
@Schema(name = "thumbnailWidth", title = "宽度")
Integer thumbnailWidth;
@Schema(name = "thumbnailHeight", title = "高度")
Integer thumbnailHeight;
}

View File

@ -1,6 +1,7 @@
package cn.bunny.services.domain.system.files.entity;
import cn.bunny.services.domain.common.model.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
@ -8,38 +9,97 @@ import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
/**
* <p>
* 系统文件表
* </p>
*
* @author Bunny
* @since 2024-10-04
*/
@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
@Accessors(chain = true)
@TableName("sys_files")
@Schema(name = "Files对象", title = "系统文件表", description = "系统文件管理")
@Schema(name = "Files对象", title = "文件记录")
public class Files extends BaseEntity {
@Schema(name = "filename", title = "文件的名称")
@Schema(name = "thSize", title = "缩略图大小,单位字节")
private Long thSize;
@Schema(name = "size", title = "文件大小,单位字节")
private Long size;
@Schema(name = "fileSizeStr", title = "文件大小(字符串)")
private String fileSizeStr;
@Schema(name = "uploadStatus", title = "上传状态仅在手动分片上传时使用1初始化完成2上传完成")
private Integer uploadStatus;
@Schema(name = "filename", title = "文件名称")
private String filename;
@Schema(name = "filepath", title = "文件在服务器上的存储路径")
@Schema(name = "objectType", title = "文件所属对象类型,例如用户头像,评价图片")
private String objectType;
@Schema(name = "hashInfo", title = "哈希信息")
private String hashInfo;
@Schema(name = "platform", title = "存储平台")
private String platform;
@Schema(name = "thMetadata", title = "缩略图元数据")
private String thMetadata;
@Schema(name = "thUrl", title = "缩略图访问路径")
private String thUrl;
@Schema(name = "thUserMetadata", title = "缩略图用户元数据")
private String thUserMetadata;
@Schema(name = "uploadId", title = "上传ID仅在手动分片上传时使用")
private String uploadId;
@Schema(name = "fileAcl", title = "文件ACL")
private String fileAcl;
@Schema(name = "url", title = "文件访问地址")
private String url;
@Schema(name = "thFilename", title = "缩略图名称")
private String thFilename;
@Schema(name = "userMetadata", title = "文件用户元数据")
private String userMetadata;
@Schema(name = "filepath", title = "存储路径")
private String filepath;
@Schema(name = "fileSize", title = "文件的大小,以字节为单位")
private Long fileSize;
@Schema(name = "attr", title = "附加属性")
private String attr;
@Schema(name = "fileType", title = "文件的MIME类型")
private String fileType;
@Schema(name = "ext", title = "文件扩展名")
private String ext;
@Schema(name = "thContentType", title = "缩略图MIME类型")
private String thContentType;
@Schema(name = "metadata", title = "文件元数据")
private String metadata;
@Schema(name = "objectId", title = "文件所属对象id")
private String objectId;
@Schema(name = "downloadCount", title = "下载数量")
private Integer downloadCount;
@Schema(name = "isDeleted", title = "是否被删除")
@Schema(name = "thFileAcl", title = "缩略图文件ACL")
private String thFileAcl;
@Schema(name = "originalFilename", title = "原始文件名")
private String originalFilename;
@Schema(name = "contentType", title = "MIME类型")
private String contentType;
@Schema(name = "basePath", title = "基础存储路径")
private String basePath;
@Schema(name = "isDeleted", title = "文件是否被删除")
@TableField(exist = false)
private Boolean isDeleted;
}

View File

@ -0,0 +1,37 @@
package cn.bunny.services.domain.system.files.entity;
import cn.bunny.services.domain.common.model.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
@EqualsAndHashCode(callSuper = true)
@Getter
@Setter
@Accessors(chain = true)
@TableName("sys_files_part_detail")
@Schema(name = "FilesParDetail对象", title = "文件分片信息表,仅在手动分片上传时使用", description = "文件分片信息表,仅在手动分片上传时使用的实体类对象")
public class FilesParDetail extends BaseEntity {
@Schema(name = "platform", title = "存储平台")
private String platform;
@Schema(name = "uploadId", title = "上传ID仅在手动分片上传时使用")
private String uploadId;
@Schema(name = "eTag", title = "分片 ETag")
private String eTag;
@Schema(name = "partNumber", title = "分片号。每一个上传的分片都有一个分片号一般情况下取值范围是1~10000")
private Integer partNumber;
@Schema(name = "partSize", title = "文件大小,单位字节")
private Long partSize;
@Schema(name = "hashInfo", title = "哈希信息")
private String hashInfo;
}

View File

@ -15,22 +15,85 @@ import lombok.*;
@Schema(name = "FileInfoVo对象", title = "管理端返回文件信息", description = "管理端返回文件信息")
public class FileInfoVo extends BaseVo {
@Schema(name = "url", title = "文件的路径")
private String url;
@Schema(name = "thSize", title = "缩略图大小,单位字节")
private Long thSize;
@Schema(name = "filename", title = "文件的名称")
@Schema(name = "size", title = "文件大小,单位字节")
private Long size;
@Schema(name = "fileSizeStr", title = "文件大小(字符串)")
private String fileSizeStr;
@Schema(name = "uploadStatus", title = "上传状态仅在手动分片上传时使用1初始化完成2上传完成")
private Integer uploadStatus;
@Schema(name = "filename", title = "文件名称")
private String filename;
@Schema(name = "filepath", title = "文件在服务器上的存储路径")
@Schema(name = "objectType", title = "文件所属对象类型,例如用户头像,评价图片")
private String objectType;
@Schema(name = "hashInfo", title = "哈希信息")
private String hashInfo;
@Schema(name = "platform", title = "存储平台")
private String platform;
@Schema(name = "thMetadata", title = "缩略图元数据")
private String thMetadata;
@Schema(name = "thUrl", title = "缩略图访问路径")
private String thUrl;
@Schema(name = "thUserMetadata", title = "缩略图用户元数据")
private String thUserMetadata;
@Schema(name = "uploadId", title = "上传ID仅在手动分片上传时使用")
private String uploadId;
@Schema(name = "fileAcl", title = "文件ACL")
private String fileAcl;
@Schema(name = "url", title = "文件访问地址")
private String url;
@Schema(name = "thFilename", title = "缩略图名称")
private String thFilename;
@Schema(name = "userMetadata", title = "文件用户元数据")
private String userMetadata;
@Schema(name = "filepath", title = "存储路径")
private String filepath;
@Schema(name = "fileSize", title = "文件的大小,以字节为单位")
private Long fileSize;
@Schema(name = "attr", title = "附加属性")
private String attr;
@Schema(name = "size", title = "文件大小")
private String size;
@Schema(name = "ext", title = "文件扩展名")
private String ext;
@Schema(name = "fileType", title = "文件的MIME类型")
private String fileType;
@Schema(name = "thContentType", title = "缩略图MIME类型")
private String thContentType;
@Schema(name = "metadata", title = "文件元数据")
private String metadata;
@Schema(name = "objectId", title = "文件所属对象id")
private String objectId;
@Schema(name = "downloadCount", title = "下载数量")
private Integer downloadCount;
@Schema(name = "thFileAcl", title = "缩略图文件ACL")
private String thFileAcl;
@Schema(name = "originalFilename", title = "原始文件名")
private String originalFilename;
@Schema(name = "contentType", title = "MIME类型")
private String contentType;
@Schema(name = "basePath", title = "基础存储路径")
private String basePath;
}

View File

@ -0,0 +1,53 @@
package cn.bunny.services.domain.system.files.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Schema(name = "FilesParDetailVO对象", title = "文件分片信息表,仅在手动分片上传时使用", description = "文件分片信息表仅在手动分片上传时使用的VO对象")
public class FilesParDetailVo {
@Schema(name = "id", title = "分片id")
private String id;
@Schema(name = "platform", title = "存储平台")
private String platform;
@Schema(name = "uploadId", title = "上传ID仅在手动分片上传时使用")
private String uploadId;
@Schema(name = "eTag", title = "分片 ETag")
private String eTag;
@Schema(name = "partNumber", title = "分片号。每一个上传的分片都有一个分片号一般情况下取值范围是1~10000")
private Integer partNumber;
@Schema(name = "partSize", title = "文件大小,单位字节")
private Long partSize;
@Schema(name = "hashInfo", title = "哈希信息")
private String hashInfo;
@Schema(name = "createUser", title = "创建用户")
private Long createUser;
@Schema(name = "updateUser", title = "操作用户")
private Long updateUser;
@Schema(name = "createTime", title = "创建时间")
private LocalDateTime createTime;
@Schema(name = "updateTime", title = "记录文件最后修改的时间戳")
private LocalDateTime updateTime;
@Schema(name = "isDeleted", title = "文件是否被删除")
private Boolean isDeleted;
}

View File

@ -1,111 +0,0 @@
package cn.bunny.services.minio;
import cn.bunny.services.domain.common.constant.UserConstant;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@Component
public class MinioHelper {
@Resource
private MinioProperties properties;
/**
* 格式化用户头像URL
*
* <p>实现头像URL的统一存储和访问格式转换</p>
*
* <ol>
* <li><b>存储处理</b>将带HTTP前缀的头像URL转换为数据库存储格式
* <ul>
* <li>匹配正则表达式^https?://.*?/(.*)</li>
* <li>提取路径部分matcher.group(1)</li>
* <li>转换为存储格式"/" + 提取的路径</li>
* </ul>
* </li>
* <li><b>访问处理</b>返回带HTTP前缀的完整访问URL</li>
* </ol>
*
* <p>典型用例</p>
* <pre>
* 输入"http|s://example.com/images/avatar.jpg"
* 存储"images/avatar.jpg"
* 访问"http|s://xxx/images/avatar.jpg"
* </pre>
*
* @param avatar 头像URL可能包含HTTP前缀或数据库存储格式
* @return 格式化后的头像URL确保包含HTTP前缀
* @throws PatternSyntaxException 当正则表达式匹配失败时抛出
* @throws IllegalArgumentException 当头像参数为空时抛出
*/
public String formatUserAvatar(String avatar) {
// 如果用户没有头像或者用户头像和默认头像相同返回默认头像
String userAvatar = UserConstant.USER_AVATAR;
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
// 替换前端发送的host前缀将其删除只保留路径名称
String regex = "^https?://.*?/(.*)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(avatar);
// 如果没有匹配
if (!matcher.matches()) return avatar;
// 匹配后返回内容
return "/" + matcher.group(1);
}
/**
* 检查并格式化用户头像URL
*
* <p>处理逻辑</p>
* <ol>
* <li>当头像为空或与默认头像相同时返回系统默认头像</li>
* <li>尝试移除头像URL中的HTTP协议和域名部分如果存在</li>
* <li>最终返回MinIO存储中的完整对象访问路径</li>
* </ol>
*
* @param avatar 用户头像URL可能为以下格式
* - /null使用默认头像
* - 完整HTTP URL"http|s://example.com/images/1.jpg"
* - MinIO对象路径"images/1.jpg"
* @return 格式化后的头像URL保证是可访问的完整路径
* - 默认头像当输入无效时
* - MinIO完整访问路径处理成功时
* @see UserConstant#USER_AVATAR 默认头像常量
* @see #getObjectNameFullPath MinIO路径处理方法
*/
public String getUserAvatar(String avatar) {
// 如果用户没有头像或者用户头像和默认头像相同返回默认头像
String userAvatar = UserConstant.USER_AVATAR;
if (!StringUtils.hasText(avatar) || avatar.equals(userAvatar)) return userAvatar;
// 替换前端发送的host前缀将其删除只保留路径名称
String regex = "^https?://.*?/(.*)";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(avatar);
// 如果没有匹配
if (matcher.matches()) return avatar;
// 匹配后返回内容
return getObjectNameFullPath(avatar);
}
/**
* 获取Minio全路径名Object带有桶名称
*
* @param objectName 对象名称
* @return 全路径
*/
public String getObjectNameFullPath(String objectName) {
String url = properties.getEndpointUrl();
return url + objectName;
}
}

View File

@ -1,227 +0,0 @@
package cn.bunny.services.minio;
import cn.bunny.services.domain.common.constant.MinioConstant;
import cn.bunny.services.domain.common.model.dto.minio.MinioUploadFileInfo;
import cn.bunny.services.domain.common.enums.ResultCodeEnum;
import cn.bunny.services.exception.AuthCustomerException;
import io.minio.*;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;
/**
* Minio操作工具类 简化操作步骤
* 自定义封装
*/
@Slf4j
@Service
public class MinioService {
@Resource
private MinioProperties properties;
@Resource
private MinioClient minioClient;
/**
* 上传文件到MinIO并返回文件处理信息
*
* <p><b>文件存储规则</b></p>
* <ul>
* <li>按日期分目录存储格式yyyy/MM-dd</li>
* <li>使用UUID重命名文件防止冲突</li>
* <li>保留原始文件名信息</li>
* <li>支持按类型分类存储通过minioPreType参数</li>
* </ul>
*
* <p><b>返回信息包含</b></p>
* <ol>
* <li>原始文件名</li>
* <li>UUID重命名后的文件名</li>
* <li>带日期路径的文件名</li>
* <li>完整存储路径不含桶名</li>
* <li>完整访问路径含桶名</li>
* </ol>
*
* @param file 上传的文件对象不可为空
* @param minioPreType 文件类型前缀用于分类存储参考MinioConstant定义
* @return 文件处理信息对象包含各种路径信息当file为null时返回null
* @throws IOException 当文件流读取异常时抛出
* @throws AuthCustomerException 当上传失败时抛出错误码UPLOAD_ERROR
* @see MinioConstant 文件类型前缀常量
* @see MinioUploadFileInfo 返回信息数据结构
*/
public MinioUploadFileInfo uploadWithFileInfo(MultipartFile file, String minioPreType) throws IOException {
if (file == null) return null;
// 上传文件时的桶名称
String bucketName = properties.getBucketName();
// 上传对象
try {
String uuid = UUID.randomUUID().toString();
// 定义日期时间格式
String dateFormatter = new SimpleDateFormat("yyyy/MM-dd").format(new Date());
// 文件后缀
String extension = "";
// 原始文件名
String filename = file.getOriginalFilename();
if (StringUtils.hasText(filename) && filename.contains(".")) {
extension = "." + filename.substring(filename.lastIndexOf(".") + 1);
}
// UUID防止重名
String uuidFilename = uuid + extension;
// 拼接时间+UUID文件名 加上时间路径
String timeUuidFilename = dateFormatter + "/" + uuidFilename;
// 上传根文件夹+拼接时间+UUID文件名
String filepath = MinioConstant.getType(minioPreType) + timeUuidFilename;
// 桶名称+上传根文件夹+拼接时间+UUID文件名
String buckNameFilepath = "/" + bucketName + MinioConstant.getType(minioPreType) + timeUuidFilename;
// 设置及Minio基础信息
MinioUploadFileInfo minioUploadFIleInfo = new MinioUploadFileInfo();
minioUploadFIleInfo.setFilename(filename);
minioUploadFIleInfo.setUuidFilename(uuidFilename);
minioUploadFIleInfo.setTimeUuidFilename(timeUuidFilename);
minioUploadFIleInfo.setFilepath(filepath);
minioUploadFIleInfo.setBucketNameFilepath(buckNameFilepath);
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(minioUploadFIleInfo.getFilepath()).stream(file.getInputStream(), file.getSize(), -1).build());
return minioUploadFIleInfo;
} catch (Exception exception) {
throw new AuthCustomerException(ResultCodeEnum.UPLOAD_ERROR);
}
}
/**
* 获取默认存储桶中的文件字节数组
*
* <p><b>注意</b>会一次性读取全部文件内容到内存大文件慎用</p>
*
* @param objectName 对象全路径名称包含目录路径
* @return 文件内容的字节数组
* @throws AuthCustomerException 当获取失败时抛出错误码{@link ResultCodeEnum#GET_BUCKET_EXCEPTION}
*/
public byte[] getBucketObjectByte(String objectName) {
String bucketName = properties.getBucketName();
try {
GetObjectResponse getObjectResponse = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
return getObjectResponse.readAllBytes();
} catch (Exception exception) {
exception.printStackTrace();
}
throw new AuthCustomerException(ResultCodeEnum.GET_BUCKET_EXCEPTION);
}
/**
* 上传文件到指定存储桶
*
* @param bucketName 存储桶名称
* @param filename 对象存储路径包含文件名
* @param inputStream 文件输入流调用方负责关闭
* @param size 文件大小字节
* @throws AuthCustomerException 当上传失败时抛出错误码{@link ResultCodeEnum#UPLOAD_ERROR}
*/
public void putObject(String bucketName, String filename, InputStream inputStream, Long size) {
try {
minioClient.putObject(PutObjectArgs.builder().bucket(bucketName).object(filename).stream(inputStream, size, -1).build());
} catch (Exception exception) {
log.error("上传文件失败:{}", (Object) exception.getStackTrace());
throw new AuthCustomerException(ResultCodeEnum.UPLOAD_ERROR);
}
}
/**
* 批量删除存储桶中的对象文件
*
* @param list 要删除的对象路径列表
* @throws AuthCustomerException 当删除失败时抛出包含错误对象信息
*/
public void removeObjects(List<String> list) {
try {
String bucketName = properties.getBucketName();
List<DeleteObject> objectList = list.stream().map(DeleteObject::new).toList();
Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(objectList).build());
for (Result<DeleteError> result : results) {
DeleteError error = result.get();
throw new AuthCustomerException("Error in deleting object " + error.objectName() + "; " + error.message());
}
} catch (Exception exception) {
exception.printStackTrace();
}
}
/**
* 更新存储桶中的文件覆盖写入
*
* @param bucketName 存储桶名称
* @param filepath 对象存储路径
* @param file 新的文件对象
* @throws AuthCustomerException 当更新失败时抛出
*/
public void updateFile(String bucketName, String filepath, MultipartFile file) {
try {
putObject(bucketName, filepath, file.getInputStream(), file.getSize());
} catch (IOException e) {
throw new AuthCustomerException(e.getMessage());
}
}
/**
* 检查并创建存储桶如果不存在
*
* @param bucketName 存储桶名称
* @return true-已存在false-新创建
* @throws AuthCustomerException 当操作失败时抛出
*/
public boolean createBucketIfNotExists(String bucketName) {
boolean found = false;
try {
found = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
// 如果 bucket 不存在就创建
if (!found) makeBucket(bucketName);
return found;
} catch (Exception exception) {
log.error("判断桶是否存在 ------ 失败消息:{}", exception.getLocalizedMessage());
exception.getStackTrace();
}
throw new AuthCustomerException("未初始化 bucket");
}
/**
* 创建新的存储桶
*
* @param bucketName 存储桶名称需符合命名规范
* @throws AuthCustomerException 当创建失败时抛出
*/
public void makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
} catch (Exception exception) {
exception.getStackTrace();
throw new AuthCustomerException("创建失败");
}
}
}

View File

@ -1,4 +1,4 @@
package cn.bunny.services.mapper.system;
package cn.bunny.services.mapper.file;
import cn.bunny.services.domain.system.files.dto.FilesDto;
import cn.bunny.services.domain.system.files.entity.Files;

View File

@ -0,0 +1,31 @@
package cn.bunny.services.mapper.file;
import cn.bunny.services.domain.system.files.dto.FilesParDetailDto;
import cn.bunny.services.domain.system.files.entity.FilesParDetail;
import cn.bunny.services.domain.system.files.vo.FilesParDetailVo;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
* <p>
* 文件分片信息表仅在手动分片上传时使用 Mapper 接口
* </p>
*
* @author Bunny
* @since 2025-05-08 23:01:19
*/
@Mapper
public interface FilesParDetailMapper extends BaseMapper<FilesParDetail> {
/**
* * 分页查询文件分片信息表仅在手动分片上传时使用内容
*
* @param pageParams 文件分片信息表仅在手动分片上传时使用分页参数
* @param dto 文件分片信息表仅在手动分片上传时使用查询表单
* @return 文件分片信息表仅在手动分片上传时使用分页结果
*/
IPage<FilesParDetailVo> selectListByPage(@Param("page") Page<FilesParDetail> pageParams, @Param("dto") FilesParDetailDto dto);
}

View File

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bunny.services.mapper.file.FilesMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.bunny.services.domain.system.files.entity.Files">
<id column="id" property="id"/>
<id column="url" property="url"/>
<id column="size" property="size"/>
<id column="filename" property="filename"/>
<id column="original_filename" property="originalFilename"/>
<id column="base_path" property="basePath"/>
<id column="filepath" property="filepath"/>
<id column="ext" property="ext"/>
<id column="content_type" property="contentType"/>
<id column="platform" property="platform"/>
<id column="th_url" property="thUrl"/>
<id column="th_filename" property="thFilename"/>
<id column="th_size" property="thSize"/>
<id column="th_content_type" property="thContentType"/>
<id column="object_id" property="objectId"/>
<id column="object_type" property="objectType"/>
<id column="metadata" property="metadata"/>
<id column="user_metadata" property="userMetadata"/>
<id column="th_metadata" property="thMetadata"/>
<id column="th_user_metadata" property="thUserMetadata"/>
<id column="attr" property="attr"/>
<id column="file_acl" property="fileAcl"/>
<id column="th_file_acl" property="thFileAcl"/>
<id column="hash_info" property="hashInfo"/>
<id column="upload_id" property="uploadId"/>
<id column="upload_status" property="uploadStatus"/>
<id column="download_count" property="downloadCount"/>
<id column="create_user" property="createUser"/>
<id column="update_user" property="updateUser"/>
<id column="create_time" property="createTime"/>
<id column="update_time" property="updateTime"/>
<id column="is_deleted" property="isDeleted"/>
<id column="id" property="id"/>
<id column="filename" property="filename"/>
<id column="filepath" property="filepath"/>
</resultMap>
<!-- 分页查询系统文件表内容 -->
<select id="selectListByPage" resultType="cn.bunny.services.domain.system.files.vo.FilesVo">
select
files.*,
create_user.username as create_username,
update_user.username as update_username
from sys_files files
left join sys_user create_user on create_user.id = files.create_user
left join sys_user update_user on update_user.id = files.update_user
<where>
files.is_deleted = 0
<if test="dto.filename != null and dto.filename != ''">
and files.filename like CONCAT('%',#{dto.filename},'%')
</if>
<if test="dto.filepath != null and dto.filepath != ''">
and files.filepath like CONCAT('%',#{dto.filepath},'%')
</if>
<if test="dto.contentType != null and dto.contentType != ''">
and files.content_type like CONCAT('%',#{dto.contentType},'%')
</if>
<if test="dto.ext != null and dto.ext != ''">
and files.ext like CONCAT('%',#{dto.ext},'%')
</if>
<if test="dto.platform != null and dto.platform != ''">
and files.platform like CONCAT('%',#{dto.platform},'%')
</if>
<if test="dto.downloadCount != null">
and files.download_count = #{dto.downloadCount}
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bunny.services.mapper.file.FilesParDetailMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.bunny.services.domain.system.files.entity.FilesParDetail">
<id column="id" property="id"/>
<id column="platform" property="platform"/>
<id column="upload_id" property="uploadId"/>
<id column="e_tag" property="eTag"/>
<id column="part_number" property="partNumber"/>
<id column="part_size" property="partSize"/>
<id column="hash_info" property="hashInfo"/>
<id column="create_user" property="createUser"/>
<id column="update_user" property="updateUser"/>
<id column="create_time" property="createTime"/>
<id column="update_time" property="updateTime"/>
<id column="is_deleted" property="isDeleted"/>
</resultMap>
<!-- 分页查询文件分片信息表,仅在手动分片上传时使用内容 -->
<select id="selectListByPage" resultType="cn.bunny.services.domain.system.files.vo.FilesParDetailVo">
select
base.*,
create_user.username as create_username,
update_user.username as update_username
from sys_files_part_detail base
left join sys_user create_user on create_user.id = base.create_user
left join sys_user update_user on update_user.id = base.update_user
<where>
base.is_deleted = 0
<if test="dto.id != null and dto.id != ''">
and base.id like CONCAT('%',#{dto.id},'%')
</if>
<if test="dto.platform != null and dto.platform != ''">
and base.platform like CONCAT('%',#{dto.platform},'%')
</if>
<if test="dto.uploadId != null and dto.uploadId != ''">
and base.upload_id like CONCAT('%',#{dto.uploadId},'%')
</if>
<if test="dto.eTag != null and dto.eTag != ''">
and base.e_tag like CONCAT('%',#{dto.eTag},'%')
</if>
<if test="dto.partNumber != null and dto.partNumber != ''">
and base.part_number like CONCAT('%',#{dto.partNumber},'%')
</if>
<if test="dto.partSize != null and dto.partSize != ''">
and base.part_size like CONCAT('%',#{dto.partSize},'%')
</if>
<if test="dto.hashInfo != null and dto.hashInfo != ''">
and base.hash_info like CONCAT('%',#{dto.hashInfo},'%')
</if>
<if test="dto.createUser != null and dto.createUser != ''">
and base.create_user like CONCAT('%',#{dto.createUser},'%')
</if>
<if test="dto.updateUser != null and dto.updateUser != ''">
and base.update_user like CONCAT('%',#{dto.updateUser},'%')
</if>
<if test="dto.createTime != null and dto.createTime != ''">
and base.create_time like CONCAT('%',#{dto.createTime},'%')
</if>
<if test="dto.updateTime != null and dto.updateTime != ''">
and base.update_time like CONCAT('%',#{dto.updateTime},'%')
</if>
<if test="dto.isDeleted != null and dto.isDeleted != ''">
and base.is_deleted like CONCAT('%',#{dto.isDeleted},'%')
</if>
</where>
</select>
</mapper>

View File

@ -1,52 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.bunny.services.mapper.system.FilesMapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="cn.bunny.services.domain.system.files.entity.Files">
<id column="id" property="id"/>
<id column="create_time" property="createTime"/>
<id column="update_time" property="updateTime"/>
<id column="create_user" property="createUser"/>
<id column="update_user" property="updateUser"/>
<id column="is_deleted" property="isDeleted"/>
<id column="filename" property="filename"/>
<id column="filepath" property="filepath"/>
<id column="file_size" property="fileSize"/>
<id column="file_type" property="fileType"/>
<id column="download_count" property="downloadCount"/>
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
id, create_time, update_time, create_user, update_user, is_deleted, filename, filepath, file_size, file_type,
download_count
</sql>
<!-- 分页查询系统文件表内容 -->
<select id="selectListByPage" resultType="cn.bunny.services.domain.system.files.vo.FilesVo">
select
files.*,
create_user.username as create_username,
update_user.username as update_username
from sys_files files
left join sys_user create_user on create_user.id = files.create_user
left join sys_user update_user on update_user.id = files.update_user
<where>
files.is_deleted = 0
<if test="dto.filename != null and dto.filename != ''">
and files.filename like CONCAT('%',#{dto.filename},'%')
</if>
<if test="dto.filepath != null and dto.filepath != ''">
and files.filepath like CONCAT('%',#{dto.filepath},'%')
</if>
<if test="dto.fileType != null and dto.fileType != ''">
and files.file_type like CONCAT('%',#{dto.fileType},'%')
</if>
<if test="dto.downloadCount != null and dto.downloadCount != ''">
and files.download_count like CONCAT('%',#{dto.downloadCount},'%')
</if>
</where>
</select>
</mapper>

View File

@ -1,117 +0,0 @@
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.bunny</groupId>
<artifactId>auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<artifactId>generator-code</artifactId>
<packaging>jar</packaging>
<name>generator-code</name>
<url>https://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- <dependency> -->
<!-- <groupId>org.xerial</groupId> -->
<!-- <artifactId>sqlite-jdbc</artifactId> -->
<!-- <version>3.49.1.0</version> -->
<!-- </dependency> -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>5.1</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
</dependency>
<!-- knife4j -->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.6</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-annotations</artifactId>
<version>1.6.14</version>
</dependency>
<!-- fastjson2 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
</dependency>
<!-- 小驼峰 和 大驼峰之间互转 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>33.4.7-jre</version>
</dependency>
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.3</version>
</dependency>
</dependencies>
</project>

View File

@ -1,11 +0,0 @@
package cn.bunny;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GeneratorCodeMainApplication {
public static void main(String[] args) {
SpringApplication.run(GeneratorCodeMainApplication.class, args);
}
}

View File

@ -1,50 +0,0 @@
package cn.bunny.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import java.io.IOException;
/**
* 去除前端传递的空格
*/
@ControllerAdvice
public class ControllerStringParamTrimConfig {
/**
* 创建 String trim 编辑器
* 构造方法中 boolean 参数含义为如果是空白字符串,是否转换为null
* 即如果为true,那么 " " 会被转换为 null,否者为 ""
*/
@InitBinder
public void initBinder(WebDataBinder binder) {
StringTrimmerEditor propertyEditor = new StringTrimmerEditor(false);
// String 类对象注册编辑器
binder.registerCustomEditor(String.class, propertyEditor);
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return jacksonObjectMapperBuilder -> {
// String 类型自定义反序列化操作
jacksonObjectMapperBuilder
.deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) {
@Override
public String deserialize(JsonParser jsonParser, DeserializationContext ctx) throws IOException {
// // 去除全部空格
// return StringUtils.trimAllWhitespace(jsonParser.getValueAsString());
// 仅去除前后空格
return jsonParser.getValueAsString().trim();
}
});
};
}
}

View File

@ -1,44 +0,0 @@
package cn.bunny.config;
import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class Knife4jConfig {
@Value("${server.port}")
private String port;
@Bean
public OpenAPI openAPI() {
String url = "http://localhost:" + port;
// 作者等信息
Contact contact = new Contact().name("Bunny").email("1319900154@qq.com").url(url);
// 使用协议
License license = new License().name("MIT").url("https://mit-license.org");
// 相关信息
Info info = new Info().title("Bunny-Admin")
.contact(contact).license(license)
.description("Bunny代码生成器")
.summary("Bunny的代码生成器")
.termsOfService(url)
.version("v1.0.0");
return new OpenAPI().info(info).externalDocs(new ExternalDocumentation());
}
@Bean
public GroupedOpenApi all() {
return GroupedOpenApi.builder().group("全部请求接口").pathsToMatch("/api/**").build();
}
}

View File

@ -1,18 +0,0 @@
package cn.bunny.config;
import jakarta.annotation.PostConstruct;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Component;
import java.util.Properties;
@Component
public class VmsHolder {
@PostConstruct
public void init() {
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
}
}

View File

@ -1,13 +0,0 @@
package cn.bunny.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class IndexController {
@GetMapping("/")
public String index() {
return "index";
}
}

View File

@ -1,38 +0,0 @@
package cn.bunny.controller;
import cn.bunny.core.SqlParserCore;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.result.Result;
import cn.bunny.dao.vo.TableInfoVo;
import cn.bunny.service.SqlParserService;
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.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@Tag(name = "解析SQL", description = "解析SQL接口")
@RestController
@RequestMapping("/api/sqlParser")
public class SqlParserController {
@Resource
private SqlParserService sqlParserService;
@Operation(summary = "解析SQL成表信息", description = "解析SQL成表信息")
@PostMapping("tableInfo")
public Result<TableInfoVo> tableInfo(String sql) {
TableInfoVo vo = sqlParserService.tableInfo(sql);
return Result.success(vo);
}
@Operation(summary = "解析SQL成列数据", description = "解析SQL成列数据")
@PostMapping("columnMetaData")
public Result<List<ColumnMetaData>> columnMetaData(String sql) {
List<ColumnMetaData> vo = SqlParserCore.parserColumnInfo(sql);
return Result.success(vo);
}
}

View File

@ -1,81 +0,0 @@
package cn.bunny.controller;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.DatabaseInfoMetaData;
import cn.bunny.dao.result.Result;
import cn.bunny.dao.vo.TableInfoVo;
import cn.bunny.service.TableService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.stream.Collectors;
@Tag(name = "数据库表控制器", description = "数据库表信息接口")
@RestController
@RequestMapping("/api/table")
public class TableController {
@Value("${bunny.master.database}")
private String currentDatabase;
@Resource
private TableService tableService;
@Operation(summary = "当前数据库信息", description = "当前连接的数据库信息")
@GetMapping("databaseInfoMetaData")
public Result<DatabaseInfoMetaData> databaseInfoMetaData() {
DatabaseInfoMetaData databaseInfoMetaData = tableService.databaseInfoMetaData();
return Result.success(databaseInfoMetaData);
}
@Operation(summary = "当前配置的数据库", description = "当前配置的数据库")
@GetMapping("currentDatabaseName")
public Result<String> getCurrentDatabaseName() {
return Result.success(currentDatabase);
}
@Operation(summary = "数据库所有的表", description = "获取[当前/所有]数据库表")
@GetMapping("databaseTableList")
public Result<List<TableInfoVo>> databaseTableList(String dbName) {
List<TableInfoVo> list = tableService.databaseTableList(dbName);
return Result.success(list);
}
@Operation(summary = "所有的数据库名称", description = "当前数据库所有的数据库名称")
@GetMapping("databaseList")
public Result<List<TableInfoVo>> databaseList() {
List<TableInfoVo> allDb = tableService.databaseTableList(null);
// 将当前数据库表分组以数据库名称为key
List<TableInfoVo> list = allDb.stream()
.collect(Collectors.groupingBy(TableInfoVo::getTableCat))
.values().stream()
.map(tableInfoVos -> {
TableInfoVo tableInfoVo = tableInfoVos.get(0);
tableInfoVo.setTableName(null);
return tableInfoVo;
}).toList();
return Result.success(list);
}
@Operation(summary = "表属性", description = "获取当前查询表属性")
@GetMapping("tableMetaData")
public Result<TableInfoVo> tableMetaData(String tableName) {
TableInfoVo tableMetaData = tableService.tableMetaData(tableName);
return Result.success(tableMetaData);
}
@Operation(summary = "表的列属性", description = "获取当前查询表中列属性")
@GetMapping("tableColumnInfo")
public Result<List<ColumnMetaData>> tableColumnInfo(String tableName) {
List<ColumnMetaData> columnInfo = tableService.tableColumnInfo(tableName);
return Result.success(columnInfo);
}
}

View File

@ -1,45 +0,0 @@
package cn.bunny.controller;
import cn.bunny.dao.dto.VmsArgumentDto;
import cn.bunny.dao.result.Result;
import cn.bunny.dao.vo.GeneratorVo;
import cn.bunny.dao.vo.VmsPathVo;
import cn.bunny.service.VmsService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@Tag(name = "生成器", description = "代码生成器接口")
@RestController
@RequestMapping("/api/vms")
public class VmsController {
@Resource
private VmsService vmsService;
@Operation(summary = "获取vms文件路径", description = "获取所有vms下的文件路径")
@GetMapping("vmsResourcePathList")
public Result<Map<String, List<VmsPathVo>>> vmsResourcePathList() {
Map<String, List<VmsPathVo>> list = vmsService.vmsResourcePathList();
return Result.success(list);
}
@Operation(summary = "生成代码", description = "生成代码")
@PostMapping("generator")
public Result<List<GeneratorVo>> generator(@Valid @RequestBody VmsArgumentDto dto) {
List<GeneratorVo> list = vmsService.generator(dto);
return Result.success(list);
}
@Operation(summary = "打包成zip下载", description = "打包成zip下载")
@PostMapping("downloadByZip")
public ResponseEntity<byte[]> downloadByZip(@Valid @RequestBody VmsArgumentDto dto) {
return vmsService.downloadByZip(dto);
}
}

View File

@ -1,196 +0,0 @@
package cn.bunny.core;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.DatabaseInfoMetaData;
import cn.bunny.dao.entity.TableMetaData;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/* 数据库信息内容 */
@Component
public class DatabaseInfoCore {
@Resource
private DataSource dataSource;
/**
* 获取表的所有主键列名
*
* @param tableName 表名
* @return 主键列名的集合
*/
@SneakyThrows
public Set<String> getPrimaryKeyColumns(String tableName) {
// 主键的key
Set<String> primaryKeys = new HashSet<>();
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
// 当前表的主键
ResultSet pkResultSet = metaData.getPrimaryKeys(null, null, tableName);
while (pkResultSet.next()) {
// 列字段
String columnName = pkResultSet.getString("COLUMN_NAME").toLowerCase();
primaryKeys.add(columnName);
}
return primaryKeys;
}
}
/**
* 获取表注释信息
*
* @param tableName 数据库表名
* @return 表信息
*/
@SneakyThrows
public TableMetaData tableInfoMetaData(String tableName) {
TableMetaData tableMetaData;
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
ResultSet tables = metaData.getTables(null, null, tableName, new String[]{"TABLE"});
// 获取表的注释信息
if (tables.next()) {
// 备注信息
String remarks = tables.getString("REMARKS");
// 数组名称
String tableCat = tables.getString("TABLE_CAT");
// 通常是"TABLE"
String tableType = tables.getString("TABLE_TYPE");
tableMetaData = TableMetaData.builder()
.tableName(tableName)
.comment(remarks)
.tableCat(tableCat)
.tableType(tableType)
.build();
} else {
throw new RuntimeException("数据表不存在");
}
return tableMetaData;
}
}
/**
* 获取[当前/所有]数据库表
*
* @return 所有表信息
*/
@SneakyThrows
public List<TableMetaData> databaseTableList(String dbName) {
// 当前数据库数据库所有的表
List<TableMetaData> allTableInfo = new ArrayList<>();
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
// 当前数据库中所有的表
ResultSet tables = metaData.getTables(dbName, null, "%", new String[]{"TABLE"});
while (tables.next()) {
// 表名称
dbName = tables.getString("TABLE_NAME");
// 设置表信息
TableMetaData tableMetaData = tableInfoMetaData(dbName);
allTableInfo.add(tableMetaData);
}
}
return allTableInfo;
}
/**
* 获取当前表的列属性
*
* @param tableName 表名称
* @return 当前表所有的列内容
*/
@SneakyThrows
public List<ColumnMetaData> tableColumnInfo(String tableName) {
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
List<ColumnMetaData> columns = new ArrayList<>();
// 当前表的主键
Set<String> primaryKeyColumns = getPrimaryKeyColumns(tableName);
// 当前表的列信息
try (ResultSet columnsRs = metaData.getColumns(null, null, tableName, null)) {
while (columnsRs.next()) {
ColumnMetaData column = new ColumnMetaData();
// 列字段
String columnName = columnsRs.getString("COLUMN_NAME");
// 将当前表的列类型转成 Java 类型
String javaType = TypeConvertCore.convertToJavaType(column.getJdbcType());
// 设置列字段
column.setColumnName(columnName);
// 列字段转成 下划线 -> 小驼峰
column.setLowercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName()));
// 列字段转成 下划线 -> 大驼峰名称
column.setUppercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName(), true));
// 字段类型
column.setJdbcType(columnsRs.getString("TYPE_NAME"));
// 字段类型转 Java 类型
column.setJavaType(javaType);
// 字段类型转 JavaScript 类型
column.setJavascriptType(StringUtils.uncapitalize(javaType));
// 备注信息
column.setComment(columnsRs.getString("REMARKS"));
// 确保 primaryKeyColumns 不为空
if (!primaryKeyColumns.isEmpty()) {
// 是否是主键
boolean isPrimaryKey = primaryKeyColumns.contains(columnName);
column.setIsPrimaryKey(isPrimaryKey);
}
columns.add(column);
}
}
columns.get(0).setIsPrimaryKey(true);
return columns;
}
}
/**
* 数据库所有的信息
*
* @return 当前连接的数据库信息属性
*/
@SneakyThrows
public DatabaseInfoMetaData databaseInfoMetaData() {
try (Connection connection = dataSource.getConnection()) {
DatabaseMetaData metaData = connection.getMetaData();
return DatabaseInfoMetaData.builder()
.databaseProductName(metaData.getDatabaseProductName())
.databaseProductVersion(metaData.getDatabaseProductVersion())
.driverName(metaData.getDriverName())
.driverVersion(metaData.getDriverVersion())
.url(metaData.getURL())
.username(metaData.getUserName())
.build();
}
}
}

View File

@ -1,134 +0,0 @@
package cn.bunny.core;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Stream;
/* 当前生产/开发下的资源文件 */
public class ResourceFileCore {
/**
* 获取目标文件夹下所有文件完整路径
*
* @param dirname 文件夹名称
* @return 目标文件完整路径
* @throws IOException IOException
*/
public static List<String> getAbsoluteFiles(String dirname) throws IOException {
List<String> fileNames = new ArrayList<>();
// 加载当前类
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Enumeration<URL> urls = classLoader.getResources(dirname);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
if (url.getProtocol().equals("file")) {
// 文件系统
File file = new File(url.getFile());
if (file.isDirectory()) {
addFullFilesFromDirectory(file, fileNames);
}
} else if (url.getProtocol().equals("jar")) {
// JAR文件
String jarPath = url.getPath().substring(5, url.getPath().indexOf("!"));
try (JarFile jar = new JarFile(jarPath)) {
Enumeration<JarEntry> entries = jar.entries();
while (entries.hasMoreElements()) {
String name = entries.nextElement().getName();
if (name.startsWith(dirname + "/") && !name.endsWith("/")) {
fileNames.add(name);
}
}
}
}
}
return fileNames;
}
/**
* 添加文件
* 获取目标文件夹下所有文件完整路径
*
* @param directory 文件夹
* @param fileNames 文件名称
*/
private static void addFullFilesFromDirectory(File directory, List<String> fileNames) {
File[] files = directory.listFiles();
if (files != null) {
for (File file : files) {
if (file.isFile()) {
fileNames.add(file.getPath());
} else if (file.isDirectory()) {
addFullFilesFromDirectory(file, fileNames);
}
}
}
}
/**
* 获取相对文件夹路径
*
* @return 相对当前的文件夹路径
* @throws IOException IOException
* @throws URISyntaxException URISyntaxException
*/
public static List<String> getRelativeFiles(String dirname) throws IOException, URISyntaxException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
URL resource = classLoader.getResource(dirname);
if (resource == null) return Collections.emptyList();
// 处理JAR包内的情况
if (resource.getProtocol().equals("jar")) {
return getFilesFromJar(resource, dirname);
} else {
// 处理文件系统情况
return getFilesFromFileSystem(resource);
}
}
private static List<String> getFilesFromJar(URL jarUrl, String dirname) throws IOException {
List<String> fileNames = new ArrayList<>();
String jarPath = jarUrl.getPath().substring(5, jarUrl.getPath().indexOf("!"));
try (JarFile jar = new JarFile(jarPath)) {
jar.entries().asIterator()
.forEachRemaining(entry -> {
String name = entry.getName();
String prefix = dirname + "/";
if (name.startsWith(prefix) && !name.endsWith("/")) {
fileNames.add(name.substring(prefix.length()));
}
});
}
return fileNames;
}
private static List<String> getFilesFromFileSystem(URL resource) throws IOException, URISyntaxException {
Path filepath = Paths.get(resource.toURI());
try (Stream<Path> paths = Files.walk(filepath)) {
return paths.filter(Files::isRegularFile)
.map(filepath::relativize)
.map(Path::toString)
// 统一使用/作为分隔符
.map(s -> s.replace('\\', '/'))
.toList();
}
}
}

View File

@ -1,110 +0,0 @@
package cn.bunny.core;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.TableMetaData;
import lombok.SneakyThrows;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class SqlParserCore {
/**
* 解析 sql 表信息
*
* @param sql sql字符串
* @return 表西悉尼
*/
@SneakyThrows
public static TableMetaData parserTableInfo(String sql) {
TableMetaData tableInfo = new TableMetaData();
// 解析sql
Statement statement;
try {
statement = CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
throw new RuntimeException("SQL解析失败");
}
if (!(statement instanceof CreateTable createTable)) {
throw new IllegalArgumentException("缺少SQL语句");
}
// 设置表基本信息
String tableName = createTable.getTable().getName().replaceAll("`", "");
tableInfo.setTableName(tableName);
tableInfo.setTableType("TABLE");
String tableOptionsStrings = String.join(" ", createTable.getTableOptionsStrings());
// 注释信息
Pattern pattern = Pattern.compile("COMMENT\\s*=\\s*'(.*?)'", Pattern.CASE_INSENSITIVE);
Matcher matcher = pattern.matcher(tableOptionsStrings);
if (matcher.find()) {
tableInfo.setComment(matcher.group(1));
}
return tableInfo;
}
/**
* 解析 sql 列信息
*
* @param sql sql字符串
* @return 列属性列表
*/
@SneakyThrows
public static List<ColumnMetaData> parserColumnInfo(String sql) {
// 解析sql
Statement statement;
try {
statement = CCJSqlParserUtil.parse(sql);
} catch (JSQLParserException e) {
throw new RuntimeException("SQL解析失败");
}
if (!(statement instanceof CreateTable createTable)) {
throw new IllegalArgumentException("缺少SQL语句");
}
return createTable.getColumnDefinitions()
.stream().map(column -> {
// 列信息
ColumnMetaData columnInfo = new ColumnMetaData();
// 列名称
columnInfo.setColumnName(column.getColumnName());
// 设置 JDBC 类型
String dataType = column.getColDataType().getDataType();
columnInfo.setJdbcType(dataType);
// 设置 Java 类型
String javaType = TypeConvertCore.convertToJavaType(dataType.contains("varchar") ? "varchar" : dataType);
columnInfo.setJavaType(javaType);
// 设置 JavaScript 类型
columnInfo.setJavascriptType(StringUtils.uncapitalize(javaType));
// 列字段转成 下划线 -> 小驼峰
columnInfo.setLowercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName()));
// 列字段转成 下划线 -> 大驼峰名称
columnInfo.setUppercaseName(TypeConvertCore.convertToCamelCase(column.getColumnName(), true));
// 解析注释
List<String> columnSpecs = column.getColumnSpecs();
String columnSpecsString = String.join(" ", columnSpecs);
Matcher columnSpecsStringMatcher = Pattern.compile("COMMENT\\s*'(.*?)'", Pattern.CASE_INSENSITIVE).matcher(columnSpecsString);
if (columnSpecsStringMatcher.find()) {
columnInfo.setComment(columnSpecsStringMatcher.group(1));
}
return columnInfo;
}).toList();
}
}

View File

@ -1,61 +0,0 @@
package cn.bunny.core;
import com.google.common.base.CaseFormat;
import org.assertj.core.util.introspection.CaseFormatUtils;
/* 类型转换数据库转Java类型等 */
public class TypeConvertCore {
/**
* 将数据库类型转换为Java类型
*/
public static String convertToJavaType(String columnType) {
if (columnType == null) return "Object";
columnType = columnType.toLowerCase();
return switch (columnType) {
case "varchar" , "char" , "text" , "longtext" , "mediumtext" , "tinytext" -> "String";
case "int" , "integer" , "tinyint" , "smallint" -> "Integer";
case "bigint" -> "Long";
case "decimal" , "numeric" -> "BigDecimal";
case "float" -> "Float";
case "double" -> "Double";
case "boolean" , "bit" , "tinyint unsigned" -> "Boolean";
case "date" , "year" -> "Date";
case "time" -> "Time";
case "datetime" , "timestamp" -> "LocalDateTime";
case "blob" , "longblob" , "mediumblob" , "tinyblob" -> "byte[]";
default -> "Object";
};
}
/**
* 下划线命名转驼峰命名
*/
public static String convertToCamelCase(String name) {
return convertToCamelCase(name, false);
}
/**
* 下划线命名转驼峰命名
*
* @param name 原始名称传入的值可以是
* `xxx_xxx` `CaseFormat`
* `caseFormat`
* @param firstLetterCapital 首字母是否大写
*/
public static String convertToCamelCase(String name, boolean firstLetterCapital) {
if (name == null || name.isEmpty()) return name;
// 转成小驼峰
String lowerCamelCase = CaseFormatUtils.toCamelCase(name);
// 首字母不大写
if (!firstLetterCapital) {
return lowerCamelCase;
}
// 将小驼峰转成大驼峰
return CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, lowerCamelCase);
}
}

View File

@ -1,62 +0,0 @@
package cn.bunny.core.vms;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.TableMetaData;
import org.apache.velocity.VelocityContext;
import java.io.StringWriter;
import java.util.List;
/**
* 模板方法模式
* 如果需要继承 AbstractVmsGenerator
*/
public abstract class AbstractVmsGenerator {
/**
* 添加生成内容
*/
abstract void addContext(VelocityContext context);
/**
* Velocity 生成模板
*
* @param context VelocityContext
* @param writer StringWriter 写入
*/
abstract void templateMerge(VelocityContext context, StringWriter writer);
/**
* 生成模板
*
* @param tableMetaData 表属性
* @param columnInfoList 列属性数组
* @return StringWriter
*/
public final StringWriter generatorCodeTemplate(TableMetaData tableMetaData, List<ColumnMetaData> columnInfoList) {
VelocityContext context = new VelocityContext();
// 添加要生成的属性
StringWriter writer = new StringWriter();
List<String> list = columnInfoList.stream().map(ColumnMetaData::getColumnName).toList();
// vm 不能直接写 `{` 需要转换下
context.put("leftBrace", "{");
// 当前的表名
context.put("tableName", tableMetaData.getTableName());
// 当前表的列信息
context.put("columnInfoList", columnInfoList);
// 数据库sql列
context.put("baseColumnList", String.join(",", list));
// 添加需要生成的内容
addContext(context);
templateMerge(context, writer);
return writer;
}
}

View File

@ -1,85 +0,0 @@
package cn.bunny.core.vms;
import cn.bunny.core.TypeConvertCore;
import cn.bunny.dao.dto.VmsArgumentDto;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 使用模板方法方便扩展
* 如果需要继承 AbstractVmsGenerator
*/
public class VmsArgumentDtoBaseVmsGenerator extends AbstractVmsGenerator {
private final VmsArgumentDto dto;
private final String path;
/**
* @param dto 类名称可以自定义格式为 xxx_xxx
* @param path 当前路径
*/
public VmsArgumentDtoBaseVmsGenerator(VmsArgumentDto dto, String path) {
this.dto = dto;
this.path = path;
}
/**
* 添加生成内容
*
* @param context VelocityContext
*/
@Override
void addContext(VelocityContext context) {
// 当前日期
String date = new SimpleDateFormat(dto.getSimpleDateFormat()).format(new Date());
context.put("date", date);
// 作者名字
context.put("author", dto.getAuthor());
// 每个 Controller 上的请求前缀
context.put("requestMapping", dto.getRequestMapping());
// 表字段的注释内容
context.put("comment", dto.getComment());
// 设置包名称
context.put("package", dto.getPackageName());
// 类名称如果是小驼峰需要 [手写] [下划线] 之后由 [代码 -> 小驼峰/大驼峰]
String className = dto.getClassName();
// 去除表开头前缀
String tablePrefixes = dto.getTablePrefixes();
// 表前缀 转成数组
String replaceTableName = "";
for (String prefix : tablePrefixes.split("[,]")) {
replaceTableName = className.replace(prefix, "");
}
// 将类名称转成小驼峰
String toCamelCase = TypeConvertCore.convertToCamelCase(replaceTableName);
context.put("classLowercaseName", toCamelCase);
// 将类名称转成大驼峰
String convertToCamelCase = TypeConvertCore.convertToCamelCase(replaceTableName, true);
context.put("classUppercaseName", convertToCamelCase);
}
/**
* Velocity 生成模板
*
* @param context VelocityContext
* @param writer StringWriter 写入
*/
@Override
void templateMerge(VelocityContext context, StringWriter writer) {
// Velocity 生成模板
Template servicePathTemplate = Velocity.getTemplate("vms/" + path, "UTF-8");
servicePathTemplate.merge(context, writer);
}
}

View File

@ -1,53 +0,0 @@
package cn.bunny.dao.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class VmsArgumentDto {
/* 作者名称 */
String author = "Bunny";
/* 包名称 */
String packageName = "cn.bunny.services";
/* requestMapping 名称 */
String requestMapping = "/api";
/* 类名称格式为xxx xxx_xxx */
@NotBlank(message = "类名称不能为空")
@NotNull(message = "类名称不能为空")
@Pattern(regexp = "^(?:[a-z][a-z0-9_]*|[_a-z][a-z0-9_]*)$", message = "类名称不合法")
private String className;
/* 表名称 */
@NotBlank(message = "表名称不能为空")
@NotNull(message = "表名称不能为空")
@Pattern(regexp = "^(?:[a-z][a-z0-9_]*|[_a-z][a-z0-9_]*)$", message = "表名称不合法")
private String tableName;
/* 时间格式 */
private String simpleDateFormat = "yyyy-MM-dd HH:mm:ss";
/* 去除表前缀 */
private String tablePrefixes = "t_,sys_,qrtz_,log_";
/* 注释内容 */
private String comment;
/* 路径 */
private List<String> path;
/* SQL 语句 */
private String sql;
}

View File

@ -1,38 +0,0 @@
package cn.bunny.dao.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ColumnMetaData {
/* 列名称 */
private String columnName;
/* 字段名称,小驼峰名称 */
private String lowercaseName;
/* 大驼峰名称 */
private String uppercaseName;
/* 数据库字段类型 */
private String jdbcType;
/* Java类型 */
private String javaType;
/* Javascript类型 */
private String javascriptType;
/* 是否为主键 */
private Boolean isPrimaryKey;
/* 字段注释 */
private String comment;
}

View File

@ -1,31 +0,0 @@
package cn.bunny.dao.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DatabaseInfoMetaData {
/* 数据库产品名称 */
private String databaseProductName;
/* 数据库产品版本 */
private String databaseProductVersion;
/* 驱动名称 */
private String driverName;
/* 数据库驱动版本 */
private String driverVersion;
/* 数据链接url */
private String url;
/* 数据库用户 */
private String username;
}

View File

@ -1,33 +0,0 @@
package cn.bunny.dao.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TableMetaData {
/* 表名 */
private String tableName;
/* 注释内容 */
private String comment;
/* 表目录 */
private String tableCat;
/* 表类型(通常是"TABLE" */
private String tableType;
/* 类名 */
private String className;
/* 列名称 */
private List<ColumnMetaData> columns;
}

View File

@ -1,34 +0,0 @@
package cn.bunny.dao.result;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 封装分页查询结果
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Schema(name = "PageResult 对象" , title = "分页返回结果" , description = "分页返回结果" )
public class PageResult<T> implements Serializable {
@Schema(name = "pageNo" , title = "当前页" )
private Long pageNo;
@Schema(name = "pageSize" , title = "每页记录数" )
private Long pageSize;
@Schema(name = "total" , title = "总记录数" )
private Long total;
@Schema(name = "list" , title = "当前页数据集合" )
private List<T> list;
}

View File

@ -1,173 +0,0 @@
package cn.bunny.dao.result;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
// 状态码
private Integer code;
// 返回消息
private String message;
// 返回数据
private T data;
/**
* * 自定义返回体
*
* @param data 返回体
* @return Result<T>
*/
protected static <T> Result<T> build(T data) {
Result<T> result = new Result<>();
result.setData(data);
return result;
}
/**
* * 自定义返回体使用ResultCodeEnum构建
*
* @param body 返回体
* @param codeEnum 返回状态码
* @return Result<T>
*/
public static <T> Result<T> build(T body, ResultCodeEnum codeEnum) {
Result<T> result = build(body);
result.setCode(codeEnum.getCode());
result.setMessage(codeEnum.getMessage());
return result;
}
/**
* * 自定义返回体
*
* @param body 返回体
* @param code 返回状态码
* @param message 返回消息
* @return Result<T>
*/
public static <T> Result<T> build(T body, Integer code, String message) {
Result<T> result = build(body);
result.setCode(code);
result.setMessage(message);
result.setData(null);
return result;
}
/**
* * 操作成功
*
* @return Result<T>
*/
public static <T> Result<T> success() {
return success(null, ResultCodeEnum.SUCCESS);
}
/**
* * 操作成功
*
* @param data baseCategory1List
*/
public static <T> Result<T> success(T data) {
return build(data, ResultCodeEnum.SUCCESS);
}
/**
* * 操作成功-状态码
*
* @param codeEnum 状态码
*/
public static <T> Result<T> success(ResultCodeEnum codeEnum) {
return success(null, codeEnum);
}
/**
* * 操作成功-自定义返回数据和状态码
*
* @param data 返回体
* @param codeEnum 状态码
*/
public static <T> Result<T> success(T data, ResultCodeEnum codeEnum) {
return build(data, codeEnum);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param message 错误信息
*/
public static <T> Result<T> success(T data, String message) {
return build(data, 200, message);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param code 状态码
* @param message 错误信息
*/
public static <T> Result<T> success(T data, Integer code, String message) {
return build(data, code, message);
}
/**
* * 操作失败
*/
public static <T> Result<T> error() {
return Result.build(null);
}
/**
* * 操作失败-自定义返回数据
*
* @param data 返回体
*/
public static <T> Result<T> error(T data) {
return build(data, ResultCodeEnum.FAIL);
}
/**
* * 操作失败-状态码
*
* @param codeEnum 状态码
*/
public static <T> Result<T> error(ResultCodeEnum codeEnum) {
return build(null, codeEnum);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param codeEnum 状态码
*/
public static <T> Result<T> error(T data, ResultCodeEnum codeEnum) {
return build(data, codeEnum);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param code 状态码
* @param message 错误信息
*/
public static <T> Result<T> error(T data, Integer code, String message) {
return build(data, code, message);
}
/**
* * 操作失败-自定义返回数据和状态码
*
* @param data 返回体
* @param message 错误信息
*/
public static <T> Result<T> error(T data, String message) {
return build(null, 500, message);
}
}

View File

@ -1,90 +0,0 @@
package cn.bunny.dao.result;
import lombok.Getter;
/**
* 统一返回结果状态信息类
*/
@Getter
public enum ResultCodeEnum {
// 成功操作 200
SUCCESS(200, "操作成功"),
ADD_SUCCESS(200, "添加成功"),
UPDATE_SUCCESS(200, "修改成功"),
DELETE_SUCCESS(200, "删除成功"),
SORT_SUCCESS(200, "排序成功"),
SUCCESS_UPLOAD(200, "上传成功"),
SUCCESS_LOGOUT(200, "退出成功"),
LOGOUT_SUCCESS(200, "退出成功"),
EMAIL_CODE_REFRESH(200, "邮箱验证码已刷新"),
EMAIL_CODE_SEND_SUCCESS(200, "邮箱验证码已发送"),
// 验证错误 201
USERNAME_OR_PASSWORD_NOT_EMPTY(201, "用户名或密码不能为空"),
EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"),
SEND_EMAIL_CODE_NOT_EMPTY(201, "请先发送邮箱验证码"),
EMAIL_CODE_NOT_MATCHING(201, "邮箱验证码不匹配"),
LOGIN_ERROR(500, "账号或密码错误"),
LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY(201, "登录信息不能为空"),
GET_BUCKET_EXCEPTION(201, "获取文件信息失败"),
SEND_MAIL_CODE_ERROR(201, "邮件发送失败"),
EMAIL_CODE_EMPTY(201, "邮箱验证码过期或不存在"),
EMAIL_EXIST(201, "邮箱已存在"),
REQUEST_IS_EMPTY(201, "请求数据为空"),
DATA_TOO_LARGE(201, "请求数据为空"),
UPDATE_NEW_PASSWORD_SAME_AS_OLD_PASSWORD(201, "新密码与密码相同"),
// 数据相关 206
ILLEGAL_REQUEST(206, "非法请求"),
REPEAT_SUBMIT(206, "重复提交"),
DATA_ERROR(206, "数据异常"),
EMAIL_USER_TEMPLATE_IS_EMPTY(206, "邮件模板为空"),
EMAIL_TEMPLATE_IS_EMPTY(206, "邮件模板为空"),
EMAIL_USER_IS_EMPTY(206, "关联邮件用户配置为空"),
DATA_EXIST(206, "数据已存在"),
DATA_NOT_EXIST(206, "数据不存在"),
ALREADY_USER_EXCEPTION(206, "用户已存在"),
USER_IS_EMPTY(206, "用户不存在"),
FILE_NOT_EXIST(206, "文件不存在"),
NEW_PASSWORD_SAME_OLD_PASSWORD(206, "新密码不能和旧密码相同"),
MISSING_TEMPLATE_FILES(206, "缺少模板文件"),
// 身份过期 208
LOGIN_AUTH(208, "请先登陆"),
AUTHENTICATION_EXPIRED(208, "身份验证过期"),
SESSION_EXPIRATION(208, "会话过期"),
// 209
THE_SAME_USER_HAS_LOGGED_IN(209, "相同用户已登录"),
// 提示错误
UPDATE_ERROR(216, "修改失败"),
URL_ENCODE_ERROR(216, "URL编码失败"),
ILLEGAL_CALLBACK_REQUEST_ERROR(217, "非法回调请求"),
FETCH_USERINFO_ERROR(219, "获取用户信息失败"),
ILLEGAL_DATA_REQUEST(219, "非法数据请求"),
CLASS_NOT_FOUND(219, "类名不存在"),
ADMIN_ROLE_CAN_NOT_DELETED(219, "无法删除admin角色"),
MENU_RANK_NEED_LARGER_THAN_THE_PARENT(219, "设置路由等级需要大于或等于父级的路由等级"),
// 无权访问 403
FAIL_NO_ACCESS_DENIED(403, "无权访问"),
FAIL_NO_ACCESS_DENIED_USER_OFFLINE(403, "用户强制下线"),
TOKEN_PARSING_FAILED(403, "token解析失败"),
FAIL_NO_ACCESS_DENIED_USER_LOCKED(403, "该账户已封禁"),
// 系统错误 500
UNKNOWN_EXCEPTION(500, "服务异常"),
SERVICE_ERROR(500, "服务异常"),
UPLOAD_ERROR(500, "上传失败"),
FAIL(500, "失败"),
;
private final Integer code;
private final String message;
ResultCodeEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}

View File

@ -1,25 +0,0 @@
package cn.bunny.dao.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class GeneratorVo {
/* 生成的代码 */
private String code;
/* 表名 */
private String tableName;
/* 注释内容 */
private String comment;
/* 生成类型路径 */
private String path;
}

View File

@ -1,29 +0,0 @@
package cn.bunny.dao.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class TableInfoVo {
/* 表目录 */
private String tableCat;
/* 表名 */
private String tableName;
/* 表类型(通常是"TABLE" */
private String tableType;
/* 注释内容 */
private String comment;
/* 类名 */
private String className;
}

View File

@ -1,23 +0,0 @@
package cn.bunny.dao.vo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class VmsPathVo {
/* 路径名称 */
private String name;
/* 显示的label */
private String label;
/* 文件夹最上级目录名称 */
private String type;
}

View File

@ -1,40 +0,0 @@
package cn.bunny.exception;
import cn.bunny.dao.result.ResultCodeEnum;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
@NoArgsConstructor
@Getter
@ToString
@Slf4j
public class GeneratorCodeException extends RuntimeException {
// 状态码
Integer code;
// 描述信息
String message = "服务异常";
// 返回结果状态
ResultCodeEnum resultCodeEnum;
public GeneratorCodeException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
public GeneratorCodeException(String message) {
super(message);
this.message = message;
}
public GeneratorCodeException(ResultCodeEnum codeEnum) {
super(codeEnum.getMessage());
this.code = codeEnum.getCode();
this.message = codeEnum.getMessage();
this.resultCodeEnum = codeEnum;
}
}

View File

@ -1,105 +0,0 @@
package cn.bunny.exception;
import cn.bunny.dao.result.Result;
import cn.bunny.dao.result.ResultCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.sql.SQLIntegrityConstraintViolationException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* 全局异常拦截器
*/
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
// 自定义异常信息
@ExceptionHandler(GeneratorCodeException.class)
@ResponseBody
public Result<Object> exceptionHandler(GeneratorCodeException exception) {
Integer code = exception.getCode() != null ? exception.getCode() : 500;
return Result.error(null, code, exception.getMessage());
}
// 运行时异常信息
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Result<Object> exceptionHandler(RuntimeException exception) {
String message = exception.getMessage();
message = StringUtils.hasText(message) ? message : "服务器异常";
exception.printStackTrace();
// 解析异常
String jsonParseError = "JSON parse error (.*)";
Matcher jsonParseErrorMatcher = Pattern.compile(jsonParseError).matcher(message);
if (jsonParseErrorMatcher.find()) {
return Result.error(null, 500, "JSON解析异常 " + jsonParseErrorMatcher.group(1));
}
// 数据过大
String dataTooLongError = "Data too long for column (.*?) at row 1";
Matcher dataTooLongErrorMatcher = Pattern.compile(dataTooLongError).matcher(message);
if (dataTooLongErrorMatcher.find()) {
return Result.error(null, 500, dataTooLongErrorMatcher.group(1) + " 字段数据过大");
}
// 主键冲突
String primaryKeyError = "Duplicate entry '(.*?)' for key .*";
Matcher primaryKeyErrorMatcher = Pattern.compile(primaryKeyError).matcher(message);
if (primaryKeyErrorMatcher.find()) {
return Result.error(null, 500, "[" + primaryKeyErrorMatcher.group(1) + "]已存在");
}
// corn表达式错误
String cronExpression = "CronExpression '(.*?)' is invalid";
Matcher cronExpressionMatcher = Pattern.compile(cronExpression).matcher(message);
if (cronExpressionMatcher.find()) {
return Result.error(null, 500, "表达式 " + cronExpressionMatcher.group(1) + " 不合法");
}
log.error("GlobalExceptionHandler===>运行时异常信息:{}", message);
return Result.error(null, 500, message);
}
// 表单验证字段
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<String> handleValidationExceptions(MethodArgumentNotValidException ex) {
String errorMessage = ex.getBindingResult().getFieldErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));
return Result.error(null, 201, errorMessage);
}
// 特定异常处理
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public Result<Object> error(ArithmeticException exception) {
log.error("GlobalExceptionHandler===>特定异常信息:{}", exception.getMessage());
return Result.error(null, 500, exception.getMessage());
}
// 处理SQL异常
@ExceptionHandler(SQLIntegrityConstraintViolationException.class)
@ResponseBody
public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException exception) {
log.error("GlobalExceptionHandler===>处理SQL异常:{}", exception.getMessage());
String message = exception.getMessage();
if (message.contains("Duplicate entry")) {
// 错误信息
return Result.error(ResultCodeEnum.USER_IS_EMPTY);
} else {
return Result.error(ResultCodeEnum.UNKNOWN_EXCEPTION);
}
}
}

View File

@ -1,13 +0,0 @@
package cn.bunny.service;
import cn.bunny.dao.vo.TableInfoVo;
public interface SqlParserService {
/**
* 解析SQL内容
*
* @param sql Sql语句
* @return 表信息内容
*/
TableInfoVo tableInfo(String sql);
}

View File

@ -1,40 +0,0 @@
package cn.bunny.service;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.DatabaseInfoMetaData;
import cn.bunny.dao.vo.TableInfoVo;
import java.util.List;
public interface TableService {
/**
* 获取表属性
*
* @param tableName 表名称
* @return 表属性
*/
TableInfoVo tableMetaData(String tableName);
/**
* 获取所有数据库
*
* @return 所有表信息
*/
List<TableInfoVo> databaseTableList(String tableName);
/**
* 获取列属性
*
* @param tableName 表名称
* @return 当前表所有的列内容
*/
List<ColumnMetaData> tableColumnInfo(String tableName);
/**
* 数据库所有的信息
*
* @return 当前连接的数据库信息属性
*/
DatabaseInfoMetaData databaseInfoMetaData();
}

View File

@ -1,37 +0,0 @@
package cn.bunny.service;
import cn.bunny.dao.dto.VmsArgumentDto;
import cn.bunny.dao.vo.GeneratorVo;
import cn.bunny.dao.vo.VmsPathVo;
import jakarta.validation.Valid;
import org.springframework.http.ResponseEntity;
import java.util.List;
import java.util.Map;
public interface VmsService {
/**
* 生成服务端代码
*
* @param dto VmsArgumentDto
* @return 生成内容
*/
List<GeneratorVo> generator(VmsArgumentDto dto);
/**
* 获取vms文件路径
*
* @return vms下的文件路径
*/
Map<String, List<VmsPathVo>> vmsResourcePathList();
/**
* 打包成zip下载
*
* @param dto VmsArgumentDto
* @return zip 文件
*/
ResponseEntity<byte[]> downloadByZip(@Valid VmsArgumentDto dto);
}

View File

@ -1,27 +0,0 @@
package cn.bunny.service.impl;
import cn.bunny.core.SqlParserCore;
import cn.bunny.dao.entity.TableMetaData;
import cn.bunny.dao.vo.TableInfoVo;
import cn.bunny.service.SqlParserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
@Service
public class SqlParserServiceImpl implements SqlParserService {
/**
* 解析SQL内容
*
* @param sql Sql语句
* @return 表信息内容
*/
@Override
public TableInfoVo tableInfo(String sql) {
TableInfoVo tableInfoVo = new TableInfoVo();
TableMetaData tableMetaData = SqlParserCore.parserTableInfo(sql);
BeanUtils.copyProperties(tableMetaData, tableInfoVo);
return tableInfoVo;
}
}

View File

@ -1,79 +0,0 @@
package cn.bunny.service.impl;
import cn.bunny.core.DatabaseInfoCore;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.DatabaseInfoMetaData;
import cn.bunny.dao.entity.TableMetaData;
import cn.bunny.dao.vo.TableInfoVo;
import cn.bunny.service.TableService;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class TableServiceImpl implements TableService {
@Resource
private DatabaseInfoCore databaseInfoCore;
/**
* 获取表属性
*
* @param tableName 表名称
* @return 表属性
*/
@SneakyThrows
@Override
public TableInfoVo tableMetaData(String tableName) {
TableInfoVo tableInfoVo = new TableInfoVo();
TableMetaData tableMetaData = databaseInfoCore.tableInfoMetaData(tableName);
BeanUtils.copyProperties(tableMetaData, tableInfoVo);
return tableInfoVo;
}
/**
* 获取[当前/所有]数据库表
*
* @return 所有表信息
*/
@SneakyThrows
@Override
public List<TableInfoVo> databaseTableList(String dbName) {
List<TableMetaData> allTableInfo = databaseInfoCore.databaseTableList(dbName);
return allTableInfo.stream().map(tableMetaData -> {
TableInfoVo tableInfoVo = new TableInfoVo();
BeanUtils.copyProperties(tableMetaData, tableInfoVo);
return tableInfoVo;
}).toList();
}
/**
* 获取当前表的列属性
*
* @param tableName 表名称
* @return 当前表所有的列内容
*/
@SneakyThrows
@Override
public List<ColumnMetaData> tableColumnInfo(String tableName) {
return databaseInfoCore.tableColumnInfo(tableName);
}
/**
* 数据库所有的信息
*
* @return 当前连接的数据库信息属性
*/
@SneakyThrows
@Override
public DatabaseInfoMetaData databaseInfoMetaData() {
return databaseInfoCore.databaseInfoMetaData();
}
}

View File

@ -1,153 +0,0 @@
package cn.bunny.service.impl;
import cn.bunny.core.DatabaseInfoCore;
import cn.bunny.core.ResourceFileCore;
import cn.bunny.core.SqlParserCore;
import cn.bunny.core.vms.VmsArgumentDtoBaseVmsGenerator;
import cn.bunny.dao.dto.VmsArgumentDto;
import cn.bunny.dao.entity.ColumnMetaData;
import cn.bunny.dao.entity.TableMetaData;
import cn.bunny.dao.vo.GeneratorVo;
import cn.bunny.dao.vo.VmsPathVo;
import cn.bunny.service.VmsService;
import cn.bunny.utils.VmsUtil;
import cn.hutool.crypto.digest.MD5;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@Service
public class VmsServiceImpl implements VmsService {
@Resource
private DatabaseInfoCore databaseInfoCore;
/**
* 生成服务端代码
*
* @param dto VmsArgumentDto
* @return 生成内容
*/
@Override
public List<GeneratorVo> generator(VmsArgumentDto dto) {
String tableName = dto.getTableName();
String sql = dto.getSql();
// 表格属性名 列信息
TableMetaData tableMetaData;
List<ColumnMetaData> columnInfoList;
// 判断是否有 SQL 如果有SQL 优先解析并生成SQL相关内容
if (StringUtils.hasText(sql)) {
tableMetaData = SqlParserCore.parserTableInfo(sql);
columnInfoList = SqlParserCore.parserColumnInfo(sql);
} else {
tableMetaData = databaseInfoCore.tableInfoMetaData(tableName);
columnInfoList = databaseInfoCore.tableColumnInfo(tableName).stream().distinct().toList();
}
return dto.getPath().stream().map(path -> {
// 生成模板
VmsArgumentDtoBaseVmsGenerator vmsArgumentDtoBaseVmsGenerator = new VmsArgumentDtoBaseVmsGenerator(dto, path);
StringWriter writer = vmsArgumentDtoBaseVmsGenerator.generatorCodeTemplate(tableMetaData, columnInfoList);
// 处理 vm 文件名
path = VmsUtil.handleVmFilename(path, dto.getClassName());
return GeneratorVo.builder()
.code(writer.toString())
.comment(tableMetaData.getComment())
.tableName(tableMetaData.getTableName())
.path(path)
.build();
}).toList();
}
/**
* 获取vms文件路径
*
* @return vms下的文件路径
*/
@SneakyThrows
@Override
public Map<String, List<VmsPathVo>> vmsResourcePathList() {
// 读取当前项目中所有的 vm 模板发给前端
List<String> vmsRelativeFiles = ResourceFileCore.getRelativeFiles("vms");
return vmsRelativeFiles.stream().map(vmFile -> {
String[] filepathList = vmFile.split("/");
String filename = filepathList[filepathList.length - 1].replace(".vm", "");
return VmsPathVo.builder().name(vmFile).label(filename).type(filepathList[0]).build();
})
.collect(Collectors.groupingBy(VmsPathVo::getType));
}
/**
* 打包成zip下载
*
* @param dto VmsArgumentDto
* @return zip 文件
*/
@Override
public ResponseEntity<byte[]> downloadByZip(VmsArgumentDto dto) {
// 需要下载的数据
List<GeneratorVo> generatorVoList = generator(dto);
// 1. 创建临时ZIP文件
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (ZipOutputStream zipOutputStream = new ZipOutputStream(byteArrayOutputStream)) {
// 2. 遍历并创建
generatorVoList.forEach(generatorVo -> {
// zip中的路径
String path = generatorVo.getPath().replace(".vm", "");
// zip中的文件
String code = generatorVo.getCode();
ZipEntry zipEntry = new ZipEntry(path);
try {
// 如果有 / 会转成文件夹
zipOutputStream.putNextEntry(zipEntry);
// 写入文件
zipOutputStream.write(code.getBytes(StandardCharsets.UTF_8));
zipOutputStream.closeEntry();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
} catch (IOException e) {
throw new RuntimeException(e);
}
// 2.1 文件不重名
long currentTimeMillis = System.currentTimeMillis();
String digestHex = MD5.create().digestHex(currentTimeMillis + "");
// 3. 准备响应
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=" + "vms-" + digestHex + ".zip");
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
return new ResponseEntity<>(byteArrayInputStream.readAllBytes(), headers, HttpStatus.OK);
}
}

View File

@ -1,59 +0,0 @@
package cn.bunny.utils;
import cn.bunny.core.TypeConvertCore;
import com.google.common.base.CaseFormat;
import java.util.Map;
public class VmsUtil {
private static final Map<String, String> TYPE_MAPPINGS = Map.of(
"controller", "Controller",
"service", "Service",
"serviceImpl", "ServiceImpl",
"mapper", "Mapper",
"resourceMapper", "Mapper"
);
/**
* 处理 vm 文件名
*
* @param path 文件路径
* @param className 类名
*/
public static String handleVmFilename(String path, String className) {
String[] splitPaths = path.split("/");
int splitPathsSize = splitPaths.length - 1;
// 大驼峰名称
String CamelCase = TypeConvertCore.convertToCamelCase(className, true);
// 小驼峰名称
String camelCase = TypeConvertCore.convertToCamelCase(className);
// 当前文件名
String filename = splitPaths[splitPathsSize];
filename = filename.replace(".vm", "");
String[] split = filename.split("\\.");
// 文件名称
String name = split[0];
// 文件扩展名
String extension = "";
if (split.length >= 2) {
extension = split[1];
}
// 判断是否是 Java 或者 xml 文件
String typeMappingsFilename = TYPE_MAPPINGS.get(name);
typeMappingsFilename = typeMappingsFilename == null ? "" : typeMappingsFilename;
if (filename.contains("java") || filename.contains("xml")) {
filename = CamelCase + typeMappingsFilename + "." + extension;
}
if (filename.contains("vue") && !filename.contains("index")) {
filename = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, camelCase) + "-" + name + "." + extension;
}
splitPaths[splitPathsSize] = filename;
return String.join("/", splitPaths);
}
}

View File

@ -1,7 +0,0 @@
bunny:
master:
host: 192.168.3.137 # localhost
port: 3306
database: auth_admin
username: root
password: "123456"

View File

@ -1,17 +0,0 @@
server:
port: 8800
spring:
profiles:
active: dev
application:
name: generator-code
thymeleaf:
check-template-location: false
datasource:
type: com.zaxxer.hikari.HikariDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://${bunny.master.host}:${bunny.master.port}/${bunny.master.database}?serverTimezone=GMT%2B8&useSSL=false&characterEncoding=utf-8&allowPublicKeyRetrieval=true
username: ${bunny.master.username}
password: ${bunny.master.password}

View File

@ -1,10 +0,0 @@
_ _
| |__ _ _ _ __ _ __ _ _ (_) __ ___ ____ _
| '_ \| | | | '_ \| '_ \| | | | | |/ _` \ \ / / _` |
| |_) | |_| | | | | | | | |_| | | | (_| |\ V | (_| |
|_.__/ \__,_|_| |_|_| |_|\__, | _/ |\__,_| \_/ \__,_|
|___/ |__/
Service Name${spring.application.name}
SpringBoot Version: ${spring-boot.version}${spring-boot.formatted-version}
SpringActive${spring.profiles.active}

View File

@ -1,69 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<contextName>logback</contextName>
<!-- 格式化 年--日 输出 -->
<timestamp key="datetime" datePattern="yyyy-MM-dd"/>
<!--编码-->
<property name="ENCODING" value="UTF-8"/>
<!-- 控制台日志 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<!-- 临界值过滤器 -->
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%cyan([%thread %d{yyyy-MM-dd HH:mm:ss}]) %yellow(%-5level) %green(%logger{100}).%boldRed(%method)-%boldMagenta(%line)-%blue(%msg%n)
</pattern>
<charset>${ENCODING}</charset>
</encoder>
</appender>
<!-- 文件日志 -->
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file>logs/${datetime}/financial-server.log</file>
<append>true</append>
<encoder>
<pattern>%date{yyyy-MM-dd HH:mm:ss} [%-5level] %thread %file:%line %logger %msg%n</pattern>
<charset>${ENCODING}</charset>
</encoder>
</appender>
<!-- 让SpringBoot内部日志ERROR级别 减少日志输出 -->
<logger name="org.springframework" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 让mybatis整合包日志ERROR 减少日志输出 -->
<logger name="org.mybatis" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 让ibatis 日志ERROR 减少日志输出 -->
<logger name="org.apache.ibatis" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 让 tomcat包打印日志 日志ERROR 减少日志输出 -->
<logger name="org.apache" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 我们自己开发的程序为DEBUG -->
<logger name="cn.bunny" level="DEBUG" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<logger name="com.baomidou" level="ERROR" additivity="false">
<appender-ref ref="STOUT"/>
</logger>
<!-- 根日志记录器INFO级别 -->
<root level="INFO">
<appender-ref ref="CONSOLE"/>
<appender-ref ref="FILE"/>
</root>
</configuration>

View File

@ -1,69 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>400 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 400 - Bad Request</h1>
<dl>
<dt>错误说明:因为错误的语法导致服务器无法理解请求信息。</dt>
<dt>原因1客户端发起的请求不符合服务器对请求的某些限制或者请求本身存在一定的错误。</dt>
<dd>解决办法:</dd>
<dd>链接中有特殊字符或者链接长度过长导致,请对应修改.</dd>
<dt>原因2request header 或者 cookie 过大所引起</dt>
<dd>解决办法:</dd>
<dd>crtl+shift+delete 快捷键清除cookie.</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,69 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>403 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>403 - Forbidden 禁止访问: 访问被拒绝</h1>
<dl>
<dt>错误说明:禁止访问,服务器拒绝访问</dt>
<dt>原因1未找到默认的索引文件</dt>
<dd>解决办法:</dd>
<dd>IIS中【启用默认内容文档】选项中将默认打开文档修改为程序首页文件格式index.html或者index.php</dd>
<dt>原因2文件夹安全权限导致</dt>
<dd>解决办法:</dd>
<dd>程序文件-右击-属性-安全-Users-修改为读取和执行权限</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,78 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>404 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 50px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>404 - Page Not Found 未找到</h1>
<dl>
<dt>错误说明:请求的页面不存在</dt>
<dt>原因1访问的文档权限不够</dt>
<dd>解决办法:</dd>
<dd>修改文件权限为755windos系统修改目录权限为可写可读。</dd>
<dt>原因2防火墙的原因</dt>
<dd>解决办法:</dd>
<dd>先关闭让防火墙通过WWW服务。</dd>
<dt>原因3站点根目录无默认访问文件</dt>
<dd>解决办法:</dd>
<dd>在根目录中创建index.html或者创建index.php。</dd>
<dt>原因4站点配置目录不正确</dt>
<dd>解决办法:</dd>
<dd>将网站应用程序复制到站点目录中,或者修改站点配置目录指定到应用程序目录中。</dd>
<dt>原因5站点使用了伪静态</dt>
<dd>解决办法:</dd>
<dd>将伪静态规则删除,或者重新编写正确的伪静态规则,或关闭伪静态配置。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,64 +0,0 @@
<!DOCTYPE html>
<html lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8">
<title>500 - 服务器错误</title>
<meta content="width=device-width, maximum-scale=1, initial-scale=1" name="viewport"/>
<style>
html, body {
height: 100%;
}
body {
color: #333;
margin: auto;
padding: 1em;
display: table;
user-select: none;
box-sizing: border-box;
font: lighter 20px "微软雅黑";
}
a {
color: #3498db;
text-decoration: none;
}
h1 {
margin-top: 0;
font-size: 3.5em;
}
main {
margin: 0 auto;
text-align: center;
display: table-cell;
vertical-align: middle;
}
.btn {
color: #fff;
padding: .75em 1em;
background: #3498db;
border-radius: 1.5em;
display: inline-block;
transition: opacity .3s, transform .3s;
}
.btn:hover {
transform: scale(1.1);
}
.btn:active {
opacity: .7;
}
</style>
</head>
<body>
<main>
<h1>:'(</h1>
<p>服务器开小差啦!管理员正在修理中...</p>
<p>还请阁下静候站点恢复~</p>
</main>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>501 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 501 - Not Implemented</h1>
<dl>
<dt>错误说明:服务器没有相应的执行动作来完成当前请求。</dt>
<dt>原因1Web 服务器不支持实现此请求所需的功能</dt>
<dd>解决办法:</dd>
<dd>可以用来HttpWebRequest指定一个UserAgent来试试的有时候你可以换电脑来测试一下的。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,80 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>502 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 50px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 502 - Bad Gateway 没有响应</h1>
<dl>
<dt>错误说明坏的网关http向后端节点请求没有响应</dt>
<dt>原因1DNS 缓冲</dt>
<dd>解决办法:</dd>
<dd>在dos窗口运行 ipconfig /flushdns该命令会刷新DNS缓冲。</dd>
<dt>原因2浏览器代理</dt>
<dd>解决办法:</dd>
<dd>关掉代理。</dd>
<dt>原因3dns 被劫持了即使使用国外的dns也会被劫持</dt>
<dd>解决办法:</dd>
<dd>
去掉VPN服务器的DNS。切换另外的dns。在windows系统中可以在本地网络连接的属性中去掉默认的dns选用国外的dns比如google的或opendns。
</dd>
<dt>原因4php执行超时</dt>
<dd>解决办法:</dd>
<dd>修改/usr/local/php/etc/php.ini 将max_execution_time 改为300。</dd>
<dt>原因5nginx等待时间超时</dt>
<dd>解决办法:</dd>
<dd>适当增加nginx.conf配置文件中FastCGI的timeout时间。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,69 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>503 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 503 - Service Unavailable 服务不可用</h1>
<dl>
<dt>错误说明:服务当前不可用</dt>
<dt>原因1服务不可用状态</dt>
<dd>解决办法:</dd>
<dd>服务器或许就是正在维护或者暂停了,你可以联系一下服务器空间商。</dd>
<dt>原因2程序占用资源太多</dt>
<dd>解决办法:</dd>
<dd>通过设置应用程序池把账户改为NetworkService即可解决。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,81 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>504 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 50px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 504 - Gateway Timeout 网关超时</h1>
<dl>
<dt>错误说明:网关超时,服务器响应时间,达到超出设定的范围</dt>
<dt>原因1后端电脑之间 IP 通讯缓慢而产生</dt>
<dd>解决办法:</dd>
<dd>如果您的 Web 服务器由某一网站托管, 只有负责那个网站设置的人员才能解决这个问题。</dd>
<dt>原因2由于nginx默认的fastcgi进程响应的缓冲区太小造成的错误</dt>
<dd>解决办法:</dd>
<dd>一般默认的fastcgi进程响应的缓冲区是8K这时可以设置大一点在nginx.conf里加入fastcgi_buffers 8
128k这表示设置fastcgi缓冲区为8块128k大小的空间。当然如果在进行某一项即时的操作, 可能需要nginx的超时参数调大点,
例如设置成60秒:send_timeout 60;经过这两个参数的调整一般不会再提示“504 Gateway Time-out”错误问题基本解决。
</dd>
<dt>原因3PHP环境的配置问题</dt>
<dd>解决办法:</dd>
<dd>更改php-fpm的几处配置 把max_children由之前的10改为现在的30这样就可以保证有充足的php-cgi进程可以被使用
把request_terminate_timeout由之前的0s改为60s这样php-cgi进程 处理脚本的超时时间就是60秒可以防止进程都被挂起提高利用效率。
接着再更改nginx的几个配置项减少FastCGI的请求次数尽量维持buffers不变 fastcgi_buffers由 4 64k 改为 2
256k fastcgi_buffer_size 由 64k 改为 128K fastcgi_busy_buffers_size 由 128K 改为 256K
fastcgi_temp_file_write_size 由 128K 改为 256K。 重新加载php-fpm和nginx的配置再次测试如果没有出现“504
Gateway Time-out”错误问题解决。
</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,72 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>505 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 505 - HTTP Version Not Supported</h1>
<dl>
<dt>错误说明HTTP 版本不受支持。</dt>
<dt>原因1您的 Web 服务器不支持,或拒绝支持客户端(如您的浏览器)在发送给服务器的 HTTP 请求数据流中指定的 HTTP
协议版本
</dt>
<dd>解决办法:</dd>
<dd>升级您的 Web 服务器软件。</dd>
<dt>原因2http请求格式的错误</dt>
<dd>解决办法:</dd>
<dd>对照一下自己的代码从打印的信息中终于找到问题所在。可能在请求后面多加了一个空格。http协议真是很严格了。
</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>506 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 506 - Variant Also Negotiates</h1>
<dl>
<dt>错误说明:</dt>
<dt>原因1服务器存在内部配置错误</dt>
<dd>解决办法:</dd>
<dd>被请求的协商变元资源被配置为在透明内容协商中使用自己,因此在一个协商处理中不是一个合适的重点。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>507 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 507 - Insufficient Storage</h1>
<dl>
<dt>错误说明:</dt>
<dt>原因1服务器无法存储完成请求所必须的内容</dt>
<dd>解决办法:</dd>
<dd>这个状况被认为是临时的。WebDAV (RFC 4918)。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>509 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 509 - Bandwidth Limit Exceeded</h1>
<dl>
<dt>错误说明:</dt>
<dt>原因1网站流量已经超出您所购买的方案限制即服务器达到带宽限制</dt>
<dd>解决办法:</dd>
<dd>1.升级方案 2.等到下个月后流量重新计算,网站即可正常浏览。</dd>
</dl>
</div>
</div>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>510 错误 - phpstudy</title>
<meta content="" name="keywords">
<meta content="" name="description">
<meta content="webkit" name="renderer">
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport">
<meta content="black" name="apple-mobile-web-app-status-bar-style">
<meta content="yes" name="apple-mobile-web-app-capable">
<meta content="telephone=no" name="format-detection">
<meta CONTENT="no-cache" HTTP-EQUIV="pragma">
<meta CONTENT="no-store, must-revalidate" HTTP-EQUIV="Cache-Control">
<meta CONTENT="Wed, 26 Feb 1997 08:21:57 GMT" HTTP-EQUIV="expires">
<meta CONTENT="0" HTTP-EQUIV="expires">
<style>
body {
font: 16px arial, 'Microsoft Yahei', 'Hiragino Sans GB', sans-serif;
}
h1 {
margin: 0;
color: #3a87ad;
font-size: 26px;
}
.content {
width: 45%;
margin: 0 auto;
}
.content > div {
margin-top: 200px;
padding: 20px;
background: #d9edf7;
border-radius: 12px;
}
.content dl {
color: #2d6a88;
line-height: 40px;
}
.content div div {
padding-bottom: 20px;
text-align: center;
}
</style>
</head>
<body>
<div class="content">
<div>
<h1>HTTP 510 - Not Extended</h1>
<dl>
<dt>错误说明:</dt>
<dt>原因1获取资源所需要的策略并没有被满足</dt>
<dd>解决办法:</dd>
<dd>需要请求有额外的扩展内容,服务器才能处理请求。</dd>
</dl>
</div>
</div>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

View File

@ -1 +0,0 @@
.page-container[data-v-128c8218]{display:flex;padding:100px}.page-container .pic-404[data-v-128c8218]{width:600px;overflow:hidden}.page-container .pic-404__parent[data-v-128c8218]{width:100%}.page-container .pic-404__child.left[data-v-128c8218]{top:17px;left:220px;width:80px;opacity:0;animation-name:cloudLeft-128c8218;animation-duration:2s;animation-timing-function:linear;animation-delay:1s;animation-fill-mode:forwards}.page-container .pic-404__child.mid[data-v-128c8218]{top:10px;left:420px;width:46px;opacity:0;animation-name:cloudMid-128c8218;animation-duration:2s;animation-timing-function:linear;animation-delay:1.2s;animation-fill-mode:forwards}.page-container .pic-404__child.right[data-v-128c8218]{top:100px;left:500px;width:62px;opacity:0;animation-name:cloudRight-128c8218;animation-duration:2s;animation-timing-function:linear;animation-delay:1s;animation-fill-mode:forwards}@keyframes cloudLeft-128c8218{0%{top:17px;left:220px;opacity:0}20%{top:33px;left:188px;opacity:1}80%{top:81px;left:92px;opacity:1}to{top:97px;left:60px;opacity:0}}@keyframes cloudMid-128c8218{0%{top:10px;left:420px;opacity:0}20%{top:40px;left:360px;opacity:1}70%{top:130px;left:180px;opacity:1}to{top:160px;left:120px;opacity:0}}@keyframes cloudRight-128c8218{0%{top:100px;left:500px;opacity:0}20%{top:120px;left:460px;opacity:1}80%{top:180px;left:340px;opacity:1}to{top:200px;left:300px;opacity:0}}.page-container .bullshit[data-v-128c8218]{width:300px;padding:30px 0;overflow:hidden}.page-container .bullshit__oops[data-v-128c8218]{margin-bottom:20px;font-size:32px;font-weight:700;line-height:40px;color:#1482f0;opacity:0;animation-name:slideUp-128c8218;animation-duration:.5s;animation-fill-mode:forwards}.page-container .bullshit__headline[data-v-128c8218]{margin-bottom:10px;font-size:20px;font-weight:700;line-height:24px;color:#222;opacity:0;animation-name:slideUp-128c8218;animation-duration:.5s;animation-delay:.1s;animation-fill-mode:forwards}.page-container .bullshit__info[data-v-128c8218]{margin-bottom:30px;font-size:13px;line-height:21px;color:gray;opacity:0;animation-name:slideUp-128c8218;animation-duration:.5s;animation-delay:.2s;animation-fill-mode:forwards}.page-container .bullshit__return-home[data-v-128c8218]{display:block;float:left;width:110px;height:36px;font-size:14px;line-height:36px;color:#fff;text-align:center;cursor:pointer;background:#1482f0;border-radius:100px;opacity:0;animation-name:slideUp-128c8218;animation-duration:.5s;animation-delay:.3s;animation-fill-mode:forwards}@keyframes slideUp-128c8218{0%{opacity:0;transform:translateY(60px)}to{opacity:1;transform:translateY(0)}}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
.database-info[data-v-5045df9f]{display:flex;justify-content:space-between;flex-wrap:wrap;flex-direction:column}.database-info p[data-v-5045df9f]{margin:5px 0 0}

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{h as v,c as a,a as f,p as s,b as t,q as e,t as l,j as c}from"./vendor-BT0L8wkZ.js";import{_ as d}from"./index-BZjZ3Az-.js";const i="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJgAAACKCAMAAABhAnODAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAMAUExURUdwTPf6/v////f6/v////////////z9//////////////////7+//v///f6/v////f5/vz///////////////j6/vf7/v////////////v8//////j7/v7+//////////////////////////////////////v8/+nx/fv9//b6/vr7/v////f5/vj7//////j7/vj7//f5/vD2/f///////////////+jy/P////////j6//////f6/v////f7/vj6/vf6/vL3/f////////j7/vv8//////3///f6/vf6/vb6/v////r8//f7/fL3/P///////////+jw/PT4/v3+//////////////7+//b6/v///////+jx/P///+jy/f////f6/uz0/eny/PT9/+jx/PT4/uz0/f////f6/vb6/vv9//z9//////3+//r8//f6/vj7/+ny/P////f6/////////+jw/Pf6/v////f6/vj7/v////f6/fT4//j7//b7//////b6/evy/P///+vz/P////////T3/v///+jx/P3+/////+nx+/f6/v///////+jw/Pj6/v///+nx/P///+vz/P////////////j7/vj7//H2/P///+zz/Pb6/v////////////P3/v39/////+/1/v///+jx++jx/Pj6/unx/ff6/+fx/Pf6/+jx/Ony/Ojx/Pz+//H3/v////7+//b6/vj8//7+//b5/v////b6/uz0/ff6/fj6//v8//j5/fb7//////v9/vn8//v8//f5//f6/vP3/Ojx/ez0/u31/v////f5/f///////////+z0/Pz9/+rz/+nw++30/Or0/fj//+jx/f////////f7//v9/+fw++nw/f////b4/v///+jw/f////P4/vj//+fz+/r8/u/2/unw//////f5/fb6/vb7//////b6/f3+//////L3/vr9/+/1/fT3/ff7/v////n8/vf6/v///+fw+/b5/fP4/f////T4/lxP5j4AAAD6dFJOUwD+9P3lAfb9pvsC/BIO+gnmDM3h7/PtBMLqvPn0NU5AId3+gajrK8T0Fc2/29/S4sXC47/4W8ho+psHMMD8GLvN97nyGfG++h74yMsGbJ/Dddjx5L5E1t/XN9PUjvzo7dHh2uge/sLBtdjs7r/s48rW08bFtMrE8NxS2cAKpy18c2OR0SPPiCnLvv35mdS9bV7z1Tlbl8woy7ToVMuw1c+63qLFM3zOD9i20N+6+GSqT5pLvOfb0Uifrn/ux5e3z4s7G41QVlrEvnzMx7GCaYXt4vw+icDeJG0alHj2jGl56FB5rcAmQfXBInOF13KSlNCEtNSBpOo946pl6lljAAAF7ElEQVR42u3ceVQTRxwH8AVCyk0gUAhKqwFRFAKIgALhEgS5WlBUsCCHCNJntYBCDQL6tGKtVbxqRUXrgYp4lko98BZ7n/a+Sy97X7QO62uRPHgBdjeTzcxm+l6+/2f4PDKZ3+zsb5eiMOdyw8UAZ9/I87VXqx0oQmJ/qfb2eFojkoDUmuvuNgZFvXf9lyQ7mjlnk5bVeBnA1JRRU15Cc+Xwr0CUIKjJqvpo6kYTThQd7S8FPZkl2DfqffKHp+JobZEEpAN1yuzxm5LdU5b50hBRLJSD/rxihRWVcO2K/1QYFG3XkQYG5ElsKNuU1PE0ZLrGycDgnMEFe4GmzSQKf5UqcamW2bVo9ATAkOV4XLWafzpufqIqUjU2j2HxUvo7AuZY34fDdUnJOJPyolTtRwIU2/tWjXvdpIA14k0Ylgct06srK6C9PbLDbTLgyoKnka+lkTBTXukHtEQaixj2KtRvcSHQmlxbpK7TJjCujQAia5IRuuaWwLicR8HAgKc5MpdLItQXeQHAZT8y2ApUE0wdC1SuBiiXxFRo2NdxMC6TGUBgmL0C6h82GggNS4VyLbUUGnYUyhU9EwgMC4tG/UUigv3lC7PmJwHBYd2FzUW/H8ni3k2XyAwAU6dia0xM0lk2WDAwGKw32fnfnepg2JapgIFh6sx5KXDej5o7al9TMmC9mZh/rrNRXRHscgFBMHUKDjyQJHED5MF6s5ZU2D1GmBFmhBlhRpgR9n+FiUV9sbAiCobkJBszDHiQCgOvkQqTP0YoDEy4n1AYSA8jFAZEIwiFAR9vQmFgmwOhMLCbVJilEWaEGWGQ2bS1nkCY/XLHno8oAle1EAVbeeWN/r1wVOC6bDJgVieL5QM/6pR482ChoWE2t0Yyfly292azAWH72sQcQzzSWTTNELDkIIhD+9bpRQXCwhJeh73HIf/jVGmFULCMndY6jRZ/IeZcPXaY7fo0PiOKy+VYYV5bTHkN6LMYAHwwl2vh/IaTlskBPljsGRG/wXKWWAJUkQ1h/e0Zz28oJ1cxMpbpb02DWBFtfjyHCk9Hxhr289Crt9u0WRRXIxrbUK6jkLGs2xh6d0+rWzkO62aTl4mQscBXqxmmfVV/M2uPDbo/IXgPOtZud8Zl4uKAFpjnoWyOaehYwSznPGFDuiGz3EZyDzU7Fx1r9hdse0HGprBHOWw+29Cx9mxgPRdOYe2udfNhGsovWI6M9VyKC2vRvszVfDV/ymCbDOEy7/RZFXd/Mnd7k6YN5TIvfryJa+91FaJjp3JKq3oo18nIWPEfRnDuCR0g28wrx7UOW7IAGUv+rLZTzRWw7e+0MgfdT3Gn1mda9imhYf8gY63J1H452wjtckbFWpwBceX4E7SLfhgNawbU/Y+5w6FdXUhY0g1wt//K4f9haxGwZOsh274b4F3b9Wel74c9w2+SQLvsECzz8E9wnRdu5sdv+QD+PC7TDNoVp+cyb7FSl9Z8hVAzP9xdp3PVj+BdJXotXLo+ghRTAusy0WcjGKJz30J3y8s3JJhnvqkHj8d37x61PbFqep5W11TeV7CTIvS5lbzrRiU37GOermdW690V8G7nIuS7Ckd+LQFD7g0VzMtiWdZ4XRHNDOL/yNHQ1um9jUo0a6vTrVDE3U1jdowd1K9vxuMw6SH9nmtma+o+UKe5SftW5/LjOYKicMDuLiK76vqugaMxlx/db4zm1/UWhrcwlx9ed2zf3PH5cNzlh9+t5O7uf3GXH76wO7jLD3YY3/KDGca//GCFSYPMKQJhTg+GUhR5MH3LDyaY/uUHD8zVnaIIhM3C8gIGvWE5IdjeP6IPDFn5YUo9b5j1pFgKY6o2H5rIC1aM/2VFNp+WFuoKQ1t+OA47v1ynCwx1+eFM9TvNkDD05UdLzN8+MUc7DEf5gTgtO35sDCcMT/mBisPmQ9msMNdMypDxfr+UEYat/OiQ7188OBiWE+JCEZGwT6ZpwMQexLw7j6KsvjlRoYZhLj88Enr8WEv3nWIvisDYdv5JGdOf/wBvCt5Mksy8ZAAAAABJRU5ErkJggg==",j={class:"page-container"},A={class:"bullshit"},n=d(v({__name:"404",setup(v){const d=l();return(v,l)=>(f(),a("div",j,[l[2]||(l[2]=s('<div class="pic-404" data-v-128c8218><img alt="404" class="pic-404__parent" src="/static/png/404-D6_y3Jr2.png" data-v-128c8218><img alt="404" class="pic-404__child left" src="'+i+'" data-v-128c8218><img alt="404" class="pic-404__child mid" src="'+i+'" data-v-128c8218><img alt="404" class="pic-404__child right" src="'+i+'" data-v-128c8218></div>',1)),t("div",A,[l[1]||(l[1]=s('<div class="bullshit__oops" data-v-128c8218>OOPS!</div><div class="bullshit__info" data-v-128c8218> All rights reserved <a href="https://wallstreetcn.com" style="color:#20a0ff;" target="_blank" data-v-128c8218>wallstreetcn</a></div><div class="bullshit__headline" data-v-128c8218>The webmaster said that you can not enter this page...</div><div class="bullshit__info" data-v-128c8218> Please check that the URL you entered is correct, or click the button below to return to the homepage. </div>',4)),t("a",{class:"bullshit__return-home",href:"/",onClick:l[0]||(l[0]=e((v=>c(d).replace("/")),["prevent"]))}," Back to home ")])]))}}),[["__scopeId","data-v-128c8218"]]);export{n as default};

View File

@ -1,2 +0,0 @@
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["static/js/404-DYq3ki41.js","static/js/vendor-BT0L8wkZ.js","static/css/vendor-lSrybVH6.css","static/css/404-XvabTZcV.css","static/js/index-DwLjqHOd.js","static/js/index-Dn1v0MTU.js","static/js/table-R7-h5oL5.js","static/js/index-DNjCtrgM.js","static/css/index-DFq_RgoD.css"])))=>i.map(i=>d[i]);
import{o as e,c as t,a as n,b as r,d as o,r as s,e as a,f as i,g as c,s as l,h as d,u,i as m,j as p,N as f,w as h,k as _,l as y,T as v,m as E,n as g}from"./vendor-BT0L8wkZ.js";!function(){const e=document.createElement("link").relList;if(!(e&&e.supports&&e.supports("modulepreload"))){for(const e of document.querySelectorAll('link[rel="modulepreload"]'))t(e);new MutationObserver((e=>{for(const n of e)if("childList"===n.type)for(const e of n.addedNodes)"LINK"===e.tagName&&"modulepreload"===e.rel&&t(e)})).observe(document,{childList:!0,subtree:!0})}function t(e){if(e.ep)return;e.ep=!0;const t=function(e){const t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),"use-credentials"===e.crossOrigin?t.credentials="include":"anonymous"===e.crossOrigin?t.credentials="omit":t.credentials="same-origin",t}(e);fetch(e.href,t)}}();const w={},P=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){document.getElementsByTagName("link");const e=document.querySelector("meta[property=csp-nonce]"),n=(null==e?void 0:e.nonce)||(null==e?void 0:e.getAttribute("nonce"));r=Promise.allSettled(t.map((e=>{if((e=function(e){return"/"+e}(e))in w)return;w[e]=!0;const t=e.endsWith(".css"),r=t?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${e}"]${r}`))return;const o=document.createElement("link");return o.rel=t?"stylesheet":"modulepreload",t||(o.as="script"),o.crossOrigin="",o.href=e,n&&o.setAttribute("nonce",n),document.head.appendChild(o),t?new Promise(((t,n)=>{o.addEventListener("load",t),o.addEventListener("error",(()=>n(new Error(`Unable to preload CSS for ${e}`))))})):void 0})))}function o(e){const t=new Event("vite:preloadError",{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then((t=>{for(const e of t||[])"rejected"===e.status&&o(e.reason);return e().catch(o)}))},b=[{path:"/error",component:()=>P((()=>import("./404-DYq3ki41.js")),__vite__mapDeps([0,1,2,3])),meta:{hidden:!0}}],L=(e,t)=>{const n=e.__vccOpts||e;for(const[r,o]of t)n[r]=o;return n},O={class:"container m-auto"},x={class:"container mx-auto"};const A=L({},[["render",function(e,a){const i=s("router-view");return n(),t("div",O,[a[0]||(a[0]=r("h1",{class:"mt-4 text-center font-bold font-size-[22px] c-primary"},"代码生成器",-1)),r("main",x,[o(i)]),a[1]||(a[1]=r("footer",{class:"my-4 text-center"},[r("p",null,"© 2025 Bunny.保留所有权利.")],-1))])}]]),j=[...[{path:"/redirect",component:A,meta:{hidden:!0},children:[{path:"/redirect/:path(.*)",component:()=>P((()=>import("./index-DwLjqHOd.js")),__vite__mapDeps([4,1,2]))}]}],...[{path:"/",name:"/",component:A,redirect:"/home",meta:{transition:"fade"},children:[{path:"/home",name:"home",component:()=>P((()=>import("./index-Dn1v0MTU.js")),__vite__mapDeps([5,1,2,6]))},{path:"/generator-code",name:"generatorCode",component:()=>P((()=>import("./index-DNjCtrgM.js")),__vite__mapDeps([7,1,2,6,8]))}]}],...b],k=a({history:i(),routes:j,scrollBehavior:()=>({left:0,top:0,behavior:"smooth"})}),S=c();const T={install(t){(e=>{e.use(k)})(t),function(e){S.use(l),e.use(S)}(t),(t=>{t.use(e)})(t)}};const I=L(d({setup(){window.$message=u()}}),[["render",function(e,t,n,r,o,s){return" "}]]);g(d({__name:"App",setup:e=>(e,t)=>{const r=s("router-view");return n(),m(p(f),null,{default:h((()=>[o(p(_),null,{default:h((()=>[o(I),o(p(y),null,{default:h((()=>[o(r,null,{default:h((({Component:e,route:t})=>[o(v,{name:t.meta.transition||"fade-transform",mode:"out-in"},{default:h((()=>[(n(),m(E(e),{key:t.path}))])),_:2},1032,["name"])])),_:1})])),_:1})])),_:1})])),_:1})}})).use(T).mount("#app");export{L as _};

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
import{t as e,d as t,v as a,x as l,y as n,h as r,z as s,A as i,c as o,a as c,w as u,j as d,B as m,C as p,F as b,b as g,D as y,E as f,G as v}from"./vendor-BT0L8wkZ.js";import{u as h,g as k}from"./table-R7-h5oL5.js";function D(){const l=e(),n=e=>{l.replace({path:"/generator-code",query:{tableName:e.tableName}}).then()};return[{title:"序号",key:"no",titleAlign:"center",align:"center",render:(e,t)=>t+1},{title:"数据库名称",key:"tableCat",titleAlign:"center",align:"center",render:e=>t(a,{type:"primary"},{default:()=>[e.tableCat]})},{title:"表类型",key:"tableType",titleAlign:"center",align:"center",render:e=>t(a,null,{default:()=>[e.tableType]})},{title:"表名",key:"tableName",titleAlign:"center",align:"center",render:e=>t(a,{type:"info",onClick:()=>n(e)},{default:()=>[e.tableName]})},{title:"注释内容",key:"comment",titleAlign:"center",align:"center",render:e=>t(a,{type:"info",onClick:()=>n(e)},{default:()=>[e.comment]})}]}const L=({node:e,option:t})=>l(n,null,{trigger:()=>e,default:()=>t.comment}),N={class:"mt-2"},x=r({__name:"index",setup(e){const l=h(),{tableList:n,dbList:r,tableListLoading:x,currentDatabaseName:A}=s(l),_=e=>{l.currentDatabaseName=null!=e?e:void 0,l.getDatabaseTableList()},C=()=>{return e=this,t=null,a=function*(){const e=yield k();200===e.code&&(l.currentDatabaseName=e.data),yield l.getDatabaseTableList()},new Promise(((l,n)=>{var r=e=>{try{i(a.next(e))}catch(t){n(t)}},s=e=>{try{i(a.throw(e))}catch(t){n(t)}},i=e=>e.done?l(e.value):Promise.resolve(e.value).then(r,s);i((a=a.apply(e,t)).next())}));var e,t,a};return i((()=>{C(),l.getDatabaseList()})),(e,l)=>(c(),o(b,null,[t(d(m),{class:"my-2",title:"提示"},{default:u((()=>[g("p",null,[l[2]||(l[2]=y(" 点击 ")),t(d(a),null,{default:u((()=>l[0]||(l[0]=[y("表名")]))),_:1}),l[3]||(l[3]=y(" 或 ")),t(d(a),null,{default:u((()=>l[1]||(l[1]=[y("注释内容")]))),_:1}),l[4]||(l[4]=y(" 跳转 "))]),g("p",N,[l[5]||(l[5]=y(" 数据库共 ")),t(d(a),{type:"info"},{default:u((()=>[y(f(d(n).length),1)])),_:1}),l[6]||(l[6]=y(" 张表 "))]),t(d(v),{"on-update-value":_,options:d(r),"render-option":d(L),value:d(A),class:"mt-2 w-[200px]","clear-filter-after-select":"",clearable:"",placeholder:"选择数据库"},null,8,["options","render-option","value"])])),_:1}),t(d(p),{bordered:!0,columns:d(D)(),data:d(n),loading:d(x)},null,8,["columns","data","loading"])],64))}});export{x as default};

View File

@ -1 +0,0 @@
import{h as a,I as e,t as s,c as r,a as t}from"./vendor-BT0L8wkZ.js";const p=a({__name:"index",setup(a){const p=e(),n=s(),{params:o,query:u}=p,{path:c}=o;return n.replace({path:"/"+c,query:u}),(a,e)=>(t(),r("div"))}});export{p as default};

View File

@ -1 +0,0 @@
var e=(e,t,a)=>new Promise(((s,r)=>{var o=e=>{try{i(a.next(e))}catch(t){r(t)}},n=e=>{try{i(a.throw(e))}catch(t){r(t)}},i=e=>e.done?s(e.value):Promise.resolve(e.value).then(o,n);i((a=a.apply(e,t)).next())}));import{a7 as t,a8 as a,H as s}from"./vendor-BT0L8wkZ.js";const r=t.create({baseURL:"/api",timeout:5e4,headers:{"Content-Type":"application/json;charset=utf-8"},paramsSerializer:e=>a.stringify(e)});r.interceptors.request.use((e=>{const t=localStorage.getItem("accessToken");return t&&(e.headers.Authorization=t),e}),(e=>Promise.reject(e))),r.interceptors.response.use((e=>{if("blob"===e.config.responseType||"arraybuffer"===e.config.responseType)return e;if(200===e.status){const{code:t,message:a}=e.data;return 200!==t&&window.$message.error(a),e.data}return Promise.reject(e.data.message||"Error")}),(e=>{if(e.response.data){const{code:t,message:a}=e.response.data;500===t?window.$message.error(a):window.$message.error(a||"系统出错")}return Promise.reject(e.message)}));const o=()=>r({url:"/table/currentDatabaseName",method:"GET"}),n=s("tableStore",{state:()=>({currentDatabaseName:void 0,databaseInfoMeta:void 0,tableList:[],tableListLoading:!1,dbList:[]}),getters:{},actions:{getDatabaseInfoMeta(){return e(this,null,(function*(){const e=yield r({url:"/table/databaseInfoMetaData",method:"GET"});200===e.code&&(this.databaseInfoMeta=e.data)}))},getDatabaseList(){return e(this,null,(function*(){this.tableListLoading=!0;const e=yield r({url:"/table/databaseList",method:"GET"});if(200!==e.code)return void(this.tableListLoading=!1);const t=e.data.map((e=>({label:e.tableCat,value:e.tableCat,comment:e.comment})));t.unshift({label:"无",value:void 0,comment:"查询全部"}),this.dbList=t,this.tableListLoading=!1}))},getDatabaseTableList(){return e(this,null,(function*(){const e={dbName:this.currentDatabaseName},t=yield(a=e,r({url:"/table/databaseTableList",method:"get",params:a}));var a;this.tableList=t.data}))},getTableMetaData(t){return e(this,null,(function*(){const e=yield(a={tableName:t},r({url:"/table/tableMetaData",method:"get",params:a}));var a;return 200!==e.code?{}:e.data}))},getTableColumnInfo(t){return e(this,null,(function*(){const e=yield(a={tableName:t},r({url:"/table/tableColumnInfo",method:"get",params:a}));var a;return 200!==e.code?{}:e.data}))}}});export{o as g,r as s,n as u};

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@ -1,16 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8"/>
<link href="/favicon.ico" rel="icon" type="image/svg+xml"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>代码生成器</title>
<script type="module" crossorigin src="/static/js/index-BZjZ3Az-.js"></script>
<link rel="modulepreload" crossorigin href="/static/js/vendor-BT0L8wkZ.js">
<link rel="stylesheet" crossorigin href="/static/css/vendor-lSrybVH6.css">
<link rel="stylesheet" crossorigin href="/static/css/index-B0-KdCP2.css">
</head>
<body>
<div id="app"></div>
</body>
</html>

View File

@ -1,65 +0,0 @@
package ${package}.controller;
import cn.bunny.dao.pojo.result.Result;
import cn.bunny.dao.pojo.result.ResultCodeEnum;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import cn.bunny.dao.pojo.result.PageResult;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import java.util.List;
/**
* <p>
* ${comment}表 前端控制器
* </p>
*
* @author ${author}
* @since ${date}
*/
@Tag(name = "${comment}" , description = "${comment}相关接口" )
@RestController
@RequestMapping("${requestMapping}/${classLowercaseName}" )
public class ${classUppercaseName}Controller {
@Autowired
private ${classUppercaseName}Service ${classLowercaseName}Service;
@Operation(summary = "分页查询${comment}" , description = "分页查询${comment}" )
@GetMapping("get${classUppercaseName}List/{page}/{limit}" )
public Result<PageResult<${classUppercaseName}Vo>> get${classUppercaseName}List(
@Parameter(name = "page" , description = "当前页" , required = true)
@PathVariable("page" ) Integer page,
@Parameter(name = "limit" , description = "每页记录数" , required = true)
@PathVariable("limit" ) Integer limit,
${classUppercaseName}Dto dto) {
Page<${classUppercaseName}> pageParams = new Page<>(page, limit);
PageResult<${classUppercaseName}Vo> pageResult = ${classLowercaseName}Service.get${classUppercaseName}List(pageParams, dto);
return Result.success(pageResult);
}
@Operation(summary = "添加${comment}" , description = "添加${comment}" )
@PostMapping("add${classUppercaseName}" )
public Result<String> add${classUppercaseName}(@Valid @RequestBody ${classUppercaseName}AddDto dto) {
${classLowercaseName}Service.add${classUppercaseName}(dto);
return Result.success(ResultCodeEnum.ADD_SUCCESS);
}
@Operation(summary = "更新${comment}" , description = "更新${comment}" )
@PutMapping("update${classUppercaseName}" )
public Result<String> update${classUppercaseName}(@Valid @RequestBody ${classUppercaseName}UpdateDto dto) {
${classLowercaseName}Service.update${classUppercaseName}(dto);
return Result.success(ResultCodeEnum.UPDATE_SUCCESS);
}
@Operation(summary = "删除${comment}" , description = "删除${comment}" )
@DeleteMapping("delete${classUppercaseName}" )
public Result<String> delete${classUppercaseName}(@RequestBody List<Long> ids) {
${classLowercaseName}Service.delete${classUppercaseName}(ids);
return Result.success(ResultCodeEnum.DELETE_SUCCESS);
}
}

View File

@ -1,29 +0,0 @@
package ${package}.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* <p>
* ${comment} Mapper 接口
* </p>
*
* @author ${author}
* @since ${date}
*/
@Mapper
public interface ${classUppercaseName}Mapper extends BaseMapper<${classUppercaseName}> {
/**
* * 分页查询${comment}内容
*
* @param pageParams ${comment}分页参数
* @param dto ${comment}查询表单
* @return ${comment}分页结果
*/
IPage<${classUppercaseName}Vo> selectListByPage(@Param("page") Page<${classUppercaseName}> pageParams, @Param("dto") ${classUppercaseName}Dto dto);
}

View File

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${package}.mapper.${classUppercaseName}Mapper">
<!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="${classUppercaseName}">
#foreach($field in ${columnInfoList})
<id column="${field.columnName}" property="${field.fieldName}"/>
#end
</resultMap>
<!-- 通用查询结果列 -->
<sql id="Base_Column_List">
${baseColumnList}
</sql>
<!-- 分页查询${comment}内容 -->
<select id="selectListByPage" resultType="${voClassType}">
select
base.*,
create_user.username as create_username,
update_user.username as update_username
from $tableName base
left join sys_user create_user on create_user.id = base.create_user
left join sys_user update_user on update_user.id = base.update_user
<where>
base.is_deleted = 0
#foreach($field in $columnInfoList)
<if test="dto.${field.fieldName} != null and dto.${field.fieldName} != ''">
and base.${field.columnName} like CONCAT('%',#{dto.${field.fieldName}},'%')
</if>
#end
</where>
</select>
</mapper>

View File

@ -1,79 +0,0 @@
package ${package}.service.impl;
import cn.bunny.dao.pojo.result.PageResult;
import ${package}.mapper.${classUppercaseName}Mapper;
import ${package}.service.${classUppercaseName}Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* ${comment} 服务实现类
* </p>
*
* @author Bunny
* @since ${date}
*/
@Service
public class ${classUppercaseName}ServiceImpl extends ServiceImpl<${classUppercaseName}Mapper, ${classUppercaseName}> implements ${classUppercaseName}Service {
/**
* * ${comment} 服务实现类
*
* @param pageParams ${comment}分页查询page对象
* @param dto ${comment}分页查询对象
* @return 查询分页${comment}返回对象
*/
@Override
public PageResult<${classUppercaseName}Vo> get${classUppercaseName}List(Page<${classUppercaseName}> pageParams, ${classUppercaseName}Dto dto) {
IPage<${classUppercaseName}Vo> page = baseMapper.selectListByPage(pageParams, dto);
return PageResult.<${classUppercaseName}Vo>builder()
.list(page.getRecords())
.pageNo(page.getCurrent())
.pageSize(page.getSize())
.total(page.getTotal())
.build();
}
/**
* 添加${comment}
*
* @param dto ${comment}添加
*/
@Override
public void add${classUppercaseName}(@Valid ${classUppercaseName}AddDto dto) {
// 保存数据
${classUppercaseName} ${classLowercaseName} =new ${classUppercaseName}();
BeanUtils.copyProperties(dto, ${classLowercaseName});
save(${classLowercaseName});
}
/**
* 更新${comment}
*
* @param dto ${comment}更新
*/
@Override
public void update${classUppercaseName}(@Valid ${classUppercaseName}UpdateDto dto) {
// 更新内容
${classUppercaseName} ${classLowercaseName} =new ${classUppercaseName}();
BeanUtils.copyProperties(dto, ${classLowercaseName});
updateById(${classLowercaseName});
}
/**
* 删除|批量删除${comment}
*
* @param ids 删除id列表
*/
@Override
public void delete${classUppercaseName}(List<Long> ids) {
removeByIds(ids);
}
}

Some files were not shown because too many files have changed in this diff Show More