
### 架构
* Ubuntu 22.04 + JDK 17.0.2 + Maven 3.8.1
* Docker 25.0.4 + Docker-Compose 2.6.1 + Gogs + Drone
* MySQL 8.0.31 + Redis 5.0.14.1
* Springboot 3.1.1 + Mybatis-plus 3.5.3.2

### 配置
Maven 配置 (用户配置) (阿里源)
```
./configuration/.m2/settings.xml
```

### 部署
#### 1.自动打包
目前项目使用自动部署
#### 2.手动打包
第三方JAR包放在 `./configuration/.m2/repository` 目录，并使用命令添加到本地 Maven 仓库
```
mvn install:install-file -Dfile=configuration/.m2/repository/ziniao-sdk-java-5.1.0.jar -DgroupId=com.ziniao -DartifactId=ziniao-sdk-java -Dversion=5.1.0 -Dpackaging=jar
```

首次部署需在 pom.xml 中去除 `copy-dependencies` 注释，启用分包功能 (将包分离到 `libs` 文件夹中)，像这样：
```
/home/www/project/BackendSys/libs
```
将分离出来的文件，然后上传到远程服务器目录

执行打包命令：
```
mvn clean package
mvn clean package -P dev
```

#### 在 Ubuntu 部署
```
// 安装 nodup (Ubuntu-22.04 虚拟机可能需要安装)
apt install perforate -y

// 启动 (libs文件夹与.jar包同级)
// sh backendsys.sh restart
sh backendsys.sh start

// 监视日志
tail -f backendsys.log
```

### 开发指南

监听控制台消息 (单点)
```
http://xxxx.com/api/log/stream/watch?sign={配置文件固定密钥}
```
#### 自定义工具类

###### SecurityUtil

注意：`@Anonymous` 下不可调用，否则会抛出错误
```java
/*
 * (不需要实例化)
 * SecurityUtil.getUserId()
 * 
 * (需要实例化)
 * @Autowired
 * private SecurityUtil securityUtil;
 * 
 * securityUtil.hasPermission("3.2.1")
 * securityUtil.hasPermissions(Arrays.asList("3.2.1", "3.2.2"))
 * securityUtil.hasPermissions(Arrays.asList("3.2.1", "3.2.2"), MatchType.OR)
 *
 * 权限注解
 * @PreAuthorize("@sr.hasPermission('3.2.1')")
 * @PreAuthorize("@sr.hasPermissions(T(java.util.Arrays).asList('3.2.1', '3.2.2'))")
 */
 ```

#### 自定义注解

- 免登录权限 (No token)
```
@Anonymous
@GetMapping("/api/getAuthDemo")
public Result getAuthDemo() {
..
```
另外， `/api/public/**` 也是免登录可访问的接口

#### 开发规范

###### 命名风格
- 入参：下划线命名 (例如: `user_id`)
- 变量：小驼峰命名 (例如: `userList`)
- 常量：全大写 (例如: `APPID`)

###### MySQL

- 禁止使用外键

###### Mybatis
- 禁止使用 where 1=1 (`update` 操作)
- 字段非空时：
```
SELECT COALESCE(uf.nickname, '') nickname, ..
```

- SQL时间字段创建统一规范：
```
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
```

- 命名为 `*_count` 的统计字段，值是 Long 类型，例如：
```
Long user_count = Convert.toLong(sysUserRole.get("user_count"));
```

###### 其他规范
- 创建实体类时，要创建多一个 `Id` 字段，比如 `article_id`，在进行 {查询详情/编辑/删除} 操作时，必须使用该 `article_id` 作为必填参数；





### 其他
##### 项目名称更换
- cmd + Shift + F 将 com.xxx 名称进行全局替换；
- 将 src/main/java/com/xxx 名称进行修改


### Future (待加功能)
1.sys_dictionary.sql 字典表重构
- 字段：{ id, dictionary_key, dictionary_value, lang }
- 使用 JSON 作为储存值，例如：{ dictionary_key: "Gender", dictionary_value: "[{\"label\":\"男\",\"value\":1},{\"label\":\"女\",\"value\":2}]" }
- 接口1：查询接口，首次调用Service时，将该值保存到Redis长效缓存
- 接口2：手动更新缓存的接口

2.Nginx均衡负载，双应用，无感知重启