一个好用的企业级java应用脚手架设计可以大大提高企业的研发效率,在本文中将结合个人实践经验探讨如何设计这样的一个脚手架。
脚手架主要满足以下要求:
1、应用部署简单,适合于企业级大规模的应用部署,比如基于k8s体系+标准化的CICD体系
2、标准的代码规范,让研发人员快速上手,比如:restful的openai接口规范,mysql规范
3、配置信息能够尽量和代码一起同步,可以支持随时回滚,保证生产环境发布的安全
4、java脚手架尽量提供必备的工具包提升研发效率:比如sql自动生成,通过openapi规范后端代码自动生成
部署方案:
部署流程:
配置文件代码结构:
● 不同环境的配置文件通过git代码分支版本管理,引入helms
包含以下yaml文件(deployment,configmap,service,ingress)
● secret.yaml包含敏感信息,不能放入git,通过pod的环境变量导入
● 通过gitlab的webhook触发流程+argocd实现自动化的CICD
● configmap的key-value集中管理,直接通过Spring Kubernetes PropertySource 实现
● 开发阶段如果启动,使用spring的application-profile.yaml方式启动
工具类规范
● 日志框架
使用默认的 logback.xml 定义格式等
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final static Logger log = LoggerFactory.getLogger(XXX.class);
log.error(XXXX);
● 数据库ORM框架:可以自动生成dao类
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</dependency>
可以参考使用 cn.ctyun.agent.builder.app.CodeGenerator.java 自动生成mybatisplus代码
● json序列化框架
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
或者使用spring 内置的 jackson 做json序列化
POJO定义规范
- VO(View Object):展示对象,它用于表示层展示数据。在Web应用中,VO通常用于Web层向模板渲染引擎层传输的对象,封装了页面所需的数据。
- BO(Business Object):业务对象,它封装了业务逻辑,可以包含一个或多个其他对象,如PO或DO。BO对应具体的业务块,例如,一个用户的BO可能包含其个人信息、交易记录等多个PO。
- PO(Persistent Object):持久化对象,通常与数据库中的表结构一一对应。PO是简单的数据对象,通常只包含属性和访问这些属性的getter和setter方法。它们通过ORM(对象关系映射)框架与数据库表进行映射。
- DO(Domain Object):领域对象,是从现实世界中抽象出来的业务实体。在领域驱动设计(DDD)中,DO通常包含业务逻辑,并且可以与PO一一对应,也可以包含多个PO。DO是业务领域内的核心对象,代表了特定的业务概念。
openapi.yaml文档定义规范
以Product对象的增删改查为例
接口名称 | 提交方式 | 路径 | 参数说明 |
---|---|---|---|
添加产品 | POST | /products | 请求体: Product 对象,包含以下字段: ● id (整数, int64): 产品ID ● name (字符串): 产品名称 ● type (整数, int32): 产品类型 ● createTime (字符串, date-time): 创建时间 ● price (数字, double): 产品价格 ● show (布尔): 是否展示 ● password (字符串, password): 产品密码 |
根据ID获取产品 | GET | /products/{id} | 路径参数: ● id (整数, int64): 产品ID |
更新产品信息 | PUT | /products/{id} | 路径参数: ● id (整数, int64): 产品ID请求体: Product 对象,字段同上 |
删除产品信息 | DELETE | /products/{id} | 路径参数: ● id (整数, int64): 产品ID |
获取产品列表 | GET | /products | 无 |
批量删除 | DELETE | /products | 请求体: id数组 对象 |
推荐使用标准的restful风格的openapi3规范书写
openapi: "3.0.3"
info:
title: inventory-api
version: 1.0.0
servers:
- url: 127.0.0.1:8080
paths:
/products:
get:
tags:
- Product
description: 获取所有产品
operationId: getAllProducts
responses:
'200':
description: 成功返回所有产品
content:
application/json:
schema:
$ref: '#/components/schemas/ProductList'
'404':
description: 未找到任何产品
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
tags:
- Product
description: 添加产品
operationId: addProduct
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
responses:
'201':
description: 产品添加成功
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: 请求错误
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/products/{id}:
get:
tags:
- Product
description: 根据 ID 获取产品
operationId: getProductById
parameters:
- in: path
name: id
schema:
type: integer
format: int64
description: 产品 ID
required: true
responses:
'200':
description: 成功获取产品
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'404':
description: 未找到产品
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
put:
tags:
- Product
description: 更新产品信息
operationId: updateProduct
parameters:
- in: path
name: id
schema:
type: integer
format: int64
description: 产品 ID
required: true
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
responses:
'200':
description: 产品更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/Product'
'400':
description: 请求错误
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'404':
description: 产品不存在
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
tags:
- Product
description: 删除指定 ID 的产品
operationId: deleteProductById
parameters:
- in: path
name: id
schema:
type: integer
format: int64
description: 产品 ID
required: true
responses:
'204':
description: 产品删除成功
'404':
description: 产品不存在
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
ProductList:
type: array
items:
$ref: '#/components/schemas/Product'
Product:
type: object
properties:
id:
type: integer
format: int64
description: 产品 ID
name:
type: string
description: 产品名称
type:
type: integer
format: int32
description: 产品类型
create_time:
type: string
format: date-time
description: 产品创建时间
price:
type: number
format: double
description: 产品价格
show:
type: boolean
description: 产品是否显示
password:
type: string
format: password
description: 产品密码
Error:
type: object
properties:
message:
type: string
Controller层定义规范
以下是运行 mvn clean package 命令:
openapi-processor-maven-plugin插件自动生成的代码:
package io.openapiprocessor.generated.api;
import io.openapiprocessor.generated.model.ProductVO;
import io.openapiprocessor.generated.support.Generated;
import java.util.List;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
@Generated(value = "openapi-processor-spring", version = "2024.1", date = "2024-08-15T21:03:15.601329+08:00")
public interface ProductApi {
@GetMapping(path = "/products", produces = {"application/json"})
ResponseEntity<List<ProductVO>> getAllProducts();
@PostMapping(path = "/products", consumes = {"application/json"}, produces = {"application/json"})
ResponseEntity<ProductVO> addProduct(@RequestBody(required = false) ProductVO body);
@GetMapping(path = "/products/{id}", produces = {"application/json"})
ResponseEntity<ProductVO> getProductById(@PathVariable(name = "id") Long id);
@PutMapping(path = "/products/{id}", consumes = {"application/json"}, produces = {"application/json"})
ResponseEntity<ProductVO> updateProduct(
@PathVariable(name = "id") Long id,
@RequestBody(required = false) ProductVO body);
@DeleteMapping(path = "/products/{id}", produces = {"application/json"})
ResponseEntity<Void> deleteProductById(@PathVariable(name = "id") Long id);
}
在source目录写一个RestController 实现ProductApi即可。