前言
在之前介绍了可靠性投递方案和项目搭建:https://juejin.im/post/5c3f43dae51d45731470a18c
唯一ID:https://juejin.im/post/5c3eb6e7518825253b5ea545
先给出完整代码:
https://github.com/hmilyos/common.git
https://github.com/hmilyos/snowFlakeDemo.git
https://github.com/hmilyos/rabbitmq-common.git available 分支
这一章节我们主要还是做一些前期准备:数据库、生成 Java实体、mapper、mapping、常量、全局异常处理
1.利用 mybatis.generator 生成基础的实体和 Mapper、Mapping
本次用到的 SQL 脚本在 rabbitmq-common 项目的 doc 文件夹 下 rabbitmq_common.sql,先来看看 generatorConfig.xml 的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!--导入属性配置-->
<properties resource="application.properties"></properties>
<!--指定特定数据库的jdbc驱动jar包的位置-->
<classPathEntry location="${db.driverLocation}"/>
<context id="default" targetRuntime="MyBatis3">
<!-- optional,旨在创建class时,对注释进行控制 -->
<commentGenerator>
<property name="suppressDate" value="true"/>
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<!--jdbc的数据库连接 -->
<jdbcConnection
driverClass="${spring.datasource.driver-class-name}"
connectionURL="${spring.datasource.url}"
userId="${spring.datasource.username}"
password="${spring.datasource.password}">
</jdbcConnection>
<!-- 非必需,类型处理器,在数据库类型和java类型之间的转换控制-->
<javaTypeResolver>
<property name="forceBigDecimals" value="false"/>
</javaTypeResolver>
<!-- Model模型生成器,用来生成含有主键key的类,记录类 以及查询Example类
targetPackage 指定生成的model生成所在的包名
targetProject 指定在该项目下所在的路径
-->
<javaModelGenerator targetPackage="com.hmily.rabbitmq.rabbitmqcommon.entity" targetProject="./src/main/java">
<!-- 是否允许子包,即targetPackage.schemaName.tableName -->
<property name="enableSubPackages" value="false"/>
<!-- 是否对model添加 构造函数 -->
<property name="constructorBased" value="true"/>
<!-- 是否对类CHAR类型的列的数据进行trim操作 -->
<property name="trimStrings" value="true"/>
<!-- 建立的Model对象是否 不可改变 即生成的Model对象不会有 setter方法,只有构造方法 -->
<property name="immutable" value="false"/>
</javaModelGenerator>
<!--mapper映射文件生成所在的目录 为每一个数据库的表生成对应的SqlMap文件 -->
<sqlMapGenerator targetPackage="mapping" targetProject="./src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<!-- 客户端代码,生成易于使用的针对Model对象和XML配置文件 的代码
type="ANNOTATEDMAPPER",生成Java Model 和基于注解的Mapper对象
type="MIXEDMAPPER",生成基于注解的Java Model 和相应的Mapper对象
type="XMLMAPPER",生成SQLMap XML文件和独立的Mapper接口
-->
<!-- targetPackage:mapper接口dao生成的位置 -->
<javaClientGenerator type="XMLMAPPER" targetPackage="com.hmily.rabbitmq.rabbitmqcommon.mapper" targetProject="./src/main/java">
<!-- enableSubPackages:是否让schema作为包的后缀 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<table tableName="t_mq_message_failed" domainObjectName="MessageFailed" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<columnOverride column="fail_desc" jdbcType="VARCHAR" />
</table>
<table tableName="t_mq_message_log" domainObjectName="Message" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false">
<columnOverride column="message" jdbcType="VARCHAR" />
</table>
</context>
</generatorConfiguration>
修改完上面的 generatorConfig.xml 就可以点击下图的插件,生成 Java 实体和映射文件
确认一下是否都生成成功,然后每个实体都实现 Serializable 序列化接口
对应的 mapping xml 文件里面 create_time、update_time 根据方法名相对应的改成用 now() ,采用数据库时间。
2. 定义常量 Constants
public final class Constants {
public static final int TRY_TIMEOUT = 3; /*超时未确认收到的时间间隔,单位 min*/
public static final int MAX_TRY_COUNT = 3; // 最大重试次数
}
3. 消息状态枚举类 MSGStatusEnum,可以根据你自己的实际情况定义
public enum MSGStatusEnum{
// 消息投递状态
SENDING(0, "投递中"),
SEND_SUCCESS(1, "投递成功"),
SEND_FAILURE(2, "投递失败"),
PROCESSING_IN(3, "处理中"),
PROCESSING_SUCCESS(4, "处理完成"),
PROCESSING_FAILED(5, "处理失败");
private int code;
private String value;
MSGStatusEnum(int code,String value){
this.code = code;
this.value = value;
}
public String getValue() {
return value;
}
public int getCode() {
return code;
}
}
4. 定义消息对应的业务类型 TypeEnum
public enum TypeEnum {
CREATE_ORDER(1, "create order");
private int code;
private String value;
TypeEnum(int code, String value){
this.code = code;
this.value = value;
}
public String getValue() {
return value;
}
public int getCode() {
return code;
}
}
5. 全局异常处理
@ControllerAdvice
public class RuntimeExceptionHandler {
private static final Logger LOG = LoggerFactory.getLogger(RuntimeExceptionHandler.class);
/**
* 捕捉自定义异常处理
* @param ex
* @return
*/
@ExceptionHandler(CustomException.class)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ServerResponse handleParametersException(CustomException ex) {
LOG.error("error:", ex);
return ServerResponse.createByErrorCodeMessage(ex.getCode(), ex.getMessage());
}
/**
* 全局运行时异常处理
* @param ex
* @return
*/
@ExceptionHandler(RuntimeException.class)
@ResponseBody
@ResponseStatus(HttpStatus.OK)
public ServerResponse handleRuntimeException(RuntimeException ex) {
LOG.error("error:", ex);
return ServerResponse.createByErrorCodeMessage(500, "接口异常,详情请查看服务端日志的异常信息");
}
}
到此,我们的前期准备都做好了,下一节就到可靠性投递的的关键代码了。