diff --git a/README.md b/README.md
index de233cb3..5f308c45 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# 项目简述
-项目基于 Spring Boot 2.7 、Spring Security 5.4 、 JWT 、 Redis 、 Mybatis-Plus 、 Knife4j 等技术栈搭建的前后端分离开源权限管理系统。
+项目基于 Spring Boot 3.0 、Spring Security 6.0 、 JWT 、 Redis 、 Mybatis-Plus 、 Knife4j 等技术栈搭建的前后端分离开源权限管理系统。
## 项目特色
-- Spring Boot 2.7 + Vue3 前后端分离单体应用,适合快速开发;
+- Spring Boot 3.0 + Vue3 前后端分离单体应用,适合快速开发;
- Spring Security + JWT 认证鉴权方案;
- 基于 RBAC 模型的权限设计,细粒度接口方法、按钮级别权限控制。
diff --git a/pom.xml b/pom.xml
index 135810a7..ce3d03db 100644
--- a/pom.xml
+++ b/pom.xml
@@ -13,7 +13,7 @@
org.springframework.boot
spring-boot-starter-parent
- 2.7.6
+ 3.0.2
@@ -21,14 +21,13 @@
17
17
- 1.18.24
5.7.21
8.0.19
1.2.4
- 3.5.2
+ 3.5.3
- 3.0.2
+ 4.0.0
2.7.6
@@ -49,7 +48,7 @@
org.projectlombok
lombok
- ${lombok.version}
+ true
@@ -98,7 +97,7 @@
com.github.xiaoymin
- knife4j-spring-boot-starter
+ knife4j-openapi3-jakarta-spring-boot-starter
${knife4j.version}
@@ -160,20 +159,20 @@
- ${project.artifactId}
org.springframework.boot
spring-boot-maven-plugin
- ${parent.version}
-
-
-
- repackage
-
-
-
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/com/youlai/system/common/base/BasePageQuery.java b/src/main/java/com/youlai/system/common/base/BasePageQuery.java
index 620ed156..e9c1dac8 100644
--- a/src/main/java/com/youlai/system/common/base/BasePageQuery.java
+++ b/src/main/java/com/youlai/system/common/base/BasePageQuery.java
@@ -1,7 +1,7 @@
package com.youlai.system.common.base;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
+
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
@@ -11,12 +11,12 @@ import lombok.Data;
* @date 2021/2/28
*/
@Data
-@ApiModel
+@Schema
public class BasePageQuery {
- @ApiModelProperty(value = "页码", example = "1")
+ @Schema(description = "页码", example = "1")
private int pageNum = 1;
- @ApiModelProperty(value = "每页记录数", example = "10")
+ @Schema(description = "每页记录数", example = "10")
private int pageSize = 10;
}
diff --git a/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java b/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java
index 0d87d9c1..4669cec9 100644
--- a/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java
+++ b/src/main/java/com/youlai/system/common/exception/GlobalExceptionHandler.java
@@ -18,9 +18,9 @@ import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;
-import javax.servlet.ServletException;
-import javax.validation.ConstraintViolation;
-import javax.validation.ConstraintViolationException;
+import jakarta.servlet.ServletException;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
import java.sql.SQLSyntaxErrorException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
diff --git a/src/main/java/com/youlai/system/common/util/ResponseUtils.java b/src/main/java/com/youlai/system/common/util/ResponseUtils.java
index 458f7721..d969b1fe 100644
--- a/src/main/java/com/youlai/system/common/util/ResponseUtils.java
+++ b/src/main/java/com/youlai/system/common/util/ResponseUtils.java
@@ -3,10 +3,12 @@ package com.youlai.system.common.util;
import cn.hutool.json.JSONUtil;
import com.youlai.system.common.result.Result;
import com.youlai.system.common.result.ResultCode;
+
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import javax.servlet.http.HttpServletResponse;
+// import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
diff --git a/src/main/java/com/youlai/system/config/SecurityConfig.java b/src/main/java/com/youlai/system/config/SecurityConfig.java
index 7df9e20a..66108783 100644
--- a/src/main/java/com/youlai/system/config/SecurityConfig.java
+++ b/src/main/java/com/youlai/system/config/SecurityConfig.java
@@ -57,8 +57,10 @@ public class SecurityConfig {
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
- return (web) -> web.ignoring()
- .antMatchers("/api/v1/auth/login", "/webjars/**", "/doc.html", "/swagger-resources/**", "/v3/api-docs");
+ return (web) -> web.ignoring().requestMatchers("/api/v1/auth/login", "/webjars/**", "/doc.html",
+ "/swagger-resources/**",
+ "/v3/api-docs/swagger-config",
+ "/v3/api-docs");
}
@Bean
diff --git a/src/main/java/com/youlai/system/config/SwaggerConfig.java b/src/main/java/com/youlai/system/config/SwaggerConfig.java
index 33154141..2d35b6bd 100644
--- a/src/main/java/com/youlai/system/config/SwaggerConfig.java
+++ b/src/main/java/com/youlai/system/config/SwaggerConfig.java
@@ -1,82 +1,54 @@
package com.youlai.system.config;
-import cn.hutool.core.collection.CollectionUtil;
-import io.swagger.annotations.Api;
+import cn.hutool.core.util.RandomUtil;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-import springfox.documentation.spi.service.contexts.SecurityContext;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.*;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
+
@Configuration
-@EnableSwagger2
public class SwaggerConfig {
- @Bean
- public Docket createRestApi() {
- return new Docket(DocumentationType.OAS_30)
- .apiInfo(apiInfo())
- .groupName("权限服务")
- //是否开启 (true 开启 false隐藏。生产环境建议隐藏)
- //.enable(false)
- .select()
- //扫描的路径包,设置basePackage会将包下的所有被@Api标记类的所有方法作为api
- .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
- //指定路径处理PathSelectors.any()代表所有的路径
- .paths(PathSelectors.any())
- .build().securityContexts(CollectionUtil.newArrayList(securityContext()))
- .securitySchemes(CollectionUtil.newArrayList(apiKey()));
- }
-
/**
- * 配置基本信息
+ * 根据@Tag 上的排序,写入x-order
*
- * @return
+ * @return the global open api customizer
*/
@Bean
- public ApiInfo apiInfo() {
- return new ApiInfoBuilder()
- //设置文档标题(API名称)
- .title("SpringBoot单体应用开发文档")
- //文档描述
- .description("快速开发文档-接口说明")
- //版本号
- .version("1.0.0")
- //联系人
- .contact(new Contact("", "http://localhost", ""))
- .build();
+ public GlobalOpenApiCustomizer orderGlobalOpenApiCustomizer() {
+ return openApi -> {
+ if (openApi.getTags() != null) {
+ openApi.getTags().forEach(tag -> {
+ Map map = new HashMap<>();
+ map.put("x-order", RandomUtil.randomInt(0, 100));
+ tag.setExtensions(map);
+ });
+ }
+ if (openApi.getPaths() != null) {
+ openApi.addExtension("x-test123", "333");
+ openApi.getPaths().addExtension("x-abb", RandomUtil.randomInt(1, 100));
+ }
+
+ };
}
- private List securitySchemes() {
- List apiKeyList= new ArrayList<>();
+ @Bean
+ public OpenAPI customOpenAPI() {
+ return new OpenAPI()
+ .info(new Info()
+ .title("XXX用户系统API")
+ .version("1.0")
- apiKeyList.add(HttpAuthenticationScheme.JWT_BEARER_BUILDER.name("Authorization").build());
- return apiKeyList;
+ .description("Knife4j集成springdoc-openapi示例")
+ .termsOfService("http://doc.xiaominfo.com")
+ .license(new License().name("Apache 2.0")
+ .url("http://doc.xiaominfo.com")));
}
- private ApiKey apiKey() {
- return new ApiKey("Authorization", "Authorization", "header");
- }
-
- List defaultAuth() {
- AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
- AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
- authorizationScopes[0] = authorizationScope;
- return CollectionUtil.newArrayList(new SecurityReference("Authorization", authorizationScopes));
- }
-
- private SecurityContext securityContext() {
- return SecurityContext.builder()
- .securityReferences(defaultAuth())
- //.forPaths(PathSelectors.regex(".*?208.*$"))
- .build();
- }
}
diff --git a/src/main/java/com/youlai/system/config/WebMvcConfig.java b/src/main/java/com/youlai/system/config/WebMvcConfig.java
index 81f05a57..92911c96 100644
--- a/src/main/java/com/youlai/system/config/WebMvcConfig.java
+++ b/src/main/java/com/youlai/system/config/WebMvcConfig.java
@@ -15,9 +15,9 @@ import org.springframework.http.converter.json.MappingJackson2HttpMessageConvert
import org.springframework.validation.beanvalidation.SpringConstraintValidatorFactory;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import javax.validation.Validation;
-import javax.validation.Validator;
-import javax.validation.ValidatorFactory;
+import jakarta.validation.Validation;
+import jakarta.validation.Validator;
+import jakarta.validation.ValidatorFactory;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.List;
diff --git a/src/main/java/com/youlai/system/controller/AuthController.java b/src/main/java/com/youlai/system/controller/AuthController.java
index 7e56505a..d1cbc950 100644
--- a/src/main/java/com/youlai/system/controller/AuthController.java
+++ b/src/main/java/com/youlai/system/controller/AuthController.java
@@ -4,8 +4,8 @@ package com.youlai.system.controller;
import com.youlai.system.common.result.Result;
import com.youlai.system.pojo.dto.TokenResult;
import com.youlai.system.security.JwtTokenManager;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -13,7 +13,7 @@ import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
-@Api(tags = "认证管理")
+@Tag(name = "认证管理")
@RestController
@RequestMapping("/api/v1/auth")
@RequiredArgsConstructor
@@ -21,7 +21,7 @@ public class AuthController {
private final AuthenticationManager authenticationManager;
private final JwtTokenManager jwtTokenManager;
- @ApiOperation(value = "登录")
+ @Operation(summary = "登录")
@PostMapping("/login")
public Result login(
@RequestParam String username,
@@ -41,7 +41,7 @@ public class AuthController {
return Result.success(tokenResult);
}
- @ApiOperation(value = "注销")
+ @Operation(summary = "注销")
@DeleteMapping("/logout")
public Result login() {
SecurityContextHolder.clearContext();
diff --git a/src/main/java/com/youlai/system/controller/FileController.java b/src/main/java/com/youlai/system/controller/FileController.java
index ea602b19..a58c34c3 100644
--- a/src/main/java/com/youlai/system/controller/FileController.java
+++ b/src/main/java/com/youlai/system/controller/FileController.java
@@ -3,15 +3,15 @@ package com.youlai.system.controller;
import com.youlai.system.common.result.Result;
import com.youlai.system.pojo.vo.file.FileInfo;
import com.youlai.system.service.FileService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
-@Api(tags = "文件接口")
+@Tag(name = "文件接口")
@RestController
@RequestMapping("/api/v1/files")
@RequiredArgsConstructor
@@ -20,19 +20,19 @@ public class FileController {
private final FileService fileService;
@PostMapping
- @ApiOperation(value = "文件上传")
+ @Operation(summary = "文件上传")
public Result uploadFile(
- @ApiParam("表单文件对象") @RequestParam(value = "file") MultipartFile file
+ @Parameter(name ="表单文件对象") @RequestParam(value = "file") MultipartFile file
) {
FileInfo fileInfo = fileService.uploadFile(file);
return Result.success(fileInfo);
}
@DeleteMapping
- @ApiOperation(value = "文件删除")
+ @Operation(summary = "文件删除")
@SneakyThrows
public Result deleteFile(
- @ApiParam("文件路径") @RequestParam String filePath
+ @Parameter(name ="文件路径") @RequestParam String filePath
) {
boolean result = fileService.deleteFile(filePath);
return Result.judge(result);
diff --git a/src/main/java/com/youlai/system/controller/SysDeptController.java b/src/main/java/com/youlai/system/controller/SysDeptController.java
index 7e88115d..18fa6de3 100644
--- a/src/main/java/com/youlai/system/controller/SysDeptController.java
+++ b/src/main/java/com/youlai/system/controller/SysDeptController.java
@@ -6,13 +6,14 @@ import com.youlai.system.pojo.form.DeptForm;
import com.youlai.system.pojo.query.DeptQuery;
import com.youlai.system.pojo.vo.dept.DeptVO;
import com.youlai.system.service.SysDeptService;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
-import javax.validation.Valid;
+import jakarta.validation.Valid;
import java.util.List;
/**
@@ -21,7 +22,7 @@ import java.util.List;
* @author haoxr
* @date 2020/11/6
*/
-@Api(tags = "部门接口")
+@Tag(name = "部门接口")
@RestController
@RequestMapping("/api/v1/dept")
@RequiredArgsConstructor
@@ -29,30 +30,30 @@ public class SysDeptController {
private final SysDeptService deptService;
- @ApiOperation(value = "获取部门列表")
+ @Operation(summary = "获取部门列表")
@GetMapping
public Result> listDepartments(DeptQuery queryParams) {
List list = deptService.listDepartments(queryParams);
return Result.success(list);
}
- @ApiOperation(value = "获取部门下拉选项")
+ @Operation(summary = "获取部门下拉选项")
@GetMapping("/options")
public Result> listDeptOptions() {
List