当前位置: 首页 > news >正文

最新SpringBoot+SpringCloud+Nacos微服务框架分享

文章目录

  • 前言
  • 一、服务规划
  • 二、架构核心
    • 1.cloud的pom
    • 2.gateway的异常handler
    • 3.gateway的filter
    • 4、admin的pom
    • 5、admin的登录核心
  • 三、code-helper分享
  • 总结


前言

        最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要是确实时间紧,倒排的,其实个人一直不认可倒排估工时法,但是现在发现不管是大公司、小故事都喜欢这样搞。无语!工时不应该是一个纯粹的根据经验 + 个人能力做了可行性的一个耗时预估值吗?怎么就爱打骨折哦,不应该考虑堆人么?
跑远了,今天主要是简单分享最新版本springBoot3.5.0 + SpringCloud2025.0.0 + nacos2.5.1的架构规划与搭建分享。


一、服务规划

        这里也只是简单规划下,不是按照最小粒度规划的,应该说就是简单按照业务线 + 基础组件的思路规划的。毕竟是个小公司,任务时间紧急,又没有专业运维,所以就简单规划下,后期服务器都不知道能不能配置全。
在这里插入图片描述

  • commom:通用jar包,这里将一些常用的集成、工具类、异常处理、子服务拦截器放这里
  • gateway:网关就不解释了,这里唯一要说的就是它是一个使用webflux响应式 Web 框架,完全非阻塞,支持响应式流背压。就是因为无关用这个,子服务用mvc,所以网关里的gateway接入redis是单独的,整个就不引入common,因为common里的统一异常处理是基于web的,与webflux不兼容,引入会报错。
  • device:业务线的子服务,涉密,就不多说了
  • admin:业务线的子服务,主要是后端管理的接口
  • third:业务线的子服务,用于处理第三方服务
  • exchange:业务线的子服务,涉密
  • code-helper:代码生成助手,我这里是mybatisplus基于自定义的模版生成基础代码,为了后面CRUD快,花不少时间集成、写自定义模版。
    其实,按道理应该还细化下common,分util、exception、mysqlplus、redis等等,但是看看兄弟们,就这么点人力,有这个基础微服务就行了。

二、架构核心

1.cloud的pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.rs.gov</groupId><artifactId>gov-cloud</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><name>gov-cloud</name><description>gov-cloud</description><modules><module>gov-common</module><module>gov-gateway</module><module>gov-device</module><module>gov-admin</module><module>gov-third</module><module>gov-exchange</module><module>gov-code-helper</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.0</version></parent><properties><java.version>17</java.version><maven.compiler.source>${java.version}</maven.compiler.source><maven.compiler.target>${java.version}</maven.compiler.target><spring-boot.version>3.5.0</spring-boot.version><spring-cloud.version>2025.0.0</spring-cloud.version><spring-cloud-alibaba.version>2023.0.1.2</spring-cloud-alibaba.version><gov.common.version>0.0.1</gov.common.version><mybatisPlus.version>3.5.7</mybatisPlus.version><hutool.version>5.8.32</hutool.version><redisson.version>3.36.0</redisson.version><commons-io.version>2.19.0</commons-io.version><netty.macSupport.version>4.1.121.Final</netty.macSupport.version><skipTests>true</skipTests></properties><dependencyManagement><dependencies><!-- Spring Boot --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!-- Spring Cloud --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- Spring Cloud Alibaba --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><pluginManagement><plugins><!-- Maven Compiler --><plugin><artifactId>maven-compiler-plugin</artifactId><version>3.14.0</version><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin><!-- Spring Boot Plugin --><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version></plugin></plugins></pluginManagement></build></project>

2.gateway的异常handler


import com.fasterxml.jackson.databind.ObjectMapper;
import com.rs.gov.govgateway.entity.RestResponse;
import lombok.SneakyThrows;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** @author zwmac*/
@Component
public class GatewayExceptionHandler implements ErrorWebExceptionHandler {private final ObjectMapper objectMapper = new ObjectMapper();@SneakyThrows@Overridepublic Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.OK);response.getHeaders().setContentType(MediaType.APPLICATION_JSON);RestResponse<?> restResponse = RestResponse.build(500, ex.getMessage());DataBuffer buffer = response.bufferFactory().wrap(objectMapper.writeValueAsBytes(restResponse));return response.writeWith(Mono.just(buffer));}
}

3.gateway的filter

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.rs.gov.govgateway.constant.CommonConstant;
import com.rs.gov.govgateway.constant.HeaderConstant;
import com.rs.gov.govgateway.entity.RestResponse;
import com.rs.gov.govgateway.entity.Tenant;
import com.rs.gov.govgateway.entity.UserAccount;
import com.rs.gov.govgateway.entity.UserInfo;
import com.rs.gov.govgateway.props.WhiteListProp;
import com.rs.gov.govgateway.service.redis.RedisService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;/*** 网关拦截** @author zwmac*/
@Component
@Slf4j
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GatewayFilter implements GlobalFilter, Ordered {@Value("${server.servlet.context-path:/gov-gateway}")private String contextPath;private final RedisService redisService;private final WhiteListProp whiteListProp;@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String url = request.getURI().getPath();log.info("接收到请求:{}", url);// 跨域放行if (request.getMethod() == HttpMethod.OPTIONS) {response.setStatusCode(HttpStatus.OK);return Mono.empty();}// 授权ServerHttpRequest mutatedRequest = this.auth(exchange);if (mutatedRequest == null) {return this.responseBody(exchange, 401, "请先登录");}// 用新的 request 构造新的 exchange 再放行ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();return chain.filter(mutatedExchange);}/*** 认证*/private ServerHttpRequest auth(ServerWebExchange exchange) {ServerHttpRequest request = exchange.getRequest();AntPathMatcher antPathMatcher = new AntPathMatcher();String path = request.getURI().getPath();if (whiteListProp.getEnable() && CollectionUtils.isNotEmpty(whiteListProp.getUrls())) {boolean whiteMatch = whiteListProp.getUrls().stream().anyMatch(url -> antPathMatcher.match(url.replace(contextPath, ""), path.replace(contextPath, "")));if (whiteMatch) {return request;}}String token = this.getToken(request);if (StringUtils.isEmpty(token)) {return null;}Object userObj = redisService.get(CommonConstant.PREFIX_USER_TOKEN + token);if (userObj == null) {return null;}UserInfo userInfo = JSONUtil.toBean(userObj.toString(), UserInfo.class);UserAccount accountInfo = userInfo.getAccountInfo();Tenant currentTenant = userInfo.getCurrentTenant();if (currentTenant != null && currentTenant.getId() != null) {accountInfo.setCurrentTenantId(currentTenant.getId());}return request.mutate().header(HeaderConstant.USERID, accountInfo.getUserId()).header(HeaderConstant.USERNAME, URLEncoder.encode(accountInfo.getSysUserName(), StandardCharsets.UTF_8)).header(HeaderConstant.USER_ACCOUNT, URLEncoder.encode(accountInfo.getLoginName(), StandardCharsets.UTF_8)).header(HeaderConstant.TENANT_ID, accountInfo.getCurrentTenantId()).build();}/*** 获取token*/public String getToken(ServerHttpRequest request) {HttpCookie tokenCookie = request.getCookies().getFirst(CommonConstant.X_ACCESS_TOKEN);if (tokenCookie == null) {String token = request.getHeaders().getFirst(CommonConstant.X_ACCESS_TOKEN);if (StrUtil.isNotEmpty(token)) {return token;}return request.getQueryParams().getFirst("token");}return tokenCookie.getValue();}/*** 设置响应体**/public Mono<Void> responseBody(ServerWebExchange exchange, Integer code, String msg) {String message = JSONUtil.parse(RestResponse.build(code, msg)).toString();byte[] bytes = message.getBytes(StandardCharsets.UTF_8);return this.responseHeader(exchange).getResponse().writeWith(Flux.just(exchange.getResponse().bufferFactory().wrap(bytes)));}/*** 设置响应体的请求头*/public ServerWebExchange responseHeader(ServerWebExchange exchange) {ServerHttpResponse response = exchange.getResponse();response.getHeaders().add(HttpHeaders.CONTENT_TYPE, "application/json");return exchange.mutate().response(response).build();}@Overridepublic int getOrder() {return -100;}}

4、admin的pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.rs.gov</groupId><artifactId>gov-cloud</artifactId><version>0.0.1-SNAPSHOT</version></parent><artifactId>gov-admin</artifactId><name>gov-admin</name><description>gov-admin</description><dependencies><!-- 通用jar --><dependency><groupId>com.rs.gov</groupId><artifactId>gov-common</artifactId><version>${gov.common.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- Spring Boot Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Nacos 注册与发现 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><!-- Nacos 拉取配置依赖 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!-- Feign 依赖 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency><!-- Spring Boot Actuator(可选) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path></annotationProcessorPaths></configuration></plugin><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

5、admin的登录核心

//生存token,直接用户名+token的secret生成String token = DigestUtil.md5Hex(userName + tokenSecret).toLowerCase();UserInfo userInfo = new UserInfo();UserAccount userAccount = new UserAccount();BeanUtil.copyProperties(sysUser, userAccount);userAccount.setLoginName(userName);userInfo.setAccountInfo(userAccount);userInfo.setToken(token);String userInfoJsonStr = JSONUtil.toJsonStr(userInfo);redisService.save(CommonConstant.PREFIX_USER_TOKEN + token, userInfoJsonStr, tokenExpire);return RestResponse.success(userInfoJsonStr);

        登录前面的校验密码、查库就不说了,这里的核心是要在redis缓存,返回token给前端,前端所有接口请求都在在请求头里放token。

三、code-helper分享

        这个是代码生成的,基于最新的mybatis-plus-generator3.5.12,这个倒是可以完全分享,是不是应该单写一篇?请允许我这么坏,有需要的请移步到下一篇。


总结

        好了,就写到这里,希望能帮到大家。现在虽然部门人少,但是团队的技术氛围不错,人少归人少,但是我们语种可全乎了,有.net、C++、QT、WPF、前端、java后端。公司个人都可承接软、硬、软硬组合项目哦,我们就是这么自信,请允许我小小的骄傲,因为我有一个好平台的依靠!
        行业前景也挺好,如果现在从事的能打开市场,按照老板的愿景,3年后我们就年产过亿,可以上市了。加油!!!!

相关文章:

  • 72道Nginx高频题整理(附答案背诵版)
  • Vue.js教学第二十二章:vue实战项目商城项目
  • 实现安全、经济、节约、环保的智慧交通开源了
  • ceph集群调整pg数量实战(下)
  • Minktec 柔性弯曲传感器应用:3D 脊柱姿势追踪与人体活动识别
  • 股指期货的基差怎么衡量贴水率?
  • OpenLayers 获取地图状态
  • css~word-break属性
  • 数据结构-链表OJ-回文链表,如何将时间复杂度控制为O(N),空间复杂度控制为O(1)?
  • 增加Label Verified
  • Mac M4 芯片运行大模型指南,包括模型微调与推理
  • 一个完整的日志收集方案:Elasticsearch + Logstash + Kibana+Filebeat (三)
  • <6>-MySQL表的增删查改
  • PostgreSQL 安装与配置全指南(适用于 Windows、macOS 与主流 Linux 发行版)
  • 【Elasticsearch】Elasticsearch 近实时高速查询原理
  • Android高性能音频与图形开发:OpenSL ES与OpenGL ES最佳实践
  • 如何判断对象是否存活
  • DevSecOps实践:CI/CD流水线集成SAST工具的完整指南
  • 从零开始搭建现代化 Monorepo 开发模板:TypeScript + Rollup + Jest + 持续集成完整指南
  • python/java环境配置
  • 清远网站制作/白银网站seo
  • 巨鹿做网站哪家好/保定seo排名外包
  • 自己怎么做外贸网站/冯宗耀seo教程
  • 网站建设项目延期验收申请/百度软件商店
  • 个人网站制作图片/正规淘宝代运营去哪里找
  • 做游戏 做网站/免费放单平台无需垫付