开发规约
yaoye Lv5

整体说明

本文档包含技术栈说明、java 微服务应用、单体动态多模块开发规范及前端开发接入规范。

技术栈说明

  • JDK 21
  • Spring Boot 3.2.2
  • lombok
  • MyBatis 3.5.15
  • MyBatis-plus 3.5.5
  • logback
  • feign-client(服务间调用)
  • nacos (配置和服务注册、发现)
  • api 文档:Knife4j(4.5.0) + springdoc-openapi
  • 数据库:TelePG、TeleDB
  • 分布式定时任务:xxl-job
  • 消息组件:CtgKafka
  • 缓存组件:CtgCache
  • ElementUI:2.4.4
  • Vue3: 3.4.19

Java 开发规范

基础开发规范

见附录《6.2 Java 开发手册(黄山版)

nacos 配置规范

开发时,不依赖 nacos 配置,所有配置存储在本地配置文件中,方便全量配置版本管控

线上 nacos 配置,只应包含必须配置的环境信息(如数据库配置)及可能需要调整的系统参数,减少后续配置成本

配置分两级结构:

  1. 全局引用: ano-global.yml,使用默认组:DEFAULT_GROUP
  2. 各中心的应用配置:与应用同名,如 ano-demo.yml,并使用中心的 group 名称,如:DEMO_GROUP

代码实现

目录说明

  • client: 服务间调用目录,填写 feign client

  • config:spring 全局 java config

  • core: 基础公共模块:全局配置、过滤器等

    • exception: 基础异常类及统一异常处理
  • modules:

    • foo: 业务模块 1

    • bar: 业务模块 2

  • domain/entity: 与数据库一一对应的实体类

  • 数据库脚本目录:doc/db/版本号(1.0,1.1 等),脚本按 ddl、dml 区分

工具类

  • 通用工具:hutools

  • JSON 工具类:com.ffcs.ctc.ano.core.util.jsonMapper

  • 时间 api:使用 java8 新的时间相关对象,如 LocalDate, LocalDateTime

  • 使用 Lombok 简化代码

输入参数验证

使用 spring validation,参考 MiscTestController 示例

启动 banner 说明

当前用户信息

异常处理

示例脚手架项目,已添加全局异常统一处理。无需在 controller 层,try catch 异常,再包装输出。

业务错误,使用 BusiException 抛异常;应用内部错误,使用 AppException 抛异常;底层错误信息写在日志里,不抛到前台展示。

service 定义

除了特殊的功能要求(比如需模拟外部接口功能),否则不创建业务层 接口类,直接写具体实现:

1
2
@Service
public class XXService{}

orm

使用 mybatis plus 做数据层的持久化操作,简单的逻辑可使用 plus 的 lambda api 做查询;复杂的 sql 使用 xml mapper 文件配置,一切以代码好理解、好维护为基准

表映射

表名、字段名终使用驼峰方式自动映射,如:

DEMO_USER -> DemoUser (表名与 entity 映射)

APP_ID -> appId

CREATED_TIME -> createdTime

分布式定时任务(xxl-job)

  • 定时任务统一使用xxl-job配置调度。
  • 轻量级任务,建议直接使用“通用HTTP任务Handler”,仅需在 xxl-job 执行器配置接口 url;如需分片模式等高级特性,使用 Bean 模式。

动态多模块开发说明

有些业务可能需多个外部功能模块,此时采用多模块独立开发方式,可以更好的分工以及按需集成。

独立动态模块使用基础脚手架,引用相同的parent pom,避免依赖版本冲突。开发时,可按模块独立编码,自测运行。集成时,模块打成独立依赖包,在主服务中引用该模块,并通过配置灵活启用。实现上,基于 SpringBoot 自身功能,无额外封装,简单易懂通用。

独立模块实现上参考以下项目:ano-funx-module,开发完成后,在主项目中引入依赖即可(集成参考:ano-demo 项目):

功能模块(ano-funx-module)

image-20240928212225427

image-20240928212231653

主模块引用及结果验证(ano-demo)

image-20240928212355524

image-20240928220556642

image-20240928220617378

代码格式规范

  • Java 代码缩进 4 个空格,不使用制表符
  • 其他文件类型(除 pom.xml 外),缩进 2 个空格
  • 以上规范已在示例项目 .editorconfig 文件中定义

代码分支及 commit 规范

  • 开发时,以 develop 分支以基础,拉修复分支(hotfix-xx-yy)或特性分支(feat-xx-yy)
  • 开发自测完成后,合并至 develop 分支
  • 提交代码 时,消息以:feat: 或fix:为前缀,分别表示是修复,还是特性提交

版本规范

版本格式:主版本号.次版本号.修订号,版本号递增规则如下:

  1. 主版本号:做了不兼容的 API 修改,
  2. 次版本号:向下兼容的功能性新增,
  3. 修订号:向下兼容的问题修正。

提交新版本时,需要 CHANGELOG.md 文件添加版本变更记录,如:

1
2
3
4
5
6
7
8
# Changelog
## [0.0.1]- 2024-01-30
### 新增
- 初始 demo
### 优化
- xx
### 修复
- yy

api 规范

  • 风格:使用 restful 风格定义 api

  • api 前缀:/api/v1/{应用名}/{模块名}

接口数据格式

  • 接口数据示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
    "code":200,
    "msg":null,
    "data":{
    "id":null,
    "name": "test-3333",
    "age": 3333,
    "remark": "测试"
    }
    }
  • code 编码为标准 http 状态码

    状态码 说明
    200 正常的请求
    400 错误的请求
    401 未登录
    403 无权限操作
    404 记录不存在
    500 系统内部异常

应用创建规范

应用按中心分类。为防止小应用无序泛滥,创建新应用,需先经过集体评审,结合已有的各中心应用,再确定是新创建?还是在旧模块中添加所需功能。

各中心已有应用,统一汇总至公共在线文档,内容需包含:中心名称、中心应用名、应用 nacos 注册服务名(后端)、应用功能说明、应用api 前缀。

应用端口

k8s 环境,各应用内部端口是隔离的。为避免非必要配置说明,所有服务的容器、服务端口使用默认端口:

  • java 应用:8080
  • 前端应用(nginx):80

另外,非对外服务(如前端),不开放外部端口。

前端开发规范

ng 配置文件规范

  1. nginx.conf 配置全局公共配置,同时引用 child 目录下的子模块配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    worker_processes  1;

    events {
    worker_connections 1024;
    }


    http {
    include mime.types;
    default_type application/octet-stream;
    server_tokens off;

    map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
    }

    log_format main '$http_x_forwarded_for - $remote_addr $remote_user [$time_local] "$host" "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" $request_time $upstream_response_time';

    access_log /var/log/nginx/access.log main;

    sendfile on;

    keepalive_timeout 65;

    # 开启gzip
    gzip on;

    # 启用gzip压缩的最小文件;小于设置值的文件将不会被压缩
    gzip_min_length 1k;

    # gzip 压缩级别 1-10
    gzip_comp_level 2;

    # 进行压缩的文件类型。
    gzip_types text/css application/xhtml+xml application/xml application/json text/plain application/javascript font/woff2;

    # 是否在http header中添加Vary: Accept-Encoding,建议开启
    gzip_vary on;


    server {
    listen 80;
    server_name localhost;

    underscores_in_headers on;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";

    proxy_set_header Host $http_host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    client_max_body_size 2G;
    proxy_max_temp_file_size 3072m;

    root /usr/share/nginx/html;
    resolver kube-dns.kube-system.svc.cluster.local valid=5s ipv6=off;

    include child/*.conf;

    # css、js、图片、字体缓存
    location ~ (/assets/.*\.(css|js|png|jpe?g|gif|woff2?|eot|ttf|svg)) {
    add_header Cache-Control "max-age=315360000";
    add_header Expires "Tue, 31 Dec 2999 16:00:00 GMT";
    }

    # html 禁用缓存
    location ~* \.(html|htm)$ {
    add_header Cache-Control no-store,no-cache,must-revalidate;
    add_header pragma no-cache;
    add_header Expires 0;
    #add_header X-Frame-Options SAMEORIGIN;
    }
    }
    }
  2. 子模块规则放在 child 目录下,如:child/iam.conf

  3. 子模块内的转发目标域名,必须使用变量方式配置,防止因子模块 web 服务未启动,导致前端总入口服务无法启动。配置样例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    set $ciam_admin_web ciam-admin-web.yl-yundao.svc.cluster.local:31032;

    location ~ (/ciam/app/iam/resources/.+\.(css|js|png|jpe?g|gif|woff2?|eot|ttf|svg|ico|json)) {
    add_header Cache-Control "max-age=315360000";
    add_header Expires "Tue, 31 Dec 2999 16:00:00 GMT";
    auth_request off;
    access_log off;
    proxy_pass http://$ciam_admin_web;
    }
  4. 各中心的服务需有各自独立的唯一前缀,用于识别转发至目标服务,如:iam 统一前缀 /ciam

IAM前端应用接入

前端子应用接入IAM,将由接入的前端子应用独立编译打包,在IAM统一前端中配置nginx要代理的地址,再将地址配置到IAM菜单中,进行相应权限配置后,就可以IAM统一菜单框架中使用应用,具体步骤如下。

前端子应用开发

前端子应用开发由对应的应用自行开发,在编译、打包部署到容器中

  1. 路径规则:

    需要编译后的目录,有固定的前缀,包括静态资源、API地址,以便于接入配置,如:

    静态资源目录:ciam/app/iam,api地址:ciam/api/v1/iam

  2. iam信息获取:

    参考IAM的API章节,可获取IAM相应的用户、组织、权限等相应信息

IAM接入配置

nginx配置示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
set $ciam_admin_web ciam-admin-web.iam.svc.cluster.local:31032;
set $ciam_gateway ciam-gateway.iam.svc.cluster.local:31034;
set $ciam_auth_center ciam-auth-center.iam.svc.cluster.local:31022;

location ~ (/ciam/app/iam/resources/.*\.(css|js|png|jpe?g|gif|woff2?|eot|ttf|svg|ico)) {
add_header Cache-Control "max-age=315360000";
add_header Expires "Tue, 31 Dec 2999 16:00:00 GMT";
auth_request off;
access_log off;
proxy_pass http://$ciam_admin_web; # 此为静态资源服务地址
}

location ~ (/ciam/app/iam/.*\.html) {
proxy_pass http://$ciam_admin_web; # 此为静态资源服务地址
}

location ^~ /ciam/api/v1/iam {
proxy_pass http://$ciam_gateway; # 此为统一网关地址
rewrite ^/aiops/api/v1/iam/(.*) /api/v1/iam/$1 break;
}

菜单配置

进入IAM管理端,配置子应用的菜单地址(配置相对路径的地址),进行授权后,即可在统一菜单框架中展示

后端开发简要流程

脚手架、示例项目等见附录《6.3 脚手架、公用类、公共依赖版本定义》。

a. 根据 “3.10. 应用创建规范” 确定应用名、api 前缀等

b. 基于示例项目 ano-demo,调整项目名、子模块名,增删项目开发所需依赖

c. 修改 application-dev.yml 中数据库配置信息

d. 编写业务代码

e. 运行服务:mvn spring-boot:run

f. 访问 swagger(默认:http://127.0.0.1:8080/swagger-ui/index.html) 验证 api

附录

MyBaits、hutools、Lombok等使用文档链接

Java开发手册(黄山版)

基于VUE前端编码规范

UIUE规范

脚手架、公用类、公共依赖版本定义