項目介紹
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. 系統架構圖


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下一步即可,安裝完成后需修改配置文件:
- 新創建環境變量:
JAVA_HOME=jdk安裝目錄CLASSPATH=%JAVA_HOME%\lib\tools.jar - 編輯Path變量添加:
%JAVA_HOME%\bin%JAVA_HOME%\jre\bin

3.3 MAVEN安裝
- 解壓軟件安裝包目錄下的
apache-maven-3.5.3-bin文件,解壓后打開conf\settings.xml文件 - 搜索
<localRepository>標簽,替換標簽內的內容為自己本機的磁盤目錄(存儲遠程倉庫下載的jar包)

3.4 IDEA離線安裝插件
IDEA導航欄選擇file -> settings 搜索 plugins,點擊齒輪圖標選擇Install Plugin from Disk... 選擇lombook.jar

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等其他服務器地址,如下圖所示:

2. 后端服務啟動順序
- 先啟動 MySQL 、redis 、nacos
- 啟動除 rms-gateway 之外的其他服務
- 啟動 rms-gateway 服務
各個服務啟動成功后可以在nacos服務列表中查看服務狀態,列表中顯示即代表啟動成功。

🔫業務異常
業務異常是自定義異常,本質是返回給前端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地址 | |
| @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服務——根據用戶名查詢用戶信息為例:

-
在
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); }
