1. JDK17+Gradle8搭建项目
获取代码请关注公众号 算法小生,回复cloud即可,不懂的欢迎加群沟通
1.1 环境准备
- IDEA2023
- JDK17
- Gradle8
1.2 多模块项目创建
我们删除src目录,如下图所示
我们新建模块api、common、client,并删除无用内容,结果如下
1.3 依赖修改
我们修改父模块build.gradle中内容如下
plugins {
id 'java'
id 'org.springframework.boot' version '3.1.0'
id 'io.spring.dependency-management' version '1.1.0'
}
archivesBaseName = "cloud-api"
bootJar.enabled = true
// 版本信息
ext {
set('springCloudVersion', "2022.0.3")
lombokVersion = '1.18.26'
}
// 通用配置
subprojects {
// 使用插件
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
// 项目默认名称与版本
group = 'online.shenjian'
version = '1.0-SNAPSHOT'
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
}
// 指定JDK版本
sourceCompatibility = '17'
jar.enabled = true
// 指定仓库地址
repositories {
mavenLocal()
mavenCentral()
}
dependencyManagement {
// 导入SpringBoot和SpringCloud依赖Bom
imports {
mavenBom org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
}
我们修改common中build.gradle内容如下
archivesBaseName = "common"
// 取消打包为 bootJar 可独立运行包,因为 common 只是一个普通的jar包
// 如果是需要独立运行的jar包,这个就改为true
bootJar.enabled = false
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
implementation 'com.alibaba:fastjson:2.0.35'
implementation 'cn.hutool:hutool-core:5.8.20'
implementation 'org.apache.commons:commons-lang3:3.12.0'
}
我们修改client中build.gradle内容如下
archivesBaseName = "client"
bootJar.enabled = false
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.1.0'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
}
我们修改api中build.gradle内容如下
archivesBaseName = "api"
bootJar.enabled = true
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
implementation 'org.springframework.cloud:spring-cloud-starter-bootstrap'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.apache.commons:commons-lang3:3.12.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.1.0'
implementation 'com.alibaba:fastjson:2.0.35'
implementation 'com.nimbusds:nimbus-jose-jwt:9.31'
implementation 'com.mysql:mysql-connector-j'
implementation 'com.alibaba:druid-spring-boot-3-starter:1.2.18'
implementation 'org.springframework.boot:spring-boot-starter-test'
compileOnly 'org.projectlombok:lombok:1.18.28'
annotationProcessor 'org.projectlombok:lombok:1.18.28'
implementation 'cn.hutool:hutool-core:5.8.20'
// 本地方法调用依赖
implementation 'net.java.dev.jna:jna:5.13.0'
// 引入本地的 common 模块
implementation project(':common')
implementation project(':client')
testImplementation 'junit:junit:4.13.1'
}
我们点击gradle刷新按钮,耐心等待相关文件下载
1.4 client模块代码编写
我们新建文件,结构如下
ResponseCode.java代码如下
public enum ResponseCode {
SUCCESS(200, "成功"),
FAIL(-1, "失败"),
UN_AUTHORIZED(401, "用户未授权,请联系管理员"),
TOKEN_EXPIRATION(402, "登录已过期,请退出后重新登录"),
LICENSE_EXPIRED(403, "授权已失效");
private Integer val;
private String des;
ResponseCode(Integer val, String des) {
this.val = val;
this.des = des;
}
public Integer val() {
return val;
}
public String des() {
return des;
}
}
ResponseVO.java代码如下
@Data
public class ResponseVo<T> implements Serializable {
private Integer code;
private String message;
private T data;
public static ResponseVo message(int code, String message) {
ResponseVo responseVo = new ResponseVo();
responseVo.setCode(code);
responseVo.setMessage(message);
return responseVo;
}
public static ResponseVo message(ResponseCode responseCode) {
ResponseVo responseVo = message(responseCode.val(), responseCode.des());
return responseVo;
}
public static ResponseVo message(int code, String message, Object data) {
ResponseVo responseVo = new ResponseVo();
responseVo.setCode(code);
responseVo.setMessage(message);
responseVo.setData(data);
return responseVo;
}
public static ResponseVo success() {
ResponseVo responseVo = new ResponseVo();
responseVo.setCode(ResponseCode.SUCCESS.val());
return responseVo;
}
public static ResponseVo success(Object data) {
ResponseVo responseVo = new ResponseVo();
responseVo.setCode(ResponseCode.SUCCESS.val());
responseVo.setData(data);
return responseVo;
}
public static ResponseVo error(String message) {
ResponseVo responseVo = new ResponseVo();
responseVo.setCode(ResponseCode.FAIL.val());
responseVo.setMessage(message);
return responseVo;
}
}
UserInfoDto.java代码如下
@Schema(description = "用户信息DTO")
@Data
public class UserInfoDto {
@Schema(description = "用户ID")
private String userId;
@Schema(description = "用户名")
private String username;
@Schema(description = "登录账号")
private String account;
@Schema(description = "密码")
private String password;
@Schema(description = "机构编码")
private String orgCode;
@Schema(description = "机构名称")
private String orgName;
@Schema(description = "角色ID")
private String roleId;
@Schema(description = "用户角色")
private String roleName;
}
CloudClient.java代码如下
@FeignClient(value = "cloud", contextId = "cloud")
@Component
public interface CloudClient {
@PostMapping(value = "/login", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "登录", tags = "用户管理")
ResponseVo login(@RequestBody UserInfoDto userInfoDto);
}
1.5 api模块代码编写
新建CloudController.java类,代码如下
@RestController
public class CloudController implements CloudClient {
@Override
public ResponseVo login(UserInfoDto userInfoDto) {
return ResponseVo.success("登录成功");
}
}
新建CloudApplication.java类,代码如下
@SpringBootApplication
public class CloudApplication {
public static void main(String[] args) {
SpringApplication.run(CloudApplication.class, args);
}
}
新建bootstrap.yml,代码如下
spring:
application:
name: cloud
profiles:
active: dev
1.6 运行并响应
我们点击CloudApplication.java中run按钮,然后用apifox工具进行请求,success
2. 集成SpringDoc Swagger3
本文我们实践SpringDoc集成至SpringBoot3中,欢迎大家沟通交流
2.1 引入依赖
我们在build.gradle中引入依赖
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.1.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-api:2.1.0'
2.2 新增SpringDocConfig.java文件
@Configuration
public class SpringDocConfig {
@Bean
public GroupedOpenApi userApi() {
return GroupedOpenApi.builder()
.group("public")
// 指定路径
.pathsToMatch("/**")
// 指定特定的 API 文档信息
.addOpenApiCustomizer(userApiCustomizer())
.build();
}
/**
* 定义 OpenApiCustomizer ,用于指定的 group
* @return
*/
public OpenApiCustomizer userApiCustomizer() {
return openApi -> openApi.info(new io.swagger.v3.oas.models.info.Info()
.title("Cloud API文档")
.version("1.0")
.contact(new io.swagger.v3.oas.models.info.Contact().name("").email("")))
// 接口增加权限校验,如果接口需要,添加 security = { @SecurityRequirement(name = "token")}即可
.components(new Components().addSecuritySchemes("token", new SecurityScheme().type(SecurityScheme.Type.HTTP).scheme("bearer").bearerFormat("JWT")));
}
}
2.3 编写application-dev.yaml文件
springdoc:
swagger-ui:
# swagger-ui地址
path: /springdoc/swagger-ui.html
enabled: true
# 配置本地访问页面
#config-url: /springdoc/api-docs/swagger-config
# 取消默认Swagger访问页面
disable-swagger-default-url: true
# 修复Failed to load remote configuration.
url: /springdoc/api-docs
api-docs:
path: /springdoc/api-docs
2.4 访问Swagger
http://localhost:8080/springdoc/swagger-ui.html
我们修改CloudClient中login方法如下,重启后看下授权区别
@PostMapping(value = "/login", produces = MediaType.APPLICATION_JSON_VALUE)
@Operation(summary = "登录", tags = "用户管理", security = { @SecurityRequirement(name = "token")})
ResponseVo login(@RequestBody UserInfoDto userInfoDto);
我们可以看到方法级别也加了锁,此时如果我们在最上面Authorize处输入token,则调用方法时也会默认传递token
3. 全局异常处理与统一返回封装
3.1 全局异常处理
config目录下GlobalExceptionHandler.java,代码如下
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
@ExceptionHandler(value = MissingServletRequestParameterException.class)
@ResponseBody
public ResponseVo MissingRequestParameter(MissingServletRequestParameterException e) {
return ResponseVo.error(e.getParameterName() + "不能为空");
}
@ExceptionHandler(value = Exception.class)
@ResponseBody
public ResponseVo exceptionHandler(Exception e) {
log.error("系统繁忙,请稍后重试: {}", e.getMessage());
e.printStackTrace();
return ResponseVo.error("系统繁忙,请稍后重试");
}
}
3.2 统一返回封装
config目录下UnitedResponseAdvice.java,代码如下
@RestControllerAdvice
@Slf4j
public class UnitedResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if (body != null && !(body instanceof ResponseVo) && !(body instanceof byte[])) {
// 放行Swagger相关
if (body instanceof TreeMap && ((TreeMap)body).containsKey("oauth2RedirectUrl")) {
return body;
}
return ResponseVo.message(ResponseCode.SUCCESS.val(), ResponseCode.SUCCESS.des(), body);
}
return body;
}
}
欢迎关注公众号算法小生