跳至主要內容

COLA常用组件

言午日尧耳总大约 5 分钟JavaSpringBootCOLA

COLA常用组件

Maven依赖

  • pom.xml
    <properties>
        <cola.components.version>5.0.0</cola.components.version>
    </properties>

    <!-- 版本管理 -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cola</groupId>
                <artifactId>cola-components-bom</artifactId>
                <version>${cola.components.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <!-- 组件 -->
    <dependencies>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-dto</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-exception</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-catchlog-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-domain-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-extension-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-statemachine</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-test-container</artifactId>
        </dependency>

      <!-- ruleengine -->
    </dependencies>

dto

  • 规范请求参数、规范响应结果,Api对接统一处理
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-dto</artifactId>
        </dependency>

请求

Query/Command

  • Query类中没有任何字段,仅标识读数据请求
@Data
@EqualsAndHashCode(callSuper = true)
public class UserFindQry extends Query {
    @Parameter(title = "姓名(模糊搜索)")
    private String name;
}
  • Command类中没有任何字段,仅标识写数据请求
@Data
@EqualsAndHashCode(callSuper = true)
public class UserAddCmd extends Command {
    @Schema(title = "姓名")
    @NotBlank(message = "name不能为空")
    private String name;

    @Schema(title = "性别")
    @NotEmpty(message = "sex不能为空")
    private Sex sex;

    @Schema(title = "密码")
    @NotBlank(message = "password不能为空")
    private String password;
}

PageQuery

  • PageQuery是分页请求,包含了分页需要的字段
    • int pageIndex: 页码,默认1
    • int pageSize: 页面大小,默认10
    • String orderBy: 排序字段
    • String orderDirection: 排序方向,"ASC"/"DESC"
    • String groupBy: 分组
    • boolean needTotalCount: 是否显示总行数
@Data
@EqualsAndHashCode(callSuper = true)
public class UserPageQry extends PageQuery {
    @Parameter(description = "姓名")
    private String name;

    @Parameter(description = "性别")
    private Sex sex;
}

响应

  • Response是所有响应类的基类,理论上返回值都可以用Response
  • 但是建议写成"SingleResponse<...>"这样的子类,Swagger文档生成的响应值更加明确,有利于团队协作

Response

  • 响应结果,所有响应的基类,即所有响应必定有以下字段
  • 其他系统对接时做统一解析
    • HTTP对接,使用状态码判断结果
    • RPC对接,使用"success"判断结果
{
  "success": true,
  "errCode": "string",
  "errMessage": "string"
}
  • 示例:无需返回值的结果
    public Response delete(Long id) {
        // 直接响应成功
        return Response.buildSuccess();

        // 可直接响应失败,但一般用在异常处理中,配合响应码使用
        // return Response.buildFailure("UNKNOWN_ERROR","错误信息");
    }

SingleResponse

  • 返回一个对象,格式如下
{
  "success": true,
  "errCode": null,
  "errMessage": null,
  "data": null
}
  • 示例:返回用户详情
    public SingleResponse<UserDetailCO> getDetail(Long id) {
        UserDetailCO detailCO = ...;
        // 返回一个对象结果
        return SingleResponse.of(detailCO);
    }

MultiResponse

  • 返回列表,格式如下
{
  "success": true,
  "errCode": null,
  "errMessage": null,
  "empty": true,
  "notEmpty": false,
  "data": []
}
  • 示例:返回所有用户
    public MultiResponse<UserDetailCO> getAll() {
        List<UserDetailCO> allUser = userService.getAll();
        return MultiResponse.of(allUser);
    }

PageResponse

  • 返回分页信息,格式如下
{
  "success": true,
  "errCode": null,
  "errMessage": null,
  "empty": true,
  "notEmpty": false,
  "pageIndex": 1,
  "pageSize": 10,
  "totalPages": 0,
  "totalCount": 0,
  "data": []
}
  • 示例:返回用户分页
    public PageResponse<UserPageCO> getPage(UserPageQry qry) {
        List<UserPageCO> list = ...;
        int totalCount = ...;
        return PageResponse.of(list, totalCount, qry.getPageSize(), qry.getPageIndex());
    }

exception

        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-exception</artifactId>
        </dependency>

业务抛出异常

  • 使用COLA中的Assert抛出BizException异常
import com.alibaba.cola.exception.BizException;
import com.alibaba.cola.exception.SysException;
import com.alibaba.cola.exception.Assert;


// 直接抛出异常
throw new BizException("这里写业务错误信息");
throw new BizException("UNKNOWN_ERROR","这里写业务错误信息");

throw new SysException("这里写系统错误信息");
throw new SysException("SYSTEM_ERROR","这里写系统错误信息");

// Assert不通过时,抛出BizException异常
Assert.isFalse(user == null, "user不能为null");
// 自定义错误码,默认错误码是"BIZ_ERROR"
Assert.isFalse(user == null, "DATA_NOR_FOUND_ERROR", "user不能为null");

全局异常捕捉

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BizException.class)
    public Response handleBizException(BizException e) {
        // 业务异常,无需记录日志
        return Response.buildFailure(e.getErrCode(), e.getMessage());
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(SysException.class)
    public Response handleSysException(SysException e) {
        // 已知系统异常,打印报错信息
        log.warn("已知系统异常:{} {}", e.getErrCode(), e.getMessage());
        return Response.buildFailure(e.getErrCode(), e.getMessage());
    }

    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(Exception.class)
    public Response handleException(Exception e) {
        // 未知系统异常,打印堆栈信息
        log.error("未知系统异常: {}", e.getMessage(), e);
        return Response.buildFailure("UNKNOWN_ERROR", e.getMessage());
    }
}

catchlog-starter

        <!-- cola示例放在app包 -->
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-catchlog-starter</artifactId>
        </dependency>

        <!-- 打印日志依赖fastjson-2.x版本,底层为fastjson2的兼容版本 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.51</version>
        </dependency>
  • 入口类增加扫描配置"com.alibaba.cola"
@SpringBootApplication(scanBasePackages = {"com.xxc.demo", "com.alibaba.cola"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  • start/resource/logback-spring.xml
    • 日志级别为"DEBUG"
<!-- 日志记录组件的日志 -->
<logger name="com.alibaba.cola.catchlog" level="DEBUG" />
  • 需要的类中注解
    • @CatchAndLog注解在类上,因为aop匹配使用@within(),匹配类注解
// 或者放在Controller层
@CatchAndLog	// aop匹配使用@within,匹配类注解
public class UserServiceImpl implements UserService{
    // ...
}
  • 打印日志示例如下
    • 打印请求参数、响应解雇、耗时
# 正常响应日志
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : START PROCESSING: UserServiceImpl.getPage(..)
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : REQUEST: {"pageIndex":1,"pageSize":10}
#...其他日志
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : RESPONSE: {"data":{"current":1,"pages":0,"records":[{"age":18,"id":1,"name":"老王"},{"age":18,"id":2,"name":"老王"},{"age":0,"id":3,"name":"string"}],"size":10,"total":0},"success":true}
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : COST: 520ms


# 报错日志
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : START PROCESSING: UserServiceImpl.getPage(..)
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : REQUEST: {"pageIndex":1,"pageSize":10}
WARN c.alibaba.cola.catchlog.CatchLogAspect   : BIZ EXCEPTION : 故意报错
ERROR c.alibaba.cola.catchlog.CatchLogAspect   : 故意报错
# ...报错堆栈
WARN c.a.c.catchlog.ApplicationContextHelper  : No bean found for com.alibaba.cola.catchlog.ResponseHandlerI
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : RESPONSE: {"errCode":"BIZ_ERROR","errMessage":"故意报错","success":false}
DEBUG c.alibaba.cola.catchlog.CatchLogAspect   : COST: 227ms

domain-starter

  • 使用@Entity注解scope为"prototype"的Bean
  • DomainFactory实例化Bean
        <!-- cola archetypes生成 -->
        <dependency>
            <groupId>com.alibaba.cola</groupId>
            <artifactId>cola-component-domain-starter</artifactId>
        </dependency>
  • 入口类增加扫描配置"com.alibaba.cola"
@SpringBootApplication(scanBasePackages = {"com.xxc.demo", "com.alibaba.cola"})
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
  • 注解为@Entity,scope为"prototype"的Bean
import com.alibaba.cola.domain.Entity;

@Entity
public class Heartbeat{
    // ...
}
  • 使用DomainFactory实例化一个对象
@Component
public class HeartbeatExe{
    @Async
    public void execute(){
        // 获取新对象
        Heartbeat heartbeat = DomainFactory.create(Heartbeat.class);
        //...
    }
}
上次编辑于:
贡献者: 许晓聪