如梦技术 java核心技术,微服务,mica,Spring mvc,Spring boot,Spring Cloud核心,Spring Cloud中国社区,致力于为Spring Boot和Spring Cloud技术人员提供学习的平台! 2022年07月07日T09:57:09.854Z https://www.dreamlu.net/ 如梦技术 Hexo Spring boot 微服务核心组件集 mica v1.0.1 发布! https://www.dreamlu.net/news/2019/04/04/spring-boot-microservice-core-component-set-mica-v1.0.1-release/ 2019年04月04日T01:00:00.000Z 2022年07月07日T09:57:09.854Z mica(云母)

mica 云母,寓意为云服务的核心,使得云服务开发更加方便快捷。mica 的前身是 lutool,lutool在内部孵化了小两年,已经被多个朋友运用到企业。由于 lutool 对微服务不够友好,故重塑了mica。mica 中的部分大部分组件进行了持续性打磨,增强易用性和性能。

mica 核心依赖

mica 基于 java 8,没有历史包袱,支持传统 Servlet 和 Reactive(webflux)。采用 mica-auto 自动生成 spring.factories 和 spring-devtools.properties 配置,仅依赖 Spring boot、Spring cloud 全家桶,无第三方依赖。市面上鲜有的微服务核心组件。

更新说明

[1.0.1] - 2019年04月03日

  • 👌 处理几处 P3C 代码检查问题。@冷冷
  • ⚡️ 优化泛型,避免部分环境下的编译问题。
  • ✨ 添加 lutool 中的 WebUtil.renderJson()。
  • ⚡️ 优化 DateUtil 性能。
  • ⚡️ 优化 RuntimeUtil,提高性能。
  • ⚡️ 升级 gradle 到 5.3.1

本次版本主要是进行了一些工具的压力测试:

Bean copy 测试

BenchmarkScoreErrorUnits
hutool1939.09226.747ops/ms
spring3569.03539.607ops/ms
cglib9112.785560.503ops/ms
mica17753.409393.245ops/ms

结论:mica 在非编译期 Bean copy 性能强劲,功能强大。

UUID 压测

BenchmarkScoreErrorUnits
jdk8UUId734.59517.220ops/ms
jdk8ThreadLocalRandomUUId3224.75932.107ops/ms
hutoolFastSimpleUUID3619.74867.195ops/ms
micaUUId(java9 方式)12375.405241.879ops/ms

结论:mica 在使用了 java9 的算法,性能卓越。

Date format 压测

BenchmarkScoreErrorUnits
java8Date2405.92444.912ops/ms
micaDateUtil2541.75348.321ops/ms
hutoolDateUtil2775.53113.526ops/ms

结论:hutool 使用的 common lang3 的 FastDateFormat 占用优势。mica 使用 tomcat8 中的 ConcurrentDateFormat 简单的规避了 SimpleDateFormat 的线程问题。

后期 mica 会进行更多的测试,保证稳定的同时,尽可能的提高性能。

开源推荐

关注我们

如梦技术-公众号.jpg
扫描上面二维码,更多精彩内容每天推荐!

]]>
<h1>mica(云母)</h1> <p>mica 云母,寓意为云服务的核心,使得云服务开发更加方便快捷。mica 的前身是 lutool,lutool在内部孵化了小两年,已经被多个朋友运用到企业。由于 lutool 对微服务不够友好,故重塑了mica。mica 中的部分大部分组
mica 微服务核心组件集 1.0.0 正式版发布! https://www.dreamlu.net/news/2019/03/21/mica-microservice-core-component-1.0.0-released/ 2019年03月21日T01:00:00.000Z 2022年07月07日T09:57:09.854Z mica(云母)

mica 云母,寓意为云服务的核心,使得云服务开发更加方便快捷。mica 的前身是 lutool,lutool在内部孵化了小两年,已经被多个朋友运用到企业。由于 lutool 对微服务不够友好,故重塑了mica。mica 中的部分大部分组件进行了持续性打磨,增强易用性和性能。

mica 核心依赖

mica 基于 java 8,没有历史包袱,支持传统 ServletReactive(webflux)。采用 mica-auto 自动生成 spring.factoriesspring-devtools.properties 配置,仅依赖 Spring boot、Spring cloud 全家桶,无第三方依赖。市面上鲜有的微服务核心组件。

更新说明

[1.0.0] - 2019年03月20日

  • 修复 webflux 下不支持的配置。
  • 异常 event requestUrl 拼接 queryString,添加 requestMethod 参数。
  • 调整环境处理和请求日志,方便动态调整。
  • 调整 base64 验证码为直接返回 Captcha 对象,方便二次处理。
  • swagger 服务名不使用大写,webflux swagger 仅仅自动配置 Docket
  • 添加 lutool 中的资源读取工具。
  • 优化文件下载。

模块划分

mica-core

  • 常用工具包,基于 Spring-core 扩展增强,无其他依赖。
  • 增强 cglib Bean copy,高性能(接近直接get set),支持链式 bean,支持类型转换 。
  • $ 工具类快捷方法,不用再记忆到底有哪些工具类。
  • 统一消息返回体,封装得更加好用。
  • Jaskson Read Write HttpMessageConverter,分读写的消息转换器。
  • Spring 枚举转换器,规则同 Jackson。

mica-launcher

  • 项目启动器
  • 启动信息打印
  • 系统环境处理
  • spi 扩展其它启动器

mica-boot

  • 异步配置。
  • 异常处理,未知异常发送 Event 事件,方便监听收集。
  • swagger自动化配置,加入jar包即可。
  • jackson配置。
  • 文件上传配置。
  • 文件下载,支持断点续传。
  • 请求日志打印,方便开发。
  • url 版本号和 header版本处理。

mica-boot-test

  • 方便 mica-boot 测试,注入 mica-launcher 中注入的参数。

mica-log4j2

  • mica log4j配置。
  • 基于 disruptor 异步日志,高性能。
  • 非开发环境将 System.out 和 err 写入 log。

mica-captcha

  • 验证码,支持 webfluxserlvet

协议 LGPL v3

允许以引入不改源码的形式免费用于学习、毕设、公司项目、私活等。

特殊情况修改代码,但仍然想闭源需经过作者同意。

参考请注明:参考自 mica:https://gitee.com/596392912/mica

开源推荐

关注我们

如梦技术-公众号.jpg
扫描上面二维码,更多精彩内容每天推荐!

]]>
<h1>mica(云母)</h1> <p>mica 云母,寓意为云服务的核心,使得云服务开发更加方便快捷。mica 的前身是 lutool,lutool在内部孵化了小两年,已经被多个朋友运用到企业。由于 lutool 对微服务不够友好,故重塑了mica。mica 中的部分大部分组
微信开发工具 spring-boot-starter-weixin v1.3.4 发布 https://www.dreamlu.net/news/2019/03/17/spring-boot-starter-weixin-v1-3-4-release/ 2019年03月17日T01:00:00.000Z 2022年07月07日T09:57:09.853Z 简介

spring-boot-starter-weixinjfinal weixinspring boot starter,这个 starter 是为了方便 Spring boot 用户使用。具体demo请查看:spring-boot-weixin-demoJFinal-weixin文档

功能

  1. 支持多公众号
  2. 提供公众号登录和用户相关接口
  3. 支持多公众号数据统计
  4. 支持公众号支付
  5. 公众号客服vs消息接口
  6. 公众号摇周边接口
  7. 公众号卡券相关
  8. 微信门店接口
  9. 微信硬件
  10. 小程序等

Jar包依赖(最新)

<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>spring-boot-starter-weixin</artifactId>
<version>1.3.4</version>
</dependency>

使用

消息

公众号

  1. 继承DreamMsgControllerAdapter,实现需要重写的消息。
  2. 类添加注解@WxMsgController,注解value为你的消息地址,使用/weixin/wx,已经组合[@RequestMapping和@Controller]

小程序

  1. 继承DreamWxaMsgController,实现需要重写的消息。
  2. 添加注解@WxMsgController,注解value为你的消息地址,使用/weixin/wxa,已经组合[@RequestMapping和@Controller]

Api接口

  • 类添加@WxApi,注解value为你的消息地址,使用/weixin/api,已经组合[@RequestMapping和@Controller]

配置

配置项默认值说明
dream.weixin.access-token-cachedreamWeixinCache缓存名,需要开启spring cache
dream.weixin.app-id-keyappId多公众号参数名,如:/weixin/wx?appId=xxx
dream.weixin.dev-modefalse开发模式
dream.weixin.url-patterns/weixin/*weixin 消息处理spring拦截器url前缀
dream.weixin.wx-configs公众号的配置多公众号配置
dream.weixin.wxa-config小程序配置小程序配置

示例配置

demo 项目中的 application.yml 配置文件。

dream:
weixin:
dev-mode: true
wx-configs:
- appId: wx9803d1188fa5fbda
appSecret: db859c968763c582794e7c3d003c3d87
- appId: wxc03edcd008ad1e70
appSecret: 11ed9e2b8e3e3c131e7be320a42b2b5a
token: 123456
wxa-config:
app-id: wx4f53594f9a6b3dcb
app-secret: eec6482ba3804df05bd10895bace0579
  • cache使用spring的cache,需要@EnableCaching开启。
  • access-token-cache 建议配置有效时间7100秒。

更新说明

2019年03月17日 v1.3.4

解决小程序,启用并设置消息推送配置校验不通过的问题。

2019年03月07日 v1.3.3

升级到 gradle 5.2.1
升级 JFinal3.6
升级 JFinal Weixin2.3
使用 mica-auto 生成 spring.factoriesdevtools 配置。
InMsg 消息对象采用 request 存储,去掉 @WxMsgController 中的 Scope 配置,将消息控制器还原为单例。

2018年12月23日 v1.3.2

修复 SpringAccessTokenCache 没有配置的问题,感谢 qq:A梦的小C 反馈。

2018年12月23日 v1.3.1

WeixinAppConfig 改为实现 SmartInitializingSingleton

2018年05月03日 v1.3.0

弃用@EnableDreamWeixin,导入jar包即可享用。
将消息路由改为spring接管。

开源推荐

微信公众号

如梦技术

精彩内容每日推荐!!!

]]>
<h2 id="简介">简介</h2> <p><code>spring-boot-starter-weixin</code> 是 <code>jfinal weixin</code> 的 <code>spring boot starter</code>,这个 <code>star
JFinal事件驱动插件JFinal-event https://www.dreamlu.net/news/2018/10/09/Jfinal-event-driver-plug-in/ 2018年10月09日T01:00:00.000Z 2022年07月07日T09:57:09.853Z 简介

模仿的Spring中的消息事件:详解Spring事件驱动模

源码连接:http://git.oschina.net/596392912/JFinal-event

手册WIKI地址:http://git.oschina.net/596392912/JFinal-event/wikis/home

使用

代码简单无任何第三方依赖,具体使用如下:

// 初始化插件
EventPlugin plugin = new EventPlugin();
// 开启异步,默认同步。或者使用`threadPool(ExecutorService executorService)`自定义线程池。
plugin.async();

// 设置扫描jar包,默认不扫描
plugin.scanJar();
// 设置监听器默认包,默认全扫描
plugin.scanPackage("net.dreamlu");

// 启动插件,用于main方法启动,jfinal中不需要,添加插件即可。
plugin.start();

// 发送第一个消息
EventKit.post(new Test1Event("hello1"));
// 发送带tag的消息
EventKit.post("save", new Test2Event(123123));

Thread.sleep(1000);

// 停止插件,用于main方法测试。
plugin.stop();

注意:异步需要2个条件

// 1. 开启异步plugin.async();
// 2. @Listener(order = 1, enableAsync = true, tag="save")注解中,enableAsync = true开启异步。

发送远程事件

// 服务端:
plugin.setRmiServer(int port);

//客户端:
plugin.setRmiClient(String host, int port);

//发送消息:
EventKit.postRemote(final ApplicationEvent event);
// 或者
EventKit.postRemote(final String tag, final ApplicationEvent event);
// 建议:将服务端和客户端通用的event类文件打成maven模块。

jar包下载:

http://central.maven.org/maven2/net/dreamlu/JFinal-event/

<dependency>
<groupId>net.dreamlu</groupId>
<artifactId>JFinal-event</artifactId>
<version>1.5.1</version>
</dependency>

更新说明:

2018年10月09日 v2.2.2

升级到jfinal 3.5 (不兼容老版本)支持新版本inject,升级到java 8优化部分代码。
DefaultBeanFactory改为jfinal 3.5 aop 创建,删除 DuangBeanFactory。
优化 ObjenesisBeanFactory 支持jfinal 3.5 inject

2018年08月14日 v2.2.1

ApplicationEvent 添加泛型,方便类型转换。

2018年04月15日 v2.2.0

插件添加手动注册监听类 plugin.register(Class<?> clazz), 多个类,多次调用register方法即可。

2018年03月02日 v2.1.0

添加CtrlHolderEvent处理同步、异步中request、session、attr、header参数传递。
使用:
需先在Config中添加me.add(new CtrlHolderInterceptor());拦截器。
然后继承CtrlHolderEvent编写自己的事件类

CtrlHolder holder = event.getCtrlHolder();
holder.getPara("p");
holder.getAttr("x");
holder.getHeader("x");
holder.getSessionAttr("x");

2017年11月29日 v2.0.4

添加ObjenesisBeanFactory处理不含有默认构造器的Bean
依赖objenesisjar包,下载地址:http://mvnrepository.com/artifact/org.objenesis/objenesis/2.6

2017年10月11日 v2.0.3

用户反馈的问题 #IFX3Z
支持多包名,用;分割,如:net.dreamlu.a;net.dreamlu.b
插件初始化时,没有扫描到监听时依然初始化成功。

2017年10月11日 v2.0.2

2.x bug修复版

2017年10月11日 v2.0.1

插件添加Bean工厂,方便IOC容器和自定义扩展。
默认为DefaultBeanFactory,可实现IBeanFactory自定义扩展。
plugin.beanFactory(new DuangBeanFactory());

2017年10月10日 v2.0.0

基于注解和方法的兼听,简化使用,不兼容1.x
支持JFinal 3.1和3.1以上版本

2017年04月28日 v1.5.1

基于rmi的远程Event

2017年03月22日 v1.4.2

更改默认线程池为SingleThreadExecutor,使异步执行有序化。

添加EventThreadFactory,处理异步时的异常避免影响服务请求。

建议:如果event需要发送大量的异步事件,建议使用自定义线程池。

如:eventPlugin.threadPool(Executors.newCachedThreadPool(new EventThreadFactory()));

2017年02月15日 v1.4.1

添加自定义线程池EventPlugin.threadPool(ExecutorService executorService)方法

2016年08月19日 v1.4.0

升级到JFinal2.2,JFinal低版本用户请使用v1.2.0。

EventKit.postEvent(event)更改为EventKit.post(event),postEvent不再建议使用。

添加EventKit.post(tag, event)方法,@Listener(order = 2, tag = "save")添加tag

开源推荐

微信公众号

如梦技术

精彩内容每日推荐!!!

]]>
<h2 id="简介">简介</h2> <p>模仿的Spring中的消息事件:<a href="http://jinnianshilongnian.iteye.com/blog/1902886" target="_blank" rel="noopener">详解Spring事件驱
JFinal 生成 markdown 格式数据字典 https://www.dreamlu.net/news/2018/01/25/JFinal-generates-the-markdown-format-data-dictionary/ 2018年01月25日T01:00:00.000Z 2022年07月07日T09:57:09.852Z 设计初衷

利用JFinal的代码生成可以为我们生成漂亮的数据字典。其格式类似Mysql的命令行,可见波总的用心。

Table: t_ad (广告表)
----------------+---------------------+------+-----+-------------------+---------
Field | Type | Null | Key | Default | Remarks
----------------+---------------------+------+-----+-------------------+---------
id | INT UNSIGNED(10) | NO | PRI | | 主键id
ad_position_id | INT UNSIGNED(10) | NO | | 0 | 广告位id
title | VARCHAR(64) | NO | | | 广告标题
content | VARCHAR(255) | NO | | | 广告内容
media_type | TINYINT UNSIGNED(2) | NO | | 0 | 媒体类型
link | VARCHAR(255) | NO | | | 链接地址
image_url | VARCHAR(255) | NO | | | 图片地址
end_time | DATETIME(19) | NO | | CURRENT_TIMESTAMP | 结束时间
seq | TINYINT(3) | NO | | 0 | 排序
enabled | TINYINT UNSIGNED(2) | NO | | 1 | 是否启用
creator | VARCHAR(32) | NO | | | 格式:创建者[id]
updator | VARCHAR(32) | NO | | | 格式:创建者[id]
create_time | DATETIME(19) | NO | | CURRENT_TIMESTAMP | 创建时间
update_time | DATETIME(19) | NO | | CURRENT_TIMESTAMP | 更新时间
----------------+---------------------+------+-----+-------------------+---------

在实际工作中现在我们更多的是采用markdown格式的文档,研究一番可以发现JFinal生成的数据字典和markdown的Table比较类型。下面来看看我的改造过程。

改造数据字典格式

添加Druid链接参数

DruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, user, password);
// remarks=true设置可以获取column remarks信息
// useInformationSchema=true设置可以获取tables remarks信息
druidPlugin.setConnectionProperties("useInformationSchema=true;remarks=true");
druidPlugin.start();
return druidPlugin.getDataSource();

重写DataDictionaryGenerator

import javax.sql.DataSource;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.generator.ColumnMeta;
import com.jfinal.plugin.activerecord.generator.TableMeta;

public class MyDataDictionaryGenerator extends com.jfinal.plugin.activerecord.generator.DataDictionaryGenerator {

public DataDictionaryGenerator(DataSource dataSource, String dataDictionaryOutputDir) {
super(dataSource, dataDictionaryOutputDir);
}

/**
* 重写掉生成换行
*/
@Override
protected String genSeparateLine(TableMeta tm) {
return "";
}

protected void generateTable(TableMeta tableMeta, StringBuilder ret) {
ret.append("Table: ").append(tableMeta.name);
if (StrKit.notBlank(tableMeta.remarks)) {
ret.append("(").append(clearBlank(tableMeta.remarks)).append(")");
}
ret.append("\n");

String sparateLine = genSeparateLine(tableMeta);
ret.append(sparateLine);
genTableHead(tableMeta, ret);
ret.append(sparateLine);
for (ColumnMeta columnMeta : tableMeta.columnMetas) {
genColumn(tableMeta, columnMeta, ret);
}
ret.append(sparateLine);
ret.append("\n");
}

/**
* 表头
*/
@Override
protected void genTableHead(TableMeta tm, StringBuilder ret) {
ret.append('\n').append('|');
genCell(tm.colNameMaxLen, " ", "Field", " ", "|", ret);
genCell(tm.colTypeMaxLen, " ", "Type", " ", "|", ret);
genCell("Null".length(), " ", "Null", " ","|", ret);
genCell("Key".length(), " ", "Key", " ","|", ret);
genCell(tm.colDefaultValueMaxLen, " ", "Default", " ", "|", ret);
genCell("Remarks".length(), " ", "Remarks", " ", "|", ret);
ret.append('\n').append('|');
genCell(tm.colNameMaxLen, " ", "-", "-", "|", ret);
ret.replace(ret.length() - 2, ret.length() - 1, " ");
genCell(tm.colTypeMaxLen, " ", "-", "-", "|", ret);
ret.replace(ret.length() - 2, ret.length() - 1, " ");
genCell("Null".length(), " ", "-", "-","|", ret);
ret.replace(ret.length() - 2, ret.length() - 1, " ");
genCell("Key".length(), " ", "-", "-","|", ret);
ret.replace(ret.length() - 2, ret.length() - 1, " ");
genCell(tm.colDefaultValueMaxLen, " ", "-", "-", "|", ret);
ret.replace(ret.length() - 2, ret.length() - 1, " ");
genCell("Remarks".length(), " ", "-", "-", "|", ret);
ret.replace(ret.length() - 2, ret.length() - 1, " ");
ret.append('\n');
}

/**
* 列
*/
@Override
protected void genColumn(TableMeta tableMeta, ColumnMeta columnMeta, StringBuilder ret) {
ret.append('|');
genCell(tableMeta.colNameMaxLen, " ", columnMeta.name, " ", "|", ret);
genCell(tableMeta.colTypeMaxLen, " ", columnMeta.type, " ", "|", ret);
genCell("Null".length(), " ", columnMeta.isNullable, " ", "|", ret);
genCell("Key".length(), " ", columnMeta.isPrimaryKey, " ", "|", ret);
genCell(tableMeta.colDefaultValueMaxLen, " ", columnMeta.defaultValue, " ", "|", ret);
genCell("Remarks".length(), " ", clearBlank(columnMeta.remarks), " ", "|", ret);
ret.append("\n");
}

/**
* 清除注释中的空白符
*/
private String clearBlank(String str) {
return str.replaceAll("[ |\t|\n]+", "");
}
}

配置新数据字典生成类

// 创建生成器
Generator generator = new Generator(dataSource, baseModelPackageName, baseModelOutputDir, modelPackageName, modelOutputDir);
DataDictionaryGenerator dg = new MyDataDictionaryGenerator(dataSource, modelOutputDir);
dg.setDataDictionaryFileName("数据字典.md");
generator.setDataDictionaryGenerator(dg);

到此大工搞成,迫不及待的看看效果展示了~

效果展示

Table: t_ad (广告表)

FieldTypeNullKeyDefaultRemarks
idINT UNSIGNED(10)NOPRI主键id
ad_position_idINT UNSIGNED(10)NO0广告位id
titleVARCHAR(64)NO广告标题
contentVARCHAR(255)NO广告内容
media_typeTINYINT UNSIGNED(3)NO0媒体类型
linkVARCHAR(255)NO链接地址
image_urlVARCHAR(255)NO图片地址
end_timeDATETIME(19)NOCURRENT_TIMESTAMP结束时间
seqTINYINT(3)NO0排序
enabledTINYINT UNSIGNED(3)NO1
creatorVARCHAR(32)NO格式:创建者[id]
updatorVARCHAR(32)NO格式:创建者[id]
create_timeDATETIME(19)NOCURRENT_TIMESTAMP创建时间
update_timeDATETIME(19)NOCURRENT_TIMESTAMP更新时间

开源推荐

微信公众号

如梦技术

精彩内容每日推荐!!!

]]>
<h2 id="设计初衷">设计初衷</h2> <p>利用JFinal的代码生成可以为我们生成漂亮的数据字典。其格式类似Mysql的命令行,可见波总的用心。</p> <figure class="highlight html"><table><tr><td class="code
使用Druid LogFilter打印可执行的sql https://www.dreamlu.net/news/2017/09/22/Print-executable-SQL-using-the-Druid-LogFilter/ 2017年09月22日T01:00:00.000Z 2022年07月07日T09:57:09.852Z 简介

通常在java项目开发为了防止sql注入我们通常都采用的预编译的sql,采用"?"号挂参,如下:

SELECT * FROM blog WHERE id = ?

往往在开发测试阶段能获取到完整的可执行的sql能帮我们及时的发现和定位问题。就有了很多朋友使用log4jdbc来记录SQL信息。

Druid中LogFilter的配置项

如下图我们可以看到有一项statementExecutableSqlLogEnable默认为false

druid 打印可执行sql

配置

这里我们以JFinal和Log4j最为演示的例子。

java代码

// 配置Druid数据库连接池插件
DruidPlugin druidPlugin = new DruidPlugin(jdbcUrl, user, password);

// 配置log插件
Log4jFilter logFilter = new Log4jFilter();
logFilter.setStatementLogEnabled(false);
logFilter.setStatementLogErrorEnabled(true);
logFilter.setStatementExecutableSqlLogEnable(true);

druidPlugin.addFilter(logFilter);

log4j.properties中添加

log4j.logger.druid.sql.Statement=DEBUG

druid中支持的日志Filter

Log4jFilter
Slf4jLogFilter
Log4j2Filter
CommonsLogFilter

开源推荐

微信公众号

如梦技术

精彩内容每日推荐!!!

]]>
<h2 id="简介">简介</h2> <p>通常在java项目开发为了防止sql注入我们通常都采用的预编译的sql,采用"?"号挂参,如下:</p> <figure class="highlight sql"><table><tr><td class="code"><pre><

AltStyle によって変換されたページ (->オリジナル) /