-
Notifications
You must be signed in to change notification settings - Fork 73
基础工具
定义公用的常量、工具类 采用了spring-boot方式启动, 启动类为Application, 也可以支持web方式启动
异常的顶级API是FrameworkException, 该类继承了RuntimeException,建议项目里面的异常都在最外层进行统一处理。
常见的异常有:
- UtilException 工具类异常
- ServiceException 业务服务异常
- AssertException 断言错误
- DaoException 数据库异常
- InitializationException 初始化启动异常
另外每个异常都需要定义错误码, 系统提供的错误码在com.hbasesoft.framework.common.ErrorCodeDef, 框架的错误码在5位之内, 成功的错误码4位以内,错误的在10000~99999之间。 项目的错误码需要大于6位数字。
错误文件的描述在errorMessage.properties中维护, 如果想定义自己的项目的错误描述,可以在application.yml中 extend.errorMessage.files 扩张配置,多个用英文逗号分隔。
extend:
errorMessage:
files: errorMessage_msg.properties
资源文件支持使用properties和yml两种方式进行配置,两种都写只从yml中读取。 application.yml文件中配置的内容可以使用com.hbasesoft.framework.common.utils.PropertyHolder中的方法来获取
PropertyHolderTest.java
@Test
public void getProperty() {
String a = PropertyHolder.getProperty("test.str.str2");
Assert.equals(a, "bcd", ErrorCodeDef.SYSTEM_ERROR_10001);
a = PropertyHolder.getProperty("test.str.none", "abcdefg");
Assert.equals(a, "abcdefg", ErrorCodeDef.SYSTEM_ERROR_10001);
a = PropertyHolder.getProperty("test.int.int2");
Assert.equals(a, "-1", ErrorCodeDef.SYSTEM_ERROR_10001);
a = PropertyHolder.getProperty("test.long.long2");
Assert.equals(a, "3000", ErrorCodeDef.SYSTEM_ERROR_10001);
a = PropertyHolder.getProperty("test.bool.bool2");
Assert.equals(a, "false", ErrorCodeDef.SYSTEM_ERROR_10001);
}
额外扩展的配置文件,可以在application.yml中通过extend.property.files 来扩展,多个用英文逗号分隔,代码中获取同application.yml一样
application.yml
project:
name: demo
test:
str:
str1: abc
str2: bcd
int:
int1: 1
int2: -1
long:
long1: 1000
long2: 3000
bool:
bool1: true
bool2: false
extend:
property:
files: ext01.properties, ext02.yml
errorMessage:
files: ext_errorMessage.properties
项目中经常能遇到启动时就需要加载xxx功能的场景,例如项目启动时需要检查数据库表有没有创建,没有创建则需要创建相应的数据。 Spring默认已经支持了这种加载方式,但有些场景我们可能需要在Spring容器加载之前启动,我们提供了com.hbasesoft.framework.common.StartupListener接口来支撑这种场景
StartupListener.java
public interface StartupListener {
// 定义多个Listener之间的先后顺序
default LoadOrder getOrder() {
return LoadOrder.LAST;
}
// Spring 容器加载之前
default void init() {
}
// Spring 容器加载完成之后
default void complete(ApplicationContext context) {
}
// 项目销毁前
default void destory() {
}
enum LoadOrder {
FIRST, MIDDLE, LAST
}
}
如何使用?
- 编写业务代码继承 StartupListener
- 在项目的src/main/resources/META-INF/services中需要新建一个com.hbasesoft.framework.common.StartupListener文件,里面的内容是具体的实现类的全称,多个实现类需要换行
断言使用com.hbasesoft.framework.common.utils.Assert工具类
AssertTest.java
@Test
public void notNull() {
Object obj = new Object();
Assert.notNull(obj, ErrorCodeDef.SYSTEM_ERROR_10001);
System.out.println("obj 不是null");
}
@Test
public void isNull() {
Object obj = null;
Assert.isNull(obj, ErrorCodeDef.SYSTEM_ERROR_10001);
System.out.println("obj 是null对象");
}
框架提供了两种方式打印日志
- 在项目中实例化com.hbasesoft.framework.common.utils.logger.Logger类,适用于需要将日志打印到固定文件中的场景。
- 另外提供了一个工具类com.hbasesoft.framework.common.utils.logger.LoggerUtil可以方便的直接打印日志
提供了场景日期格式转化的方法,com.hbasesoft.framework.common.utils.date.DateUtil
DateUtilTest.java
@Test
public void string2Date() {
long t1 = NUM_A;
long t2 = NUM_B;
long t3 = NUM_C;
String d8 = "20180912";
Date date = DateUtil.string2Date(d8);
Assert.isTrue(date.getTime() == t1, ErrorCodeDef.SYSTEM_ERROR_10001);
String d11 = "2018年09月12日";
date = DateUtil.string2Date(d11);
Assert.isTrue(date.getTime() == t1, ErrorCodeDef.SYSTEM_ERROR_10001);
String d10 = "2018-09-12";
date = DateUtil.string2Date(d10);
Assert.isTrue(date.getTime() == t1, ErrorCodeDef.SYSTEM_ERROR_10001);
String d102 = "2018/09/12";
date = DateUtil.string2Date(d102);
Assert.isTrue(date.getTime() == t1, ErrorCodeDef.SYSTEM_ERROR_10001);
String d14 = "20180912105355";
date = DateUtil.string2Date(d14);
Assert.isTrue(date.getTime() == t2, ErrorCodeDef.SYSTEM_ERROR_10001);
String d17 = "20180912105355123";
date = DateUtil.string2Date(d17);
Assert.isTrue(date.getTime() == t3, ErrorCodeDef.SYSTEM_ERROR_10001);
String d19 = "2018-09-12 10:53:55";
date = DateUtil.string2Date(d19);
Assert.isTrue(date.getTime() == t2, ErrorCodeDef.SYSTEM_ERROR_10001);
String d192 = "2018/09/12 10:53:55";
date = DateUtil.string2Date(d192);
Assert.isTrue(date.getTime() == t2, ErrorCodeDef.SYSTEM_ERROR_10001);
String d21 = "2018年09月12日 10时53分55秒";
date = DateUtil.string2Date(d21);
Assert.isTrue(date.getTime() == t2, ErrorCodeDef.SYSTEM_ERROR_10001);
String d23 = "2018-09-12 10:53:55.123";
date = DateUtil.string2Date(d23);
Assert.isTrue(date.getTime() == t3, ErrorCodeDef.SYSTEM_ERROR_10001);
String d232 = "2018/09/12 10:53:55.123";
date = DateUtil.string2Date(d232);
Assert.isTrue(date.getTime() == t3, ErrorCodeDef.SYSTEM_ERROR_10001);
String str = "18年9月12号10点53分55秒";
date = DateUtil.string2Date(str, "yy年M月dd号hh点mm分ss秒");
Assert.isTrue(date.getTime() == t2, ErrorCodeDef.SYSTEM_ERROR_10001);
}
@Test
public void date2String() {
Date date = new Date(NUM_C);
String d8 = DateUtil.date2String(date, DateConstants.DATE_FORMAT_8);
Assert.equals(d8, "20180912", ErrorCodeDef.SYSTEM_ERROR_10001);
String d11 = DateUtil.date2String(date, DateConstants.DATE_FORMAT_11);
Assert.equals(d11, "2018年09月12日", ErrorCodeDef.SYSTEM_ERROR_10001);
String d10 = DateUtil.date2String(date, DateConstants.DATE_FORMAT_10);
Assert.equals(d10, "2018-09-12", ErrorCodeDef.SYSTEM_ERROR_10001);
String d102 = DateUtil.date2String(date, DateConstants.DATE_FORMAT_10_2);
Assert.equals(d102, "2018/09/12", ErrorCodeDef.SYSTEM_ERROR_10001);
String d14 = DateUtil.date2String(date, DateConstants.DATETIME_FORMAT_14);
Assert.equals(d14, "20180912105355", ErrorCodeDef.SYSTEM_ERROR_10001);
String d17 = DateUtil.date2String(date, DateConstants.DATETIME_FORMAT_17);
Assert.equals(d17, "20180912105355123", ErrorCodeDef.SYSTEM_ERROR_10001);
String d19 = DateUtil.date2String(date);
Assert.equals(d19, "2018-09-12 10:53:55", ErrorCodeDef.SYSTEM_ERROR_10001);
String d192 = DateUtil.date2String(date, DateConstants.DATETIME_FORMAT_19_2);
Assert.equals(d192, "2018/09/12 10:53:55", ErrorCodeDef.SYSTEM_ERROR_10001);
String d21 = DateUtil.date2String(date, DateConstants.DATETIME_FORMAT_21);
Assert.equals(d21, "2018年09月12日 10时53分55秒", ErrorCodeDef.SYSTEM_ERROR_10001);
String d23 = DateUtil.date2String(date, DateConstants.DATETIME_FORMAT_23);
Assert.equals(d23, "2018-09-12 10:53:55.123", ErrorCodeDef.SYSTEM_ERROR_10001);
String d232 = DateUtil.date2String(date, DateConstants.DATETIME_FORMAT_23_2);
Assert.equals(d232, "2018/09/12 10:53:55.123", ErrorCodeDef.SYSTEM_ERROR_10001);
String str = DateUtil.date2String(date, "yy年M月dd号hh点mm分ss秒");
Assert.equals(str, "18年9月12号10点53分55秒", ErrorCodeDef.SYSTEM_ERROR_10001);
}
提供获取随机数、transId、比较等等常见的方法 com.hbasesoft.framework.common.utils.CommonUtil
CommonUtilTest.java
@Test
public void getTransactionID() {
String str1 = CommonUtil.getTransactionID();
String str2 = CommonUtil.getTransactionID();
Assert.notEquals(str1, str2, ErrorCodeDef.SYSTEM_ERROR_10001);
System.out.println("生成了两个不一样的串码");
}
提供了文件读取、流转化、文件拷贝等方法 com.hbasesoft.framework.common.utils.io.IOUtil
提供了Javascript、Velocity、OGNL表达式的解析方法
VelocityParseFactoryTest.java
@Test
public void parse() {
Bean bean = new Bean("张三", NUM_18);
Map<String, Object> params = new HashMap<>();
params.put("b", bean);
String template = "你好,我的名字叫${b.name}";
String str = VelocityParseFactory.parse("template01", template, params);
Assert.equals(str, "你好,我的名字叫张三", ErrorCodeDef.SYSTEM_ERROR_10001);
}
JavaScriptUtilTest.java
@Test
public void eval() {
String script = "1+1";
Double result = Double.valueOf(CommonUtil.getString(JavaScriptUtil.eval(script, null)));
Assert.isTrue(result - 2 == 0, ErrorCodeDef.SYSTEM_ERROR_10001);
Bean bean = new Bean("张三", NUM_18);
Map<String, Object> params = new HashMap<>();
params.put("b", bean);
script = "b.getAge() + 2";
result = Double.valueOf(CommonUtil.getString(JavaScriptUtil.eval(script, params)));
Assert.isTrue(result - NUM_20 == 0, ErrorCodeDef.SYSTEM_ERROR_10001);
}
提供了Http Get、Post、下载文件等方法的快速访问 com.hbasesoft.framework.common.utils.io.HttpUtil
HttpUtilTest.java
@Test
public void doGet() {
System.out
.println(HttpUtil.doGet("https://jintan.towngasvcc.com/?null&ticket=2ccd00830d4448668b573c803f599c0f"));
System.out.println(HttpUtil.doGet("https://www.towngasvcc.com", "utf-8"));
}
@Test
public void doPost() {
Map<String, String> param = new HashMap<>();
System.out.println(HttpUtil.doPost("http://www.baidu.com", param));
}
@Test
public void doGetDowloadFile() {
HttpUtil.doGetDowloadFile("https://timgsa.baidu.com/timg?image"
+ "&quality=80&size=b9999_10000&sec=1506669107&di=3f964616fbb30dc8e9090f3921ce6dbf"
+ "&imgtype=jpg&er=1&src=http%3A%2F%2Fimgsrc.baidu.com%2Fbaike%2Fpic%"
+ "2Fitem%2Fcb8065380cd79123ea3a4a45af345982b2b7802d.jpg", "a2.jpg");
}
提供md5、base64、密码加密、解密、字节转16进制字符等方法 com.hbasesoft.framework.common.utils.security.DataUtil
DataUtilTest.java
@Test
public void md5For16() {
String str1 = "123456";
String str2 = DataUtil.md5For16(str1);
Assert.equals(str2, "49BA59ABBE56E057", ErrorCodeDef.SYSTEM_ERROR_10001);
}
目前采用了protostuff 协议做的序列化和反序列化 com.hbasesoft.framework.common.utils.bean.SerializationUtil
SerializationUtilTest.java
@Test
public void serial() {
Bean bean = new Bean("hello world", NUM_18);
byte[] bs = SerializationUtil.serial(bean);
String hexStr = DataUtil.byte2HexStr(bs);
Assert.equals(hexStr, "0A0B68656C6C6F20776F726C641012", ErrorCodeDef.SYSTEM_ERROR_10001);
}
@Test
public void unserial() {
byte[] bs = DataUtil.hexStr2Byte("0A0B68656C6C6F20776F726C641012");
Bean bean = SerializationUtil.unserial(Bean.class, bs);
Assert.equals(bean.getName(), "hello world", ErrorCodeDef.SYSTEM_ERROR_10001);
}
提供了java bean转xml、xml转java bean的方法 com.hbasesoft.framework.common.utils.xml.XmlBeanUtil
XmlTest.java
@Test
public void bean2xml() {
Student student = new Student();
student.setAge(NUM_10);
student.setName("小明");
student.setRemark("小明是位好同学,<hello>年年三好学生👩🎓");
System.out.println(XmlBeanUtil.object2Xml(student));
}
@Test
public void xml2bean() {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><student><name>小明</name><age>10</age><remark>"
+ "<![CDATA[小明是位好<abcdedf>同学,年年三好学生👩🎓]]></remark></student>";
Student student = XmlBeanUtil.xml2Object(xml, Student.class);
System.out.println(student.getAge());
System.out.println(student.getName());
System.out.println(student.getRemark());
}
Framework属于企业级底层开发框架,集成了log、cache、db、message、rule、tx,每块都以模块形式组织,可以根据项目需要获取模块。我们的初衷是屏蔽项目中各种第三方库之间的版本冲突,打造一套屏蔽底层中间件的全新API,提高项目代码的适配能力。
- framework-common 定义公用的常量、工具类 采用了spring-boot方式启动, 启动类为Application, 也可以支持web方式启动。
- framework-log 分布式集成日志模块,详细的记录了每个方法执行的参数、返回结果、执行时间,可以很方便的排查问题或告警,通过远程接口上传服务器(支持直连服务端,也支持通过kafka发送)
- framework-cache 定义了缓存的获取。 支持注解方式访问缓存, 支持基于Redis的分布式锁
- framework-db 是简单易用的轻量级DAO(Data Access Object)框架,它集成了Hibernate实体维护和Mybaits SQL分离的两大优势,提供了非入侵式API,可以与Hibernate、SpringJdbc等数据库框架很好的集成
- framework-job 定时任务,支持quartz、xxl-job、ElasticJob简单封装的定时器,支持分布式、分片等功能
- framework-message 消息模块,通过简单的api发布和订阅事件, 目前支持kafka、redis、rocketMq
- framework-rule 规则引擎,基于json的轻量级规则引擎, 支持多种插件及扩展, 例如:基于状态机的工作流引擎
- framework-tx 分布式事务,支持各种远程接口、同步异步消息。
- [framework-dependencies] 项目依赖,解决版本包依赖问题
- [framework-shell] 控制台方式提供命令操作,支持自定义各种命令,做各种小工具使用。
- [framework-langchain4j] 对langchain4j的补充,支持国内的大模型,让大家更高效的开发AIGC应用。
jdk1.8请使用framework3.X版本,framework4.X已升级至jdk21版本
Hibernate我用了2年半, 13年下半年去中兴软创用了一年SQL服务(软创内部框架), 14年在京东驻场用了2个月的MyBatis,综合了一下这些项目,各有各的优缺点。例如针对复杂业务SQL,hibernate明显能力不足,简单的功能MyBaties也要弄死人,所以一直在思考一个问题有没有一个框架能扬长避短,把大家的优点都发挥出来。 当时在某网站上看了一个帖子介绍了minidao,思路很新颖,拜读了源码。 从此框架之路走起。( 为什么不直接使用minidao,一是这个项目不火、更新节奏也不快,使用风险较大, 二是软创内部使用的都是自己的框架,连spring都没有,hibernate更不可能,jdk都处于1.4、1.5版本,不可能直接使用minidao )
- 14年7月份左右在软创内部gitlab上发布了第一个版本easydao,主要是结合软创当时的系统框架在其之上封装了一层。
- 14年10月份在github上发布了easydao 剥离掉软创内部框架依赖,使其可以不依赖软创的框架,可以结合spring和hibernate,或者可以单独使用jdbc来使用。
- 15年6月开始framework-0.1版本的设计,数据库已经用的很爽了,但是一个项目不仅仅是数据库,还有很多其他东西, 当时针对的是web项目规划了很多模块,类似于现在的web结构, 做了job可以在线管理,消息、rpc、缓存等等功能
- 16年1月22日正式发布1.0版本
- 16年7月21日发布2.0版本,web模块和jeecg合并单独组成framework-manager, framework专门解决项目底层问题
- 17年9月24日发布3.0版本,升级了spring boot版本至2.0, 去掉了dubbox这个rpc框架,引入spring-cloud框架。前端也放弃了jeecg,基于ant-design-pro 实现的一套web框架(目前还未从项目中分离出来,暂未开源)
- 20年2月4日发布了3.4版本, 增加了framework-tx模块,正式支持分布式事务。
- 23年人工智能比较火,又增加了framework-langchain4j,专门扩展国内的一些大模型。
- 中兴视通网上营业厅项目V1.0
- 咪咕在线客服V1.0
- 中国实践教育平台V2.0
- 大丰科创园微信项目V1.0
- 苏州市总工会微信V1.0
- 佛山港华网上营业厅项目V1.0
- 苏州港华网上营业厅项目V1.0
- 苏州体育局微信活动运营项目V1.0
- 苏州市防汛排涝物资管理系统V1.0
- 港华集团网上营业厅项目
- E网通项目
- 港华紫荆微信项目
- 港华物联网平台