java 微服务架构搭建笔记

项目介绍

1. 技术选型

1.1 核心框架

  • SpringBoot 2.3.0.RELEASE
  • SpringCloud Hoxton.SR6
  • SpringCloud Alibaba 2.1.1.RELEASE
    • nacos (注册中心 | 配置中心)
    • sentinel (限流熔断)
    • seata (分布式事务——可选)
  • SpringSecurity 5.3.2
  • Spring WebMvc
  • 数据持久层框架
    • mybatis plus
  • 三方服务

 

2. 系统架构图

 

image-20201211150932396

 

image-20201211143903748

 

3. 环境地址

 

名称地址备注
MySQL 192.168.30.4:3306 用户名/密码:root/Ams_2020
Redis 192.168.30.20:6379  
Nacos 192.168.30.20:8848 用户名/密码:nacos/nacos ——(ZMUU_IP)
SVN 192.168.30.4:8443/svn/java-rms  
MQ XXX.XXX.XXX.XXX 开发到了在补充
FILE XXX.XXX.XXX.XXX 开发到了在补充
ELK XXX.XXX.XXX.XXX 开发到了在补充

 

4. 后端服务

 

4.1 系统服务

项目名称说明端口
注册中心服务 使用nacos 默认8848
配置中心服务 使用nacos 默认8848
rms-gateway 网关服务 8080
rms-auth 认证中心服务 8081
sentinel控制台 限流熔断监控中心 8082

4.2 业务服务

项目名称说明端口
rms-core 档案核心业务服务 9090
rms-base 系统基础信息服务 9091
rms-file 文件服务 9092
rms-flow 工作流服务 9093
rms-xxx 其他服务待拆分(搜索...) todo

5. 目录结构

5.1 全局服务目录

rms
│
├─rms-auth					 //认证服务
│
├─rms-common				 //公共模块
│  ├─rms-common-cache		 //缓存模块
│  ├─rms-common-core		 //核心模块
│  ├─rms-common-log			 //日志模块
│  ├─rms-common-mybatis		 //mybtais配置
│  ├─rms-common-security	 //安全模块
│  └─rms-common-swagger		 //swagger配置
│
├─rms-gateway				 //网关服务
│
├─rms-modules				 //业务服务
│  ├─rms-base				 //系统服务
│  ├─rms-core				 //核心服务
│  ├─rms-file				 //文件服务
│  └─rms-flow				 //流程服务
│  └─rms-xxx				 //其他业务服务
│
├─rms-modules-api			 //服务接口模块--对应业务服务
│   ├─rms-base-api			 //系统接口模块
│   ├─rms-core-api			 //核心接口模块
│   └─rms-file-api			 //文件接口模块
│
└─pom.xml				     //全局pom文件(依赖版本控制)
 

5.2 详细模块目录

5.2.1 公共模块

rms-common-core
│ 
├─src
│  ├─main
│  │  ├─java
│  │  │  └─com.rms.common.core			
│  │  │           ├─constant			//公共常量定义
│  │  │           ├─enums				//公共枚举定义
│  │  │           ├─exception			//公共异常--controller层异常、service层异常
│  │  │           ├─model				//公共模型
│  │  │           └─util				//公共工具类
│  │  └─resources
│  │      └─META-INF					//springboot启动需要被扫描的组件
│  └─test							   
│      └─java						    //单元测试
└─ pom.xml							    //依赖管理

 

5.2.2 业务模块

rms-base rms-base-api基础系统服务为例说明业务模块目录结构

rms-base
│ 
├─src
│  ├─main
│  │  ├─java
│  │  │  └─com.rms.base			    	//包:命名com.rms.模块名称
│  │  │         ├─annotation			//自定义注解(非必须)
│  │  │         ├─aspect		    	//切面(非必须)
│  │  │         ├─controller			//controller层
│  │  │         ├─constant				//常量	
│  │  │         ├─enums					//枚举
│  │  │         ├─mapper				//mapper接口
│  │  │         └─service				//业务接口
│  │  │         └─impl					//业务实现
│  │  │         └─RmsBaseApplication.java //服务启动类
│  │  └─resources				    	//资源服务目录(spring.yml配置文件、日志等)
│  │      ├─mapper				    	//mapper-xml文件
│  │      └─META-INF					//springboot启动需要被扫描的组件
│  └─test							    //测试目录
│      └─java			         	    //在该目录下创建创建包,单元测试类
└─ pom.xml							    //本模块依赖及打包方式等
 

服务模块所使用到的数据实体定义到相应的xxx-xxx-api模块中(为其他业务模块提供本模块api)

rms-base-api
├─src
│  └─main
│      ├─java
│      │  └─com.rms.base.api
│      │         ├─dto					//数据传输对象
│      │         ├─entity				//数据库实体
│      │         ├─feign				//feign远程调用接口
│      │         └─vo					//展示对象
│      └─resources
│          └─META-INF					//springboot启动需要被扫描的组件
└─pom.xml							

⚾️环境要求

1. 准备工作

  • JDK: 1.8+
  • Maven: 3.3+
  • MySQL: 5.7+
  • IntelliJ IDEA | eclipse

2. IDEA插件

  • lombok(必装)
  • MyBatisX (选装)

3. 软件安装

3.1 IDEA安装

详情参见软件安装包中idea文件夹,内附安装及破解教程。

3.2 JDK安装配置

运行软件安装包下jdk-8u221-windows-x64下一步即可,安装完成后需修改配置文件:

  1. 新创建环境变量:JAVA_HOME=jdk安装目录 CLASSPATH=%JAVA_HOME%\lib\tools.jar
  2. 编辑Path变量添加: %JAVA_HOME%\bin %JAVA_HOME%\jre\bin

image-20201211110836459

3.3 MAVEN安装

  1. 解压软件安装包目录下的apache-maven-3.5.3-bin文件,解压后打开conf\settings.xml文件
  2. 搜索<localRepository>标签,替换标签内的内容为自己本机的磁盘目录(存储远程仓库下载的jar包)

image-20201211125951651

image-20201211130652806

3.4 IDEA离线安装插件

IDEA导航栏选择file -> settings 搜索 plugins,点击齿轮图标选择Install Plugin from Disk... 选择lombook.jar

image-20201211130509147

3.5 NACOS安装(选装)

解压nacos-server-1.4.0安装,修改conf\application.properties文件,结尾添加如下属性:

### 数据库配置 ###
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://127.0.0.1:3306/nacos?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=UTC
db.user=username
db.password=password
 

application.properties配置文件其他属性说明

server.servlet.contextPath=/nacos #项目访问路径前缀
server.port=8848 #访问端口(8848珠峰高度),可以自己指定
 

启动

  • 双击执行解压后nacos文件夹下bin\startup.cmd(默认集群方式)
  • startup.cmd -m standalone单机模式启动 (✔)

访问路径:127.0.0.1:8848/nacos 默认用户名/密码:nacos/nacos

4. 软件安装包说明

文件名备注
idea idea安装包(含破解教程)
RedisDesktopManager redis可视化工具
apache-maven-3.5.3-bin maven仓库
jdk-8u221-windows-x64 jdk安装
lombok lombok插件(idea版)
nacos_config nacos配置文件(启动nacos服务后通过web控制台导入)
nacos-server-1.4.0 nacos注册中心|配置文件中心
powerdesigner 数据库表结构设计

 

 

🚀启动

 

1. 配置文件

 

项目启动之前需要修改resources\bootstrap.yml配置文件,修改注册中心、配置中心地址。

 

spring:
  profiles:
    active: dev
  application:
    name: rms-base #服务名称
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.10.161:8848 #注册中心地址
      config:
        server-addr: 192.168.10.161:8848 #配置信息地址
        file-extension: yml
        shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}

 

 

启动nacos后修改数据库、redis等其他服务器地址,如下图所示:

 

image-20201211182427917

 

2. 后端服务启动顺序

 

  1. 先启动 MySQL 、redis 、nacos
  2. 启动除 rms-gateway 之外的其他服务
  3. 启动 rms-gateway 服务

 

各个服务启动成功后可以在nacos服务列表中查看服务状态,列表中显示即代表启动成功。

 

image-20201211182656615

🔫业务异常

业务异常是自定义异常,本质是返回给前端JSON格式对象。在某些场景下抛出业务异常结束请求,抛出异常后由全局异常处理器进行拦截并构造JSON对象返回。RMS系统中业务异常分为HttpReqException ServiceException两种类型,两者都是继承自RuntimeException

1. 自定义异常类型

  • HttpReqException:在controller层抛出该异常类型
  • ServiceException:在业务层抛出异常类型

以ServiceException为例说明自定异常,构造函数ServiceException(ICodeEnum error)内传入ICodeEnum接口的具体实现枚举类型。

public class ServiceException extends RuntimeException {
    
    ICodeEnum error; //定义异常枚举格式

    public ServiceException(ICodeEnum error){
        super(error.getMsg());
        this.error = error;
    }

    public ICodeEnum getCodeEnum(){
        return this.error;
    }
}
 

使用自定义异常方法

/*
1.传入枚举值CommonCodeEnum.ERROR_NOT_FOUND
2.CommonCodeEnum 实现 ICodeEnum接口,统一异常枚格式
*/
throw new ServiceException(CommonCodeEnum.ERROR_NOT_FOUND);
 

响应返回对象

{
    "code": 20002"msg":"此操作需要登录系统!"
}
 

2. 全局异常处理器

rms-common-security模块定义GlobalExceptionHandler全局异常处理器 ,在业务层抛出异常后由全局异常处理器进行捕获。捕获后将构造ResponseResult(包括code和msg字段)对象进行统一的结果返回,前端根据请求响应状态码判定失败后统一对返回结果进行解析,从而友好的提示给用户。

@RestControllerAdvice
public class GlobalExceptionHandler {
    /*
    * 参数绑定、参数校验失败
    * HttpStatus.BAD_REQUEST
    * */
    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseResult validatorExceptionHandler(Exception exception) {}
    
    /*
    * controller层请求相关错误捕获
    * HttpStatus.BAD_REQUEST
    * */
    @ExceptionHandler(HttpReqException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseResult httpReqExceptionHandler(HttpReqException e){}
    
    /*
    * service层抛出业务异常捕获
    * HttpStatus.INTERNAL_SERVER_ERROR
    * */
    @ExceptionHandler(ServiceException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseResult serviceExceptionHandler(ServiceException e) {}
    
    /*
    * 捕获其他未定义异常
    * HttpStatus.INTERNAL_SERVER_ERROR
    * */
    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResponseResult ExceptionHandler(Exception e) {}

}


参数校验

参数校验框架使用hibernate validator,通过pom引入spring-boot-starter-validation依赖进行导入。通过注解完成参数合法性校验,在参数非法时将抛出BindException,由全局异常处理器进行捕获处理。

1. 使用方法

👉 在参数前添加@Validated注解

@ApiOperation("新增用户")
@PostMapping("/addUser")
public ResponseResult login(@RequestBody @Validated SysUserModel sysUserModel) {
    //...
}
 

👉 在参数实体对应的字段上添加相应的校验注解即可实现参数校验功能。

@Data
@NoArgsConstructor
@ApiModel
public class SysUserModel {

    /*
    1.当校验失败时,将返回message上的信息
    2.{sys.user.loginName.empty} 失败信息统一配置在messages.properties文件下:
    	---------------------------------------
    	sys.user.loginName.length=用户名长度非法
        sys.user.password.length=密码长度非法
        sys.user.userId.empty=用户ID为空
        sys.user.deptId.empty=部门ID为空
        ---------------------------------------
    */
    @NotBlank(message = "{sys.user.id.empty}",groups = GroupEdit.class)
    private String id;
    
    @NotBlank(message = "{sys.user.username.empty}",groups = {GroupAdd.class, GroupEdit.class}) 
    @ApiModelProperty("用户名")
    private String username;

    @NotBlank(message = "{sys.user.password.empty}",groups = {GroupAdd.class, GroupEdit.class})
    @ApiModelProperty("密码")
    private String password;

}

2. 常用校验注解

注解名称功能说明
@Null 检查该字段为空
@NotNull 不能为null
@NotBlank 不能为空,常用于检查空字符串
@NotEmpty 不能为空,多用于检测list是否size是0
@Max 该字段的值只能小于或等于该值
@Min 该字段的值只能大于或等于该值
@Past 检查该字段的日期是在过去
@Future 检查该字段的日期是否是属于将来的日期
@Email 检查是否是一个有效的email地址
@Pattern(regex=,flag=) 被注释的元素必须符合指定的正则表达式
@Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@Size(min=, max=) 检查该字段的size是否在min和max之间,可以是字符串、数组、集合、Map等
@Length(min=,max=) 检查所属的字段的长度是否在min和max之间,只能用于字符串
@AssertTrue 用于boolean字段,该字段只能为true
@AssertFalse 该字段的值只能为false

3. 校验分组

开发过程中大部分情况下CRUD都会使用同一个POJO。不同业务,可能参数校验规则不同,使用同一个POJO就需要进行分组校验。如:新增用户场景下不需要检验id属性,修改字段下必须要检验id属性。

以上面的新增用户接口为例,@Validated注解添加value属性,指定分组。

@ApiOperation("新增用户")
@PostMapping("/addUser")
public ResponseResult login(@RequestBody @Validated(GroupAdd.class) SysUserModel sysUserModel) {
    //...
}


POJO的相应字段上的@Validated注解设置groups属性。

public class SysUserModel {

    /*
    1.设置groups属性用于分组检验
    */
    @NotBlank(message = "{sys.user.id.empty}",groups = GroupEdit.class)
    private String id;
    
    @NotBlank(message = "{sys.user.username.empty}",groups = {GroupAdd.class, GroupEdit.class}) 
    @ApiModelProperty("用户名")
    private String username;

    @NotBlank(message = "{sys.user.password.empty}",groups = {GroupAdd.class, GroupEdit.class})
    @ApiModelProperty("密码")
    private String password;

}

服务调用

服务之间的远程调用使用Netflix开源的Feign框架,Feign是一种声明式、模板化的HTTP客户端。在Spring Cloud中使用Feign,可以做到使用HTTP请求远程服务时能与调用本地方法一样的编码体验,开发者完全感知不到这是一个远程方法,更感知不到这是一个HTTP请求。

1. Feign的使用

rms-auth服务调用rms-base服务——根据用户名查询用户信息为例:

image-20201222083848145

  1. rms-base-api模块(com.rms.base.api.feign包下)创建调用接口IUserClient

    @FeignClient(
        value = AppConstants.RMS_BASE, //定义Feign指向的服务ID
        contextId = "userClient", 
        fallbackFactory = UserClientFallback.class //回调
    )
    public interface IUserClient {
    
        /*
         * 根据用户名获取用户信息
         * */
        @GetMapping("/user/info/{username}")
        public SysUserModel loadUserByUserame(@PathVariable("username") String username);
        
    }


 

posted @   zwbsoft  阅读(944)  评论(0编辑  收藏  举报
编辑推荐:
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示