A high-performance and lightweight suites for spring-boot-based web development. Liberg为从零基础小白到中高级Java Web开发者提供一站式的极速开发体验和解决方案。 特别适合快速迭代的中小项目。
源代码仓库地址:
从外部视角来看,Web系统=数据+功能。Liberg
就是围绕“数据”和“接口”来设计和构架整个Web系统。
数据:由data.entity
包下的实体类进行承载,映射到数据库中的表。entity
的一个字段映射为数据库表的一列。通过注解@dbmap(isMap=false)
设定为不映射的类或成员除外。
接口:即service.interfaces
包下的接口声明类,映射为controller.api.XxxControllor
和service.XxxService
。
其中,XxxController
是承接http
请求的入口。每一个接口方法,映射为一个接口uri
。
XxxService
是开发者实现业务逻辑、编写逻辑代码的地方。
基于Liberg
来开发Web
应用,开发者只需要定义好实体类和接口类(对外提供API
),然后编写具体业务逻辑代码即可。其他ORM
等相关胶水代码由LibergCoder
插件进行自动的创建和维护。
_ _ _
| | (_| |
| | _| |__ ___ _ __ __ _
| | | | '_ \ / _ | '__/ _` |
| |____| | |_) | __| | | (_| |
|______|_|_.__/ \___|_| \__, |
__/ |
Liberg (v2.0.0) |___/
使用Liberg
开发Web服务,需要用到Liberg ORM
库(普通Jar
)和LibergCoder
(Idea插件Jar
)两部分。
ORM
核心,除了mysql-connector-java
和logback
外,无其他依赖。可用于任何Java服务端程序开发。Spring Boot
Java代码生成——解析实体类和接口类生成脚手架代码,加速项目开发。Liberg
是一个真正实现“零反射”的Java ORM
框架。
反射赋予了Java动态编程的能力。通过反射可以在运行时通过全限定类名动态地创建对象、获取对象的属性和方法、为对象赋予新的属性值、调用对象中的方法等等。利用Java的反射机制,动态地创建对象、为对象属性赋值,就可以很容易地实现将数据表中的一条记录转换为一个Java
实体类的对象。几乎所有ORM
(Object Relational Mapping)框架就就是这个套路。差别不过是在反射的基础上做了多大程度的优化。
反射的强大特性在代码自动化和框架场景中大有用武之地,但也有一个缺点:那就是——慢。
通过Liberg ORM
精致地封装,配合LibergCoder
代码生成,Liberg
真正做到了实体关系映射上的“零反射”。
总之,Liberg同时注重性能和开发体验,是一个极轻量级的ORM
框架。
LibergCoder
插件读取Java实体类
,自动建表、自动跟踪DDL
升级,生成XxxDao
数据访问类。Liberg ORM
管理数据库连接池,完成数据行到实体类对象的转换。
支持的映射类型如下:
序号 | Java实体字段类型 | 数据表字段类型 |
---|---|---|
1 | byte | TINYINT |
2 | int | INT |
3 | long | BIGINT |
4 | @dbmap(length=x) String,其中x<=4095 | VARCHAR(x) |
5 | @dbmap(length=y) String,其中y>=4096 | TEXT |
提示
浮点数为了保留精度,请使用long/String类型进行存储。
支持自动在单列/两列组合/三列组合(能够唯一定位一条数据)上建立查询缓存(LRU淘汰算法)。如果命中缓存,就可以省掉从数据库读取数据、然后构建实体对象的过程,大大提升查询的速度。
很多需要手动创建的代码、配置文件,LibergCoder
自动完成创建和维护。在LibergCoder
插件的加持下,实现了完全自动化的Spring Boot Web
项目初始化,包括.properties
配置创建、pom.xml
依赖添加、数据库创建、数据表创建、表结构升级等等。
LibergCoder
会创建和维护必要的支撑代码,开发者只写业务:定义实体类、定义API
接口、编写业务方法的具体实现。
让开发者创建最少的文件、写最少的代码。这是Liberg
项目诞生的初衷。
SQL DQL/DML
风格的代码// 示例data.dao.UserDao.java
// 其中columnXxx在UserDao的父类data.dao.impl.UserDaoImpl中定义
// 而UserDaoImpl是完全由代码插件LibergCoder维护的
// 通过openId字段查询单条记录
return getEq(columnOpenId, "xxxxxxx");
// 通过parentId字段查询多条记录,最多返回50条数据
return getEqs(columnParentId, 1000, 50);
// 查询用户名为name,或者密码为xxx并且年龄大于30的一条记录,
// 返回一条找到的User记录,若没有符合条件的记录返回null
return select()
.whereEq(columnName, name)
.or()
.eq(columnPassword, encryptPwd("xxx"))
.gt(columnAge, 30)
.one();
// data.DBUpgrader.java
// 由LibergCoder维护的,数据库/表结构升级类
private void upgradeTo2(Statement stat) throws SQLException {
// 在user表的id列后添加一个bigint类型的_company_id列
alter("user")
.addColumn("_company_id", dbImpl.typeLong(), "id")
.exec(stat);
}
更多示例,请参见附录I SQL风格的代码。
CRUD
系列方法,彻底甩掉xml
save/update/getEq/getEqs/delete同步操作
asyncSave/asyncUpdate异步操作
batchSave/batchUpdate/batchSaveOrUpdate批量操作
编程式事务
transaction(this::doSth());
String result = transaction(()->{doSth(); return "result";});
BaseDao中的所有操作不会用到任何反射代码。
LibergCoder
生成的XxxDaoImpl
继承自BaseDao<T>
,并自动创建了表字段对应的所有列columnXxx
,CRUD
方便快捷。
总之,Liberg + LibergCoder == 零反射的ORM框架 + SpringBoot代码自动化工具
。
在Idea
中创建Spring Initializr
项目,仅仅需要勾选Spring Web
依赖。
下载本地安装Idea插件LibergCoder插件,当前最新版本2.0.0,安装完成,重启Idea,菜单栏末尾多出一个LibergCoder
菜单。
下载本项目源代码,本地Maven install
,将liberg.jar
包安装到本地Maven仓库
中。
打开SpringBoot项目的启动类(带@SpringBootApplication注解),然后点击Idea的LibergCoder菜单,执行Initialize...
完成项目代码的初始化。
Initialize
执行完成之后,整个项目会被IDEA重新载入。
Initialize
操作会执行如下动作:
在项目目录下创建LibergCoder
的配置文件LibergConfig.properties
。
修改pom.xml
,增加mysql-connector-java
和fastjson
依赖,如果缺失的话。
修改resources
下的application.properties
文件,增加一些数据库和application.name, server.port
等默认配置。
创建data.dao、data.entity、data.type、service.interfaces、controller.api、misc
等package。
创建misc.InitializeRunner
类,该类完成数据库的初始化(建库、建表、初始化数据等等)。
创建misc.ResponseBodyProcessor
类,完成fastjson
序列化,并且加入跨域和JSONP
的支持。
创建data.DBConfig
类,用于从application.properties
文件加载数据库的配置。
创建data.DBImpl
类,这个类是数据库建表、数据库版本升级,以及数据初始化的入口,由LibergCoder插件维护。
创建data.DBInitializer
类,开发者在这里增加数据初始化的代码,如果有需要的话。
创建data.DBUpgrader
类,由LibergCoder维护的数据库版本自动升级实现类。一般情况下不需要额外关心。
Initialize
一般仅需要执行一次,如果某些支撑文件缺失,可以执行Initialize
重新创建出来。
创建一个entity类,比如data/entity/User.java
public class User {
// 实体数据缓存到id列的LRU容器中,缓存容量为10万
@cache(cap=TenThousands.X10)
public long id; //实体类要有一个long类型的id作为数据表的自增主键
//isIndex为true表示需要给此列创建索引
// companyId+name可以唯一确定一条记录,这里定义为一个缓存组
@dbmap(isIndex=true) @cache(groupCap=TenThousands.X10, group="g1")
public long companyId;
@dbmap(isIndex=true) @dbmap(isIndex=true) @cache(seq=1, group="g1")
public String name;// 映射到varchar(255)
@dbmap(length=31) // 映射到varchar(31)
public String password;
public byte age; // byte映射为TINYINT字段
public long roleId;// long映射为BIGINT字段
public long createTime;
//isMap为false的成员不映射到数据表的字段
@dbmap(isMap=false)
public Role role;
@dbmap(isMap=false) //可用于额外填充附加信息返回给客户端
public UserDetail userDetail;
}
在IDEA中打开User.java
文件后,执行LibergCoder--Build entity/interface...
,LibergCoder
插件会解析此实体类,生成或修改相关的代码文件。比如:
自动创建data.dao.impl.UserDaoImpl
类,用于支持对user
表的CRUD
操作。
public class UserDaoImpl extends BaseDao<User> {
public static final String TABLE_NAME = "user";
public static final CachedColumn<User, Long> columnId;
public static final CachedColumn<User, Long> columnCompanyId;
public static final CachedColumn<User, String> columnName;
public static final Column<User, String> columnPassword;
public static final Column<User, Byte> columnAge;
public static final Column<User, Long> columnRoleId;
public static final Column<User, Long> columnCreateTime;
public static final CachedColumnPair<User, Long, String> $companyId$name;
// 生成的其他方法
}
自动创建继承UserDaoImpl
的data.dao.UserDao
类,开发者在此文件中实现自己的逻辑。
自动修改data.DBImpl
加入user
表的建表逻辑。
自动修改User.java
文件,给每个字段增加fastjson
提供的@JSONField
注解。
创建一个接口,比如service/interfaces/IUserService.java
public interface IUserService {
//接口中的方法须冠以public修饰符,否则当前版本LibergCoder不能识别
public Response register(String userName, String password) throws OperatorException;
public Response login(String userName, String password) throws OperatorException;
public User getByName(String userName) throws OperatorException;
public boolean nameExists(String userName) throws OperatorException;
}
在IDEA中打开IUserService.java
文件后,执行LibergCoder--Build entity/interface...
,LibergCoder
插件会解析此interface
,生成或修改相关的代码文件。比如:
自动创建controller.api.UserController
类,用于承接HTTP
请求。
@RestController
@RequestMapping("/api/user")
public class UserController {
private final UserService service;
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
// 省去一些模板代码
@PostMapping("/register")
public Response register(@RequestParam("un") String userName,
@RequestParam("p") String password) throws OperatorException {
try {
return service.register(userName, password);
} catch (OperatorException e) {
logger.error("Error: [" + e.code() + "]" + e.desc(), e);
return Response.fail(e);
}
}
@PostMapping("/getByName")
public Response getByName(@RequestParam("un") String userName) throws OperatorException {
try {
return Response.ok(service.getByName(userName));
} catch (OperatorException e) {
logger.error("Error: [" + e.code() + "]" + e.desc(), e);
return Response.fail(e);
}
}
//...
}
创建service.UserService
类,这是IUserService
的实现类,开发者在此编写代码,完成接口需要实现的具体业务逻辑。
在resources/static/api-doc
目录下创建Markdown格式的接口文档。
运行SpringBoot
项目,看看发生了什么。
如果遇到了麻烦,请参考附录liberg-demo
示例项目:附录II 相关项目(gitee)。
把复杂留给框架和工具,让开发顺畅丝滑。重复的事情,无须重复做。
如果您也认可Liberg
这种零反射ORM+插件生成支撑代码的开发方式,欢迎加入贡献代码,一起交流进步。
SQL
风格的查询、更新代码演示。
// XxxDao文件中,单条件查询,支持eq(=),ne(<>),gt(>),ge(>=),lt(<),le(<=),like
// 查询满足条件的单条记录
Xxx record = getEq(columnStatus, 0);
// 查询满足条件的记录,最多返回50条
List<Xxx> records = getEqs(columnStatus, 0, 50);
// 只查询用户名这一列,按id列降序,返回一个List<String>
return select(columnName)
.whereGt(columnId, 0)
.eq(columnNickName, nickName)
.desc(columnId)
.all(50);
Segment
)//只查询id和name两列,返回Segment<User>
Segment<User> userSegment = select(columnId, columnName)
.whereEq(columnAge, 18)
.one();
long id = userSegment.get(columnId);
String name = userSegment.get(columnName);
// 分页查询
return select()
.whereEq(columnIndustryId, industryId)
.eq(columnSceneId, sceneId)
.page(pageNum, pageSize);
// prepare方式的预编译查询:这里演示只查询用户名
final PreparedSelectWhere<String> psw = prepareSelect(columnName)
.whereGe$(columnId)
.eq$(columnAge);
try (final PreparedSelectExecutor<String> prepare = psw.prepare()) {
// 填充条件参数
prepare.setParameter(columnId, 1);
prepare.setParameter(columnAge, 10);
// 第一次查询
prepare.one();
// 填充条件参数
prepare.setParameter(columnId, 2);
prepare.setParameter(columnAge, 30);
// 再次查询
prepare.one();
}
// 演示更新操作:更新用户名、密码、增大年龄,通过id相等条件
update().set(columnName, newName)
.set(columnPassword, newPassword)
.increment(columnAge, ageIncrement)
.whereEq(columnId, id)
.execute();
UserDao userDao = UserDao.self();
RoleDao roleDao = RoleDao.self();
JoinQuery jq = JoinQuery.basedOn(userDao)
.innerJoin(roleDao).eq(userDao.columnRoleId, roleDao.columnId)
.where(userDao).eq(userDao.columnName, "张三")
.asc(userDao.columnId).limit(10);
final JoinResult all = jq.all(50);
Liberg项目:https://gitee.com/liberg-cn/Liberg
liberg-demo: Liberg+LibergCoder
的Spring Boot
演示项目
LibergCoder: Idea插件
Liberg项目:https://github.com/liberg-cn/Liberg
liberg-demo: Liberg+LibergCoder
的Spring Boot
演示项目
LibergCoder: Idea插件
dao.imp.XxxDaoImpl.java
文件中,完全由LibergCoder
维护。开发者只需要关心dao.XxxDao.java
文件。Liberg ORM,高效、简洁、专注于Web。
QQ交流群:126193402
加微信拉群:linysuccess
多谢Star/Fork支持🤝🤝🤝
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。