mirror of
https://github.com/hs-web/hsweb-framework.git
synced 2026-05-23 10:21:46 +08:00
基本功能
This commit is contained in:
@@ -1,11 +0,0 @@
|
||||
# 通用功能模块
|
||||
实现通用CRUD功能,增删改查,直接继承之.
|
||||
# 目录介绍
|
||||
1. [hsweb-commons-controller](hsweb-commons-controller):通用springmvc控制器
|
||||
1. [hsweb-commons-dao](hsweb-commons-dao):通用dao实现
|
||||
1. [hsweb-commons-entity](hsweb-commons-entity):通用实体类
|
||||
1. [hsweb-commons-service](hsweb-commons-service):通用服务类
|
||||
1. [hsweb-commons-utils](hsweb-commons-utils):工具类
|
||||
|
||||
# 使用
|
||||
[如何建一个增删改查功能](create-crud.md)
|
||||
@@ -1,505 +0,0 @@
|
||||
# 使用通用CRUD 创建 dao,service,controller...
|
||||
|
||||
|
||||
hsweb 按照功能分模块, 再将controller,service,dao等分为子模块.
|
||||
以[hsweb-system-menu](../hsweb-system/hsweb-system-menu)为例,创建maven项目模块以及子模块.
|
||||
## 模块结构
|
||||
* hsweb-system-menu
|
||||
- hsweb-system-menu-controller
|
||||
- hsweb-system-menu-dao
|
||||
- hsweb-system-menu-dao-api
|
||||
- hsweb-system-menu-dao-mybatis
|
||||
- hsweb-system-menu-entity
|
||||
- hsweb-system-menu-model
|
||||
- hsweb-system-menu-service
|
||||
- hsweb-system-menu-service-api
|
||||
- hsweb-system-menu-service-simple
|
||||
- hsweb-system-menu-service-cloud
|
||||
- hsweb-system-menu-starter
|
||||
|
||||
[使用idea创建时的常见问题](https://github.com/hs-web/hsweb-framework/issues/31)
|
||||
|
||||
## Entity
|
||||
模块:hsweb-system-menu-entity
|
||||
|
||||
hsweb中的entity都为接口并提供了一个默认实现,例如 MenuEntity=>SimpleMenuEntity.
|
||||
但是并不强制使用此方式创建entity. 可以只有类,不使用接口.
|
||||
约定:
|
||||
1. entity应该实现`Entity`接口
|
||||
2. 有主键的entity应该实现`GenericEntity<PK>`接口
|
||||
3. entity应该使用`EntityFactory`创建而不是new
|
||||
4. 树形结构的entity,可以实现`TreeSortSupportEntity<PK>`
|
||||
|
||||
注: `PK`=主键
|
||||
|
||||
创建一个entity.
|
||||
|
||||
1. 引入maven依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-entity</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
2. 新建接口类:
|
||||
```java
|
||||
package org.hswebframework.web.entity.menu;
|
||||
|
||||
import org.hswebframework.web.commons.entity.GenericEntity;
|
||||
import org.hswebframework.web.commons.entity.RecordCreationEntity;
|
||||
|
||||
public interface MenuEntity extends GenericEntity<String> {
|
||||
|
||||
String getName();
|
||||
|
||||
void setName(String remark);
|
||||
|
||||
String getUrl();
|
||||
|
||||
void setUrl(String url);
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
3. 新建默认实现类
|
||||
|
||||
```java
|
||||
package org.hswebframework.web.entity.menu;
|
||||
|
||||
import org.hswebframework.web.commons.entity.GenericEntity;
|
||||
import org.hswebframework.web.commons.entity.RecordCreationEntity;
|
||||
|
||||
public class SimpleMenuEntity implements MenuEntity {
|
||||
private String name;
|
||||
private String url;
|
||||
|
||||
public String getName(){
|
||||
return this.name;
|
||||
}
|
||||
public void setName(String name){
|
||||
this.name=name;
|
||||
}
|
||||
public String getUrl(){
|
||||
return this.url;
|
||||
}
|
||||
public void setUrl(String url){
|
||||
this.url=url;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
注意: 默认实现类一般和接口在同一个包中,并且名称为Simple开头+接口名称.
|
||||
因为默认的`EntityFactory`按照此约定来创建未指定特殊实现接口实现的实例.详见 [MapperEntityFactory](hsweb-commons-entity/src/main/java/org/hswebframework/web/commons/entity/factory/MapperEntityFactory.java)
|
||||
|
||||
## DAO
|
||||
模块:hsweb-system-menu-dao
|
||||
|
||||
hsweb 目前提供了mybatis的通用dao实现,支持动态条件.
|
||||
常用dao接口:
|
||||
1. [InsertDao](hsweb-commons-dao/hsweb-commons-dao-api/src/main/java/org/hswebframework/web/dao/InsertDao.java) : 支持insert
|
||||
2. [DeleteDao](hsweb-commons-dao/hsweb-commons-dao-api/src/main/java/org/hswebframework/web/dao/DeleteDao.java) : 支持根据主键删除
|
||||
3. [DeleteByEntityDao](hsweb-commons-dao/hsweb-commons-dao-api/src/main/java/org/hswebframework/web/dao/dynamic/DeleteByEntityDao.java) : 支持根据实体删除(动态条件)
|
||||
4. [QueryByEntityDao](hsweb-commons-dao/hsweb-commons-dao-api/src/main/java/org/hswebframework/web/dao/dynamic/QueryByEntityDao.java) : 支持根据实体查询(动态条件)
|
||||
5. [UpdateByEntityDao](hsweb-commons-dao/hsweb-commons-dao-api/src/main/java/org/hswebframework/web/dao/dynamic/UpdateByEntityDao.java) : 支持根据实体更新(动态条件)
|
||||
6. [CrudDao](hsweb-commons-dao/hsweb-commons-dao-api/src/main/java/org/hswebframework/web/dao/CrudDao.java) : 集上述dao于一体
|
||||
|
||||
增删改查功能继承 `CrudDao`即可.
|
||||
|
||||
1. 新建Dao接口
|
||||
进入模块: hsweb-system-menu-dao-api 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-dao-api</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
创建接口:
|
||||
```java
|
||||
package org.hswebframework.web.dao.menu;
|
||||
|
||||
import org.hswebframework.web.dao.CrudDao;
|
||||
import org.hswebframework.web.entity.menu.MenuEntity;
|
||||
|
||||
public interface MenuDao extends CrudDao<MenuEntity, String> {
|
||||
}
|
||||
|
||||
```
|
||||
2. mybatis实现.
|
||||
进入模块: hsweb-system-menu-dao-mybatis引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-dao-mybatis</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
hsweb依然使用xml的方式实现dao,xml建议放到resources目录下如: 'resources/org/hswebframework/web/dao/mybatis/mappers/menu'
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://www.mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
|
||||
<mapper namespace="org.hswebframework.web.dao.menu.MenuDao">
|
||||
<resultMap id="MenuResultMap" type="org.hswebframework.web.entity.menu.SimpleMenuEntity">
|
||||
<id property="id" column="u_id" javaType="string" jdbcType="VARCHAR"/>
|
||||
<result property="name" column="name" javaType="String" jdbcType="VARCHAR"/>
|
||||
<result property="url" column="url" javaType="String" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<!--用于动态生成sql所需的配置-->
|
||||
<sql id="config">
|
||||
<bind name="resultMapId" value="'MenuResultMap'"/>
|
||||
<bind name="tableName" value="'s_menu'"/>
|
||||
</sql>
|
||||
|
||||
<insert id="insert" parameterType="org.hswebframework.web.commons.entity.Entity">
|
||||
<include refid="config"/>
|
||||
<include refid="BasicMapper.buildInsertSql"/>
|
||||
</insert>
|
||||
|
||||
<delete id="deleteByPk" parameterType="String">
|
||||
<include refid="config"/>
|
||||
<include refid="BasicMapper.switcher"/> <!--支持表切换-->
|
||||
delete from ${_fullTableName} where u_id =#{id}
|
||||
</delete>
|
||||
|
||||
<delete id="delete" parameterType="org.hswebframework.web.commons.entity.Entity">
|
||||
<include refid="config"/>
|
||||
<include refid="BasicMapper.buildDeleteSql"/>
|
||||
</delete>
|
||||
|
||||
<update id="update" parameterType="org.hswebframework.web.commons.entity.Entity">
|
||||
<include refid="config"/>
|
||||
<include refid="BasicMapper.buildUpdateSql"/>
|
||||
</update>
|
||||
|
||||
<select id="query" parameterType="org.hswebframework.web.commons.entity.Entity" resultMap="MenuResultMap">
|
||||
<include refid="config"/>
|
||||
<include refid="BasicMapper.buildSelectSql"/>
|
||||
</select>
|
||||
|
||||
<select id="count" parameterType="org.hswebframework.web.commons.entity.Entity" resultType="int">
|
||||
<include refid="config"/>
|
||||
<include refid="BasicMapper.buildTotalSql"/>
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
```
|
||||
|
||||
注意: 目前动态条件参数仅支持: `QueryParamEntity`,`UpdateParamEntity`,`DeleteParamEntity`
|
||||
|
||||
|
||||
## Service
|
||||
模块: hsweb-system-menu-service
|
||||
|
||||
通用service中,很多实现使用接口(java8的default),以实现多继承
|
||||
|
||||
常用通用service接口:
|
||||
1. [InsertService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/InsertService.java):增
|
||||
2. [DeleteService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/DeleteService.java):删
|
||||
3. [UpdateService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/UpdateService.java):改
|
||||
4. [QueryService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/QueryService.java):查
|
||||
5. [QueryByEntityService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/QueryByEntityService.java):动态查
|
||||
6. [CrudService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/CrudService.java): 合以上为一
|
||||
7. [TreeService](hsweb-commons-service/hsweb-commons-service-api/src/main/java/org/hswebframework/web/service/TreeService.java):树结构(`TreeSupportEntity`)常用操作服务
|
||||
|
||||
常用通用service实现:
|
||||
1. [GenericService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/GenericService.java): 通用服务,提供增删改查,dsl方式操作接口.
|
||||
2. [AbstractService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/AbstractService.java):提供验证器等服务类常用操作,实现`CreateEntityService`.
|
||||
3. [AbstractTreeSortService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/AbstractTreeSortService.java):同上,对树形结构操作.实现`TreeService`.
|
||||
4. [GenericEntityService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/GenericEntityService.java): 通用服务,实现对`GenericEntity`的增删改查操作
|
||||
5. [DefaultDSLDeleteService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/DefaultDSLDeleteService.java): dsl方式删除
|
||||
6. [DefaultDSLQueryService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/DefaultDSLQueryService.java): dsl方式查询
|
||||
7. [DefaultDSLUpdateService](hsweb-commons-service/hsweb-commons-service-simple/src/main/java/org/hswebframework/web/service/DefaultDSLUpdateService.java): dsl方式更新
|
||||
|
||||
DSL方式操作使用[easy-orm](https://github.com/hs-web/hsweb-easy-orm)来构建动态查询参数,[使用方法](hsweb-commons-service/hsweb-commons-service-simple/README.md).
|
||||
|
||||
1. 创建service接口
|
||||
进入模块: hsweb-system-menu-service-api
|
||||
|
||||
引入依赖:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-service-api</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
创建接口类:
|
||||
```java
|
||||
package org.hswebframework.web.service.menu;
|
||||
|
||||
|
||||
import org.hswebframework.web.entity.menu.MenuEntity;
|
||||
import org.hswebframework.web.service.CrudService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface MenuService
|
||||
//泛型<实体类型,主键类型>
|
||||
extends CrudService<MenuEntity, String> {
|
||||
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
进入模块:hsweb-system-menu-service-simple
|
||||
|
||||
引入依赖:
|
||||
```xml
|
||||
<!--上面创建的service接口模块-->
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-system-menu-service-api</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
<!--通用service实现模块-->
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-service-simple</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
创建实现类
|
||||
```java
|
||||
package org.hswebframework.web.service.menu.simple;
|
||||
|
||||
import org.hswebframework.web.dao.menu.MenuDao;
|
||||
import org.hswebframework.web.entity.menu.MenuEntity;
|
||||
import org.hswebframework.web.id.IDGenerator;
|
||||
import org.hswebframework.web.service.GenericEntityService;
|
||||
import org.hswebframework.web.service.menu.MenuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service("menuService")
|
||||
public class SimpleMenuService
|
||||
//泛型<实体类型,主键类型>
|
||||
extends GenericEntityService<MenuEntity, String>
|
||||
implements MenuService {
|
||||
|
||||
private MenuDao menuDao;
|
||||
|
||||
//ID生成器,通用服务的ID都使用主动ID生成,不使用orm或者数据库自动生成
|
||||
//可通过自己实现IDGenerator进行自定义生成
|
||||
@Override
|
||||
protected IDGenerator<String> getIDGenerator() {
|
||||
return IDGenerator.MD5;
|
||||
}
|
||||
// 实现CrudDao接口的类
|
||||
@Override
|
||||
public MenuDao getDao() {
|
||||
return menuDao;
|
||||
}
|
||||
|
||||
//注入dao实现
|
||||
@Autowired
|
||||
public void setMenuDao(MenuDao menuDao) {
|
||||
this.menuDao = menuDao;
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## controller
|
||||
模块: hsweb-system-menu-controller
|
||||
|
||||
常用通用controller接口
|
||||
|
||||
1. [CreateController](hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/CreateController.java) : 增
|
||||
2. [DeleteController](hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/DeleteController.java) : 删
|
||||
3. [UpdateController](hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/UpdateController.java) : 改
|
||||
4. [QueryController](hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/QueryController.java) : 查
|
||||
5. [CrudController](hsweb-commons-controller/src/main/java/org/hswebframework/web/controller/CrudController.java) : 增删改查
|
||||
|
||||
泛型: E, PK, Q extends Entity, M => Entity,主键,动态查询实体类,Model.
|
||||
增改时,使用Model接收参数;查询时,使用Q接受参数,使用Model作为响应.
|
||||
注意: Model 并不是必须,如果不使用单独的Model,可使用 `SimpleCrudController`. 通用controller使用restful方式提供接口
|
||||
响应结果统一为`ResponseMessage<T>`. [更多使用方法](hsweb-commons-controller/README.md)
|
||||
|
||||
1. 创建Controller
|
||||
|
||||
进入模块:hsweb-system-menu-controller
|
||||
|
||||
引入依赖:
|
||||
```xml
|
||||
<!--只依赖service接口-->
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-system-menu-service-api</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
<!--通用Controller-->
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-controller</artifactId>
|
||||
<version>${hsweb.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
创建类:
|
||||
```java
|
||||
package org.hswebframework.web.controller.menu;
|
||||
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.hswebframework.web.authorization.Authentication;
|
||||
import org.hswebframework.web.authorization.Role;
|
||||
import org.hswebframework.web.authorization.annotation.Authorize;
|
||||
import org.hswebframework.web.commons.entity.TreeSupportEntity;
|
||||
import org.hswebframework.web.commons.entity.param.QueryParamEntity;
|
||||
import org.hswebframework.web.controller.GenericEntityController;
|
||||
import org.hswebframework.web.controller.message.ResponseMessage;
|
||||
import org.hswebframework.web.entity.menu.MenuEntity;
|
||||
import org.hswebframework.web.logging.AccessLogger;
|
||||
import org.hswebframework.web.service.menu.MenuGroupService;
|
||||
import org.hswebframework.web.service.menu.MenuService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hswebframework.web.controller.message.ResponseMessage.ok;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("${hsweb.web.mappings.menu:menu}") //默认/menu
|
||||
@Authorize(permission = "menu") // menu权限
|
||||
@Api(value = "menu-manager", description = "系统菜单管理") //swagger
|
||||
public class MenuController implements
|
||||
//泛型 <实体,主键,动态查询实体(目前只支持此类型),模型>
|
||||
//等同 SimpleGenericEntityController<MenuEntity, String, QueryParamEntity>
|
||||
GenericEntityController<MenuEntity, String, QueryParamEntity, MenuEntity> {
|
||||
|
||||
private MenuService menuService;
|
||||
|
||||
@Autowired
|
||||
public void setMenuService(MenuService menuService) {
|
||||
this.menuService = menuService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuService getService() {
|
||||
return menuService;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## starter
|
||||
模块: hsweb-system-menu-starter
|
||||
模块整合,自动配置.
|
||||
|
||||
1. 引入依赖
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-system-menu-service-simple</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-system-menu-dao-mybatis</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-system-menu-controller</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-spring-boot-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-tests</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!--其他依赖-->
|
||||
```
|
||||
|
||||
2. 新建文件: `resources/hsweb-starter.js`,此脚本在模块第一次使用或者更新版本的时候被执行
|
||||
内容如下:
|
||||
|
||||
```js
|
||||
//组件信息
|
||||
var info = {
|
||||
groupId: "org.hsweb",
|
||||
artifactId: "hsweb-system-menu",
|
||||
version: "3.0",
|
||||
website: "https://github.com/hs-web/hsweb-framework/tree/master/hsweb-system/hsweb-system-menu",
|
||||
author: "zh.sqy@qq.com",
|
||||
comment: "菜单"
|
||||
};
|
||||
|
||||
//版本更新信息
|
||||
var versions = [
|
||||
// {
|
||||
// version: "3.0.1",
|
||||
// upgrade: function (context) {
|
||||
// //如果已安装3.0.0,准备使用3.0.1,将执行此代码
|
||||
// java.lang.System.out.println("更新到3.0.2了");
|
||||
// }
|
||||
// }
|
||||
];
|
||||
var JDBCType = java.sql.JDBCType;
|
||||
function install(context) {
|
||||
//当首次使用此模块的时候,执行创建数据库
|
||||
var database = context.database;
|
||||
database.createOrAlter("s_menu")
|
||||
.addColumn().name("u_id").varchar(32).notNull().primaryKey().comment("uid").commit()
|
||||
.addColumn().name("name").varchar(64).notNull().comment("名称").commit()
|
||||
.addColumn().name("url").varchar(2048).notNull().comment("url").commit()
|
||||
//更多字段
|
||||
//。。。
|
||||
.comment("系统菜单表").commit()
|
||||
}
|
||||
|
||||
//以下为固定写法,无需改动
|
||||
dependency.setup(info)
|
||||
.onInstall(install)
|
||||
.onUpgrade(function (context) { //更新时执行
|
||||
var upgrader = context.upgrader;
|
||||
upgrader.filter(versions)
|
||||
.upgrade(function (newVer) {
|
||||
newVer.upgrade(context);
|
||||
});
|
||||
})
|
||||
.onUninstall(function (context) {
|
||||
//卸载时执行
|
||||
});
|
||||
```
|
||||
|
||||
3. 自动配置类
|
||||
目前无需创建自动配置类
|
||||
|
||||
4. 单元测试
|
||||
TODO
|
||||
|
||||
在使用的时候,直接依赖starter即可:
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-system-menu-starter</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
```
|
||||
在未来将提供更多的starter,例如dubbo,spring-cloud
|
||||
@@ -44,6 +44,46 @@
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-r2dbc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-datasource-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>io.r2dbc</groupId>
|
||||
<artifactId>r2dbc-h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot.experimental</groupId>
|
||||
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,34 @@
|
||||
package org.hswebframework.web.crud.annotation;
|
||||
|
||||
import org.hswebframework.web.crud.configuration.EasyormRepositoryRegistrar;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.persistence.Table;
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @see org.hswebframework.ezorm.rdb.mapping.ReactiveRepository
|
||||
* @see org.hswebframework.ezorm.rdb.mapping.SyncRepository
|
||||
* @since 4.0.0
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
@Documented
|
||||
@Import({EasyormRepositoryRegistrar.class})
|
||||
public @interface EnableEasyormRepository {
|
||||
|
||||
/**
|
||||
* 实体类包名:
|
||||
* <pre>
|
||||
* com.company.project.entity
|
||||
* </pre>
|
||||
*/
|
||||
String[] value();
|
||||
|
||||
/**
|
||||
* @see org.hswebframework.ezorm.rdb.mapping.jpa.JpaEntityTableMetadataParser
|
||||
*/
|
||||
Class<? extends Annotation>[] annotation() default Table.class;
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.hswebframework.web.crud.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface ImplementFor {
|
||||
|
||||
Class value();
|
||||
|
||||
Class idType() default Void.class;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.hswebframework.web.crud.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @see org.hswebframework.ezorm.rdb.mapping.ReactiveRepository
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface Reactive {
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Slf4j
|
||||
public class AutoDDLProcessor {
|
||||
|
||||
private List<Class> entities = new ArrayList<>();
|
||||
|
||||
@Autowired
|
||||
private DatabaseOperator operator;
|
||||
|
||||
@Autowired
|
||||
private EasyormProperties properties;
|
||||
|
||||
@Autowired
|
||||
private EntityTableMetadataResolver resolver;
|
||||
|
||||
private boolean reactive;
|
||||
|
||||
public void init() {
|
||||
if (properties.isAutoDdl()) {
|
||||
if(reactive){
|
||||
Flux.fromIterable(entities)
|
||||
.doOnNext(type -> log.info("auto ddl for {}", type))
|
||||
.map(resolver::resolve)
|
||||
.flatMap(meta -> operator.ddl().createOrAlter(meta).commit().reactive())
|
||||
.onErrorContinue((err, a) -> log.warn(err.getMessage(), err))
|
||||
.then()
|
||||
.block();
|
||||
}else{
|
||||
for (Class entity : entities) {
|
||||
log.warn("auto ddl for {}", entity);
|
||||
try {
|
||||
operator.ddl()
|
||||
.createOrAlter(resolver.resolve(entity))
|
||||
.commit()
|
||||
.sync();
|
||||
} catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.mapping.parser.EntityTableMetadataParser;
|
||||
import org.hswebframework.ezorm.rdb.metadata.RDBColumnMetadata;
|
||||
import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class CompositeEntityTableMetadataResolver implements EntityTableMetadataResolver {
|
||||
|
||||
private List<EntityTableMetadataParser> resolvers = new ArrayList<>();
|
||||
|
||||
private Map<Class, AtomicReference<RDBTableMetadata>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
public void addParser(EntityTableMetadataParser resolver) {
|
||||
resolvers.add(resolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RDBTableMetadata resolve(Class<?> entityClass) {
|
||||
|
||||
return cache.computeIfAbsent(entityClass, type -> new AtomicReference<>(doResolve(type))).get();
|
||||
}
|
||||
|
||||
private RDBTableMetadata doResolve(Class<?> entityClass) {
|
||||
return resolvers.stream()
|
||||
.map(resolver -> resolver.parseTableMetadata(entityClass))
|
||||
.filter(Optional::isPresent)
|
||||
.map(Optional::get)
|
||||
.reduce((t1, t2) -> {
|
||||
for (RDBColumnMetadata column : t1.getColumns()) {
|
||||
t2.addColumn(column.clone());
|
||||
}
|
||||
return t2;
|
||||
}).orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper;
|
||||
import org.hswebframework.ezorm.rdb.mapping.EntityManager;
|
||||
import org.hswebframework.ezorm.rdb.mapping.wrapper.EntityResultWrapper;
|
||||
|
||||
@AllArgsConstructor
|
||||
public class DefaultEntityResultWrapperFactory implements EntityResultWrapperFactory {
|
||||
|
||||
private EntityManager entityManager;
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public <T> ResultWrapper<T, ?> getWrapper(Class<T> tClass) {
|
||||
return new EntityResultWrapper<>(() -> entityManager.newInstance(tClass),
|
||||
entityManager.getMapping(tClass));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import lombok.SneakyThrows;
|
||||
import org.hswebframework.ezorm.core.meta.Feature;
|
||||
import org.hswebframework.ezorm.rdb.executor.SyncSqlExecutor;
|
||||
import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSqlExecutor;
|
||||
import org.hswebframework.ezorm.rdb.executor.reactive.ReactiveSyncSqlExecutor;
|
||||
import org.hswebframework.ezorm.rdb.mapping.EntityColumnMapping;
|
||||
import org.hswebframework.ezorm.rdb.mapping.EntityManager;
|
||||
import org.hswebframework.ezorm.rdb.mapping.MappingFeatureType;
|
||||
import org.hswebframework.ezorm.rdb.mapping.jpa.JpaEntityTableMetadataParser;
|
||||
import org.hswebframework.ezorm.rdb.mapping.parser.EntityTableMetadataParser;
|
||||
import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata;
|
||||
import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
|
||||
import org.hswebframework.ezorm.rdb.operator.DefaultDatabaseOperator;
|
||||
import org.hswebframework.web.crud.sql.DefaultJdbcExecutor;
|
||||
import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
|
||||
import org.hswebframework.web.crud.entity.factory.EntityFactory;
|
||||
import org.hswebframework.web.crud.sql.DefaultJdbcReactiveExecutor;
|
||||
import org.hswebframework.web.crud.sql.DefaultR2dbcExecutor;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(EasyormProperties.class)
|
||||
@EnableEasyormRepository("org.hswebframework.web.**.entity")
|
||||
public class EasyOrmConfiguration {
|
||||
|
||||
@Autowired
|
||||
private EasyormProperties properties;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnBean(DataSource.class)
|
||||
public static class JdbcSqlExecutorConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SyncSqlExecutor syncSqlExecutor() {
|
||||
return new DefaultJdbcExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveSqlExecutor reactiveSqlExecutor() {
|
||||
return new DefaultJdbcReactiveExecutor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(ConnectionFactory.class)
|
||||
public static class R2dbcSqlExecutorConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveSqlExecutor reactiveSqlExecutor() {
|
||||
return new DefaultR2dbcExecutor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SyncSqlExecutor syncSqlExecutor(ReactiveSqlExecutor reactiveSqlExecutor) {
|
||||
return ReactiveSyncSqlExecutor.of(reactiveSqlExecutor);
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EntityManager entityManager(EntityTableMetadataResolver resolver, EntityFactory entityFactory) {
|
||||
return new EntityManager() {
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public <E> E newInstance(Class<E> type) {
|
||||
return entityFactory.newInstance(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityColumnMapping getMapping(Class entity) {
|
||||
|
||||
return resolver.resolve(entityFactory.getInstanceType(entity))
|
||||
.getFeature(MappingFeatureType.columnPropertyMapping.createFeatureId(entity))
|
||||
.map(EntityColumnMapping.class::cast)
|
||||
.orElse(null);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DefaultEntityResultWrapperFactory defaultEntityResultWrapperFactory(EntityManager entityManager) {
|
||||
return new DefaultEntityResultWrapperFactory(entityManager);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EntityTableMetadataResolver entityTableMappingResolver(List<EntityTableMetadataParser> parsers) {
|
||||
CompositeEntityTableMetadataResolver resolver = new CompositeEntityTableMetadataResolver();
|
||||
parsers.forEach(resolver::addParser);
|
||||
return resolver;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public EntityTableMetadataParser jpaEntityTableMetadataParser(DatabaseOperator operator) {
|
||||
JpaEntityTableMetadataParser parser = new JpaEntityTableMetadataParser();
|
||||
parser.setDatabaseMetadata(operator.getMetadata());
|
||||
|
||||
return parser;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public DatabaseOperator databaseOperator() {
|
||||
RDBDatabaseMetadata metadata = properties.createDatabaseMetadata();
|
||||
|
||||
return DefaultDatabaseOperator.of(metadata);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public BeanPostProcessor autoRegisterFeature(DatabaseOperator operator) {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof Feature) {
|
||||
operator.getMetadata().addFeature(((Feature) bean));
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.SneakyThrows;
|
||||
import org.hswebframework.ezorm.rdb.metadata.RDBDatabaseMetadata;
|
||||
import org.hswebframework.ezorm.rdb.metadata.RDBSchemaMetadata;
|
||||
import org.hswebframework.ezorm.rdb.metadata.dialect.Dialect;
|
||||
import org.hswebframework.ezorm.rdb.supports.h2.H2SchemaMetadata;
|
||||
import org.hswebframework.ezorm.rdb.supports.mssql.SqlServerSchemaMetadata;
|
||||
import org.hswebframework.ezorm.rdb.supports.mysql.MysqlSchemaMetadata;
|
||||
import org.hswebframework.ezorm.rdb.supports.oracle.OracleSchemaMetadata;
|
||||
import org.hswebframework.ezorm.rdb.supports.posgres.PostgresqlSchemaMetadata;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
@ConfigurationProperties(prefix = "easyorm")
|
||||
@Data
|
||||
public class EasyormProperties {
|
||||
|
||||
private String defaultSchema;
|
||||
|
||||
private String[] schemas = {};
|
||||
|
||||
private boolean autoDdl = true;
|
||||
|
||||
private boolean allowAlter = false;
|
||||
|
||||
private DialectEnum dialect = DialectEnum.h2;
|
||||
|
||||
private Class<? extends Dialect> dialectType;
|
||||
|
||||
private Class<? extends RDBSchemaMetadata> schemaType;
|
||||
|
||||
public RDBDatabaseMetadata createDatabaseMetadata() {
|
||||
RDBDatabaseMetadata metadata = new RDBDatabaseMetadata(createDialect());
|
||||
|
||||
Set<String> schemaSet = new HashSet<>(Arrays.asList(schemas));
|
||||
if (defaultSchema != null) {
|
||||
schemaSet.add(defaultSchema);
|
||||
}
|
||||
schemaSet.stream()
|
||||
.map(this::createSchema)
|
||||
.forEach(metadata::addSchema);
|
||||
|
||||
metadata.getSchema(defaultSchema)
|
||||
.ifPresent(metadata::setCurrentSchema);
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public RDBSchemaMetadata createSchema(String name) {
|
||||
if (schemaType == null) {
|
||||
return dialect.createSchema(name);
|
||||
}
|
||||
return schemaType.getConstructor(String.class).newInstance(name);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public Dialect createDialect() {
|
||||
if (dialectType == null) {
|
||||
return dialect.getDialect();
|
||||
}
|
||||
|
||||
return dialectType.newInstance();
|
||||
}
|
||||
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum DialectEnum {
|
||||
mysql(Dialect.MYSQL) {
|
||||
@Override
|
||||
public RDBSchemaMetadata createSchema(String name) {
|
||||
return new MysqlSchemaMetadata(name);
|
||||
}
|
||||
},
|
||||
mssql(Dialect.MSSQL) {
|
||||
@Override
|
||||
public RDBSchemaMetadata createSchema(String name) {
|
||||
return new SqlServerSchemaMetadata(name);
|
||||
}
|
||||
},
|
||||
oracle(Dialect.ORACLE) {
|
||||
@Override
|
||||
public RDBSchemaMetadata createSchema(String name) {
|
||||
return new OracleSchemaMetadata(name);
|
||||
}
|
||||
},
|
||||
postgres(Dialect.POSTGRES) {
|
||||
@Override
|
||||
public RDBSchemaMetadata createSchema(String name) {
|
||||
return new PostgresqlSchemaMetadata(name);
|
||||
}
|
||||
},
|
||||
h2(Dialect.H2) {
|
||||
@Override
|
||||
public RDBSchemaMetadata createSchema(String name) {
|
||||
return new H2SchemaMetadata(name);
|
||||
}
|
||||
},
|
||||
;
|
||||
|
||||
Dialect dialect;
|
||||
|
||||
public abstract RDBSchemaMetadata createSchema(String name);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hswebframework.ezorm.rdb.mapping.defaults.DefaultReactiveRepository;
|
||||
import org.hswebframework.ezorm.rdb.mapping.defaults.DefaultSyncRepository;
|
||||
import org.hswebframework.utils.ClassUtils;
|
||||
import org.hswebframework.web.crud.annotation.EnableEasyormRepository;
|
||||
import org.hswebframework.web.crud.annotation.ImplementFor;
|
||||
import org.hswebframework.web.crud.annotation.Reactive;
|
||||
import org.hswebframework.web.crud.entity.GenericEntity;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.core.io.support.ResourcePatternResolver;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.core.type.classreading.MetadataReader;
|
||||
import org.springframework.core.type.classreading.MetadataReaderFactory;
|
||||
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Slf4j
|
||||
public class EasyormRepositoryRegistrar implements ImportBeanDefinitionRegistrar {
|
||||
|
||||
private ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
|
||||
|
||||
private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
@SuppressWarnings("all")
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
|
||||
Map<String, Object> attr = importingClassMetadata.getAnnotationAttributes(EnableEasyormRepository.class.getName());
|
||||
if (attr == null) {
|
||||
return;
|
||||
}
|
||||
String[] arr = (String[]) attr.get("value");
|
||||
String path = Arrays.stream(arr)
|
||||
.map(str -> ResourcePatternResolver
|
||||
.CLASSPATH_ALL_URL_PREFIX
|
||||
.concat(str.replace(".", "/")).concat("/**/*.class"))
|
||||
.collect(Collectors.joining());
|
||||
|
||||
Class<Annotation>[] anno = (Class[]) attr.get("annotation");
|
||||
|
||||
List<Class> allEntities = new ArrayList<>();
|
||||
|
||||
for (Resource resource : resourcePatternResolver.getResources(path)) {
|
||||
MetadataReader reader = metadataReaderFactory.getMetadataReader(resource);
|
||||
String className = reader.getClassMetadata().getClassName();
|
||||
Class entityType = Class.forName(className);
|
||||
if (Arrays.stream(anno)
|
||||
.noneMatch(ann -> AnnotationUtils.findAnnotation(entityType, ann) != null)) {
|
||||
continue;
|
||||
}
|
||||
allEntities.add(entityType);
|
||||
ImplementFor implementFor = AnnotationUtils.findAnnotation(entityType, ImplementFor.class);
|
||||
Reactive reactive = AnnotationUtils.findAnnotation(entityType, Reactive.class);
|
||||
Class genericType = Optional.ofNullable(implementFor)
|
||||
.map(ImplementFor::value)
|
||||
.orElseGet(() -> {
|
||||
return Stream.of(entityType.getInterfaces())
|
||||
.filter(e -> GenericEntity.class.isAssignableFrom(e))
|
||||
.findFirst()
|
||||
.orElse(entityType);
|
||||
});
|
||||
Class idType = null;
|
||||
if (implementFor == null || implementFor.idType() == Void.class) {
|
||||
try {
|
||||
if (GenericEntity.class.isAssignableFrom(entityType)) {
|
||||
idType = ClassUtils.getGenericType(entityType);
|
||||
}
|
||||
if (idType == null) {
|
||||
Method getId = org.springframework.util.ClassUtils.getMethod(entityType, "getId");
|
||||
idType = getId.getReturnType();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
idType = String.class;
|
||||
}
|
||||
} else {
|
||||
idType = implementFor.idType();
|
||||
}
|
||||
if(reactive!=null){
|
||||
log.debug("register ReactiveRepository<{},{}>", genericType.getName(), idType.getSimpleName());
|
||||
|
||||
ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultReactiveRepository.class, genericType, idType);
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setTargetType(repositoryType);
|
||||
definition.setBeanClass(ReactiveRepositoryFactoryBean.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.getPropertyValues().add("entityType", entityType);
|
||||
registry.registerBeanDefinition(entityType.getSimpleName().concat("ReactiveRepository"), definition);
|
||||
}else {
|
||||
log.debug("register SyncRepository<{},{}>", genericType.getName(), idType.getSimpleName());
|
||||
|
||||
ResolvableType repositoryType = ResolvableType.forClassWithGenerics(DefaultSyncRepository.class, genericType, idType);
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setTargetType(repositoryType);
|
||||
definition.setBeanClass(SyncRepositoryFactoryBean.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.getPropertyValues().add("entityType", entityType);
|
||||
registry.registerBeanDefinition(entityType.getSimpleName().concat("SyncRepository"), definition);
|
||||
}
|
||||
}
|
||||
|
||||
RootBeanDefinition definition = new RootBeanDefinition();
|
||||
definition.setTargetType(AutoDDLProcessor.class);
|
||||
definition.setBeanClass(AutoDDLProcessor.class);
|
||||
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
|
||||
definition.getPropertyValues().add("entities", allEntities);
|
||||
definition.setInitMethodName("init");
|
||||
registry.registerBeanDefinition(AutoDDLProcessor.class.getName(), definition);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper;
|
||||
|
||||
public interface EntityResultWrapperFactory {
|
||||
|
||||
<T> ResultWrapper<T, ?> getWrapper(Class<T> tClass);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.metadata.RDBTableMetadata;
|
||||
|
||||
public interface EntityTableMetadataResolver {
|
||||
|
||||
RDBTableMetadata resolve(Class<?> entityClass);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.hswebframework.ezorm.rdb.mapping.defaults.DefaultReactiveRepository;
|
||||
import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class ReactiveRepositoryFactoryBean<E, PK>
|
||||
implements FactoryBean<ReactiveRepository<E, PK>> {
|
||||
|
||||
@Autowired
|
||||
private DatabaseOperator operator;
|
||||
|
||||
@Autowired
|
||||
private EntityTableMetadataResolver resolver;
|
||||
|
||||
private Class<E> entityType;
|
||||
|
||||
@Autowired
|
||||
private EntityResultWrapperFactory wrapperFactory;
|
||||
|
||||
@Override
|
||||
public ReactiveRepository<E, PK> getObject() {
|
||||
|
||||
return new DefaultReactiveRepository<>(operator,
|
||||
resolver.resolve(entityType),
|
||||
entityType,
|
||||
wrapperFactory.getWrapper(entityType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return ReactiveRepository.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.hswebframework.web.crud.configuration;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.ezorm.rdb.mapping.SyncRepository;
|
||||
import org.hswebframework.ezorm.rdb.mapping.defaults.DefaultSyncRepository;
|
||||
import org.hswebframework.ezorm.rdb.operator.DatabaseOperator;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class SyncRepositoryFactoryBean<E, PK>
|
||||
implements FactoryBean<SyncRepository<E, PK>> {
|
||||
|
||||
|
||||
@Autowired
|
||||
private DatabaseOperator operator;
|
||||
|
||||
@Autowired
|
||||
private EntityTableMetadataResolver resolver;
|
||||
|
||||
private Class<E> entityType;
|
||||
|
||||
@Autowired
|
||||
private EntityResultWrapperFactory wrapperFactory;
|
||||
|
||||
@Override
|
||||
public SyncRepository<E, PK> getObject() {
|
||||
|
||||
return new DefaultSyncRepository<>(operator,
|
||||
resolver.resolve(entityType),
|
||||
entityType,
|
||||
wrapperFactory.getWrapper(entityType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return SyncRepository.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -16,20 +16,34 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao.dynamic;
|
||||
package org.hswebframework.web.crud.entity;
|
||||
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.bean.ToString;
|
||||
import org.springframework.data.annotation.Id;
|
||||
|
||||
import javax.persistence.Column;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 根据实体类动态查询,可传入特定的实体类进行查询。
|
||||
* 目前支持{@link org.hswebframework.web.commons.entity.param.QueryParamEntity} 动态查询
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
* @since 4.0
|
||||
*/
|
||||
public interface QueryByEntityDao<PO> {
|
||||
List<PO> query(Entity queryEntity);
|
||||
@Getter
|
||||
@Setter
|
||||
public class GenericEntity<PK> implements Entity {
|
||||
|
||||
int count(Entity queryEntity);
|
||||
@Column(length = 32)
|
||||
@Id
|
||||
private PK id;
|
||||
|
||||
public String toString(String... ignoreProperty) {
|
||||
return ToString.toString(this, ignoreProperty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToString.toString(this);
|
||||
}
|
||||
}
|
||||
@@ -16,70 +16,47 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
package org.hswebframework.web.crud.entity;
|
||||
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.ezorm.rdb.mapping.annotation.Comment;
|
||||
|
||||
import javax.persistence.Column;
|
||||
|
||||
/**
|
||||
* 支持树形结构,排序的实体类,要使用树形结构,排序功能的实体类直接继承该类
|
||||
*/
|
||||
public abstract class SimpleTreeSortSupportEntity<PK> extends SimpleGenericEntity<PK>
|
||||
@Getter
|
||||
@Setter
|
||||
public abstract class GenericTreeSortSupportEntity<PK> extends GenericEntity<PK>
|
||||
implements TreeSortSupportEntity<PK> {
|
||||
/**
|
||||
* 父级类别
|
||||
*/
|
||||
@Column(name = "parent_id", length = 32)
|
||||
@Comment("父级ID")
|
||||
private PK parentId;
|
||||
|
||||
/**
|
||||
* 树结构编码,用于快速查找, 每一层由4位字符组成,用-分割
|
||||
* 如第一层:0001 第二层:0001-0001 第三层:0001-0001-0001
|
||||
*/
|
||||
@Column(name = "path", length = 128)
|
||||
@Comment("树路径")
|
||||
private String path;
|
||||
|
||||
/**
|
||||
* 排序索引
|
||||
*/
|
||||
@Column(name = "sort_index", precision = 32)
|
||||
@Comment("排序序号")
|
||||
private Long sortIndex;
|
||||
|
||||
@Column(name = "_level", precision = 32)
|
||||
@Comment("树层级")
|
||||
private Integer level;
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPath(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PK getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParentId(PK parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSortIndex() {
|
||||
return sortIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLevel(Integer level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSortIndex(Long sortIndex) {
|
||||
this.sortIndex = sortIndex;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
package org.hswebframework.web.crud.entity;
|
||||
|
||||
public interface SortSupportEntity extends Comparable<SortSupportEntity>, Entity {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
package org.hswebframework.web.crud.entity;
|
||||
|
||||
/**
|
||||
* 支持树形结构,排序的实体类,要使用树形结构,排序功能的实体类直接继承该类
|
||||
@@ -16,12 +16,12 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
package org.hswebframework.web.crud.entity;
|
||||
|
||||
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.hswebframework.utils.RandomUtil;
|
||||
import org.hswebframework.web.id.IDGenerator;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.*;
|
||||
@@ -29,13 +29,11 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
public interface TreeSupportEntity<PK> extends GenericEntity<PK> {
|
||||
public interface TreeSupportEntity<PK> extends Entity {
|
||||
|
||||
String id = "id";
|
||||
PK getId();
|
||||
|
||||
String path = "path";
|
||||
|
||||
String parentId = "parentId";
|
||||
void setId(PK id);
|
||||
|
||||
String getPath();
|
||||
|
||||
@@ -63,7 +63,7 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory {
|
||||
public MapperEntityFactory() {
|
||||
}
|
||||
|
||||
public <T> MapperEntityFactory(Map<Class<T>, Mapper> realTypeMapper) {
|
||||
public MapperEntityFactory(Map<Class<?>, Mapper> realTypeMapper) {
|
||||
this.realTypeMapper.putAll(realTypeMapper);
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class MapperEntityFactory implements EntityFactory, BeanFactory {
|
||||
if (iterator.hasNext()) {
|
||||
realType = (Class<T>) iterator.next().getClass();
|
||||
}
|
||||
//尝试使用 Simple类,如: package.SimpleUserBean
|
||||
|
||||
if (realType == null) {
|
||||
mapper = defaultMapperFactory.apply(beanClass);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package org.hswebframework.web.crud.service;
|
||||
import org.hswebframework.ezorm.rdb.mapping.SyncRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
public class DefaultCrudService<E,K> implements CrudService<E,K> {
|
||||
public class GenericCrudService<E,K> implements CrudService<E,K> {
|
||||
|
||||
@Autowired
|
||||
private SyncRepository<E, K> repository;
|
||||
@@ -3,7 +3,7 @@ package org.hswebframework.web.crud.service;
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
public class DefaultReactiveCrudService<E,K> implements ReactiveCrudService<E,K> {
|
||||
public class GenericReactiveCrudService<E,K> implements ReactiveCrudService<E,K> {
|
||||
|
||||
@Autowired
|
||||
private ReactiveRepository<E, K> repository;
|
||||
@@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public interface ReactiveCrudService<E, K> {
|
||||
@@ -40,13 +41,26 @@ public interface ReactiveCrudService<E, K> {
|
||||
return publisher.flatMap(e -> findById(Mono.just(e)));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
default Mono<SaveResult> save(Publisher<E> entityPublisher) {
|
||||
return getRepository()
|
||||
.save(entityPublisher);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
default Mono<Integer> insertBatch(Publisher<? extends Collection<E>> entityPublisher) {
|
||||
return getRepository()
|
||||
.insertBatch(entityPublisher);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
default Mono<Integer> insert(Publisher<E> entityPublisher) {
|
||||
return getRepository()
|
||||
.insert(entityPublisher);
|
||||
}
|
||||
|
||||
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
default Mono<Integer> deleteById(Publisher<K> idPublisher) {
|
||||
return getRepository()
|
||||
.deleteById(idPublisher);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.hswebframework.web.crud.sql;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.hswebframework.ezorm.rdb.executor.SqlRequest;
|
||||
import org.hswebframework.ezorm.rdb.executor.jdbc.JdbcSyncSqlExecutor;
|
||||
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper;
|
||||
import org.hswebframework.web.datasource.DataSourceHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
|
||||
@Slf4j
|
||||
public class DefaultJdbcExecutor extends JdbcSyncSqlExecutor {
|
||||
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
protected String getDatasourceId() {
|
||||
return DataSourceHolder.switcher().datasource().current().orElse("default");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(SqlRequest sqlRequest) {
|
||||
|
||||
DataSource dataSource = DataSourceHolder.isDynamicDataSourceReady() ?
|
||||
DataSourceHolder.currentDataSource().getNative() :
|
||||
this.dataSource;
|
||||
Connection connection = DataSourceUtils.getConnection(dataSource);
|
||||
boolean isConnectionTransactional = DataSourceUtils.isConnectionTransactional(connection, dataSource);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("DataSource ({}) JDBC Connection [{}] will {}be managed by Spring", getDatasourceId(), connection, (isConnectionTransactional ? "" : "not "));
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection, SqlRequest sqlRequest) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("Releasing DataSource ({}) JDBC Connection [{}]", getDatasourceId(), connection);
|
||||
}
|
||||
try {
|
||||
DataSource dataSource = DataSourceHolder.isDynamicDataSourceReady() ?
|
||||
DataSourceHolder.currentDataSource().getNative() :
|
||||
this.dataSource;
|
||||
DataSourceUtils.doReleaseConnection(connection, dataSource);
|
||||
} catch (SQLException e) {
|
||||
log.error(e.getMessage(), e);
|
||||
try {
|
||||
connection.close();
|
||||
} catch (Exception e2) {
|
||||
log.error(e2.getMessage(), e2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public void execute(SqlRequest request) {
|
||||
super.execute(request);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Throwable.class)
|
||||
@Override
|
||||
public int update(SqlRequest request) {
|
||||
return super.update(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public <T, R> R select(SqlRequest request, ResultWrapper<T, R> wrapper) {
|
||||
return super.select(request, wrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.hswebframework.web.crud.sql;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.executor.SqlRequest;
|
||||
import org.hswebframework.ezorm.rdb.executor.jdbc.JdbcReactiveSqlExecutor;
|
||||
import org.hswebframework.web.datasource.DataSourceHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
|
||||
public class DefaultJdbcReactiveExecutor extends JdbcReactiveSqlExecutor {
|
||||
@Autowired
|
||||
private DataSource dataSource;
|
||||
|
||||
@Override
|
||||
public Mono<Connection> getConnection(SqlRequest sqlRequest) {
|
||||
|
||||
DataSource dataSource = DataSourceHolder.isDynamicDataSourceReady() ?
|
||||
DataSourceHolder.currentDataSource().getNative() :
|
||||
this.dataSource;
|
||||
Connection connection = DataSourceUtils.getConnection(dataSource);
|
||||
return Mono.just(connection);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseConnection(Connection connection, SqlRequest sqlRequest) {
|
||||
DataSource dataSource = DataSourceHolder.isDynamicDataSourceReady() ?
|
||||
DataSourceHolder.currentDataSource().getNative() :
|
||||
this.dataSource;
|
||||
DataSourceUtils.releaseConnection(connection, dataSource);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.hswebframework.web.crud.sql;
|
||||
|
||||
import io.r2dbc.spi.Connection;
|
||||
import io.r2dbc.spi.ConnectionFactory;
|
||||
import org.hswebframework.ezorm.rdb.executor.SqlRequest;
|
||||
import org.hswebframework.ezorm.rdb.executor.reactive.r2dbc.R2dbcReactiveSqlExecutor;
|
||||
import org.hswebframework.ezorm.rdb.executor.wrapper.ResultWrapper;
|
||||
import org.hswebframework.web.datasource.DataSourceHolder;
|
||||
import org.hswebframework.web.datasource.R2dbcDataSource;
|
||||
import org.reactivestreams.Publisher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.r2dbc.connectionfactory.ConnectionFactoryUtils;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.SignalType;
|
||||
|
||||
public class DefaultR2dbcExecutor extends R2dbcReactiveSqlExecutor {
|
||||
|
||||
@Autowired
|
||||
private ConnectionFactory defaultFactory;
|
||||
|
||||
@Override
|
||||
protected Mono<Connection> getConnection() {
|
||||
if (DataSourceHolder.isDynamicDataSourceReady()) {
|
||||
return DataSourceHolder.currentR2dbc()
|
||||
.flatMap(R2dbcDataSource::getNative)
|
||||
.flatMap(ConnectionFactoryUtils::getConnection);
|
||||
} else {
|
||||
return ConnectionFactoryUtils.getConnection(defaultFactory);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseConnection(SignalType type, Connection connection) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.NOT_SUPPORTED)
|
||||
public Mono<Void> execute(Publisher<SqlRequest> request) {
|
||||
return super.execute(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Mono<Integer> update(Publisher<SqlRequest> request) {
|
||||
return super.update(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public <E> Flux<E> select(Publisher<SqlRequest> request, ResultWrapper<E, ?> wrapper) {
|
||||
return super.select(request, wrapper);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# Auto Configure
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.hswebframework.web.crud.configuration.EasyOrmConfiguration
|
||||
@@ -0,0 +1,29 @@
|
||||
package org.hswebframework.web.crud;
|
||||
|
||||
import org.hswebframework.ezorm.rdb.mapping.ReactiveRepository;
|
||||
import org.hswebframework.web.crud.entity.TestEntity;
|
||||
import org.hswebframework.web.crud.service.TestEntityService;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
@SpringBootTest
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class CrudTests {
|
||||
|
||||
@Autowired
|
||||
private TestEntityService service;
|
||||
|
||||
@Test
|
||||
public void test(){
|
||||
Mono.just(TestEntity.of("test",100))
|
||||
.as(service::insert)
|
||||
.as(StepVerifier::create)
|
||||
.expectNext(1)
|
||||
.verifyComplete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.hswebframework.web.crud;
|
||||
|
||||
import org.hswebframework.web.crud.entity.factory.EntityFactory;
|
||||
import org.hswebframework.web.crud.entity.factory.MapperEntityFactory;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@SpringBootApplication
|
||||
@Configuration
|
||||
public class TestApplication {
|
||||
|
||||
@Bean
|
||||
public EntityFactory entityFactory(){
|
||||
return new MapperEntityFactory();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.hswebframework.web.crud.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.crud.annotation.Reactive;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Table(name = "s_test")
|
||||
@Reactive
|
||||
@AllArgsConstructor(staticName = "of")
|
||||
@NoArgsConstructor
|
||||
public class TestEntity extends GenericEntity<String> {
|
||||
|
||||
@Column(length = 32)
|
||||
private String name;
|
||||
|
||||
@Column
|
||||
private Integer age;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.hswebframework.web.crud.service;
|
||||
|
||||
import org.hswebframework.web.crud.entity.TestEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class TestEntityService extends GenericReactiveCrudService<TestEntity,String> {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
logging:
|
||||
level:
|
||||
org.hswebframework: debug
|
||||
org.springframework.transaction: debug
|
||||
org.springframework.data.r2dbc.connectionfactory: debug
|
||||
#spring:
|
||||
# r2dbc:
|
||||
#
|
||||
easyorm:
|
||||
default-schema: PUBLIC
|
||||
dialect: h2
|
||||
@@ -1,5 +0,0 @@
|
||||
# 通用DAO实现
|
||||
|
||||
支持动态条件的通用CRUD实现
|
||||
|
||||
⚠️注意:目前仅提供了[mybatis](hsweb-commons-dao-mybatis)实现.
|
||||
@@ -1,47 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ /*
|
||||
~ * Copyright 2019 http://www.hswebframework.org
|
||||
~ *
|
||||
~ * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ * you may not use this file except in compliance with the License.
|
||||
~ * You may obtain a copy of the License at
|
||||
~ *
|
||||
~ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
~ *
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ * See the License for the specific language governing permissions and
|
||||
~ * limitations under the License.
|
||||
~ */
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hsweb-commons-dao</artifactId>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hsweb-commons-dao-api</artifactId>
|
||||
|
||||
<description>通用增删改查-通用Dao接口模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-entity</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao;
|
||||
|
||||
import org.hswebframework.web.dao.dynamic.UpdateByEntityDao;
|
||||
import org.hswebframework.web.dao.dynamic.DeleteByEntityDao;
|
||||
import org.hswebframework.web.dao.dynamic.QueryByEntityDao;
|
||||
|
||||
/**
|
||||
* 通用增删改查DAO接口,定义了增删改查.以及动态条件查询,修改,删除。
|
||||
*
|
||||
* @param <E> PO类型
|
||||
* @param <PK> 主键类型
|
||||
* @author zhouhao
|
||||
* @see InsertDao
|
||||
* @see DeleteDao
|
||||
* @see DeleteByEntityDao
|
||||
* @see UpdateByEntityDao
|
||||
* @see QueryByEntityDao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface CrudDao<E, PK> extends
|
||||
InsertDao<E>,
|
||||
DeleteDao<PK>,
|
||||
DeleteByEntityDao,
|
||||
UpdateByEntityDao,
|
||||
QueryByEntityDao<E> {
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao;
|
||||
|
||||
/**
|
||||
* Dao的总接口,用于标识类为Dao
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface Dao {
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao;
|
||||
|
||||
/**
|
||||
* 通用删除dao
|
||||
*
|
||||
* @param <PK> 主键类型
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface DeleteDao<PK> extends Dao {
|
||||
/**
|
||||
* 根据主键删除数据,并返回被删除数据的数量
|
||||
*
|
||||
* @param pk 主键
|
||||
* @return 删除的数据数量, 理论上此返回值应该为0或者1.
|
||||
*/
|
||||
int deleteByPk(PK pk);
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao;
|
||||
|
||||
/**
|
||||
* 通用数据插入DAO接口
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface InsertDao<E> extends Dao {
|
||||
void insert(E e);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao.dynamic;
|
||||
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
|
||||
/**
|
||||
* 根据实体类条件进行删除,删除条件根据实体类进行解析。解析方式和{@link QueryByEntityDao#query}一致
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface DeleteByEntityDao {
|
||||
int delete(Entity entity);
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.dao.dynamic;
|
||||
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
|
||||
/**
|
||||
* 根据实体类进行更新,实体类支持动态条件或者普通实体类。
|
||||
* 动态条件和{@link QueryByEntityDao#query(Entity)} 一致。
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface UpdateByEntityDao {
|
||||
int update(Entity entity);
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ /*
|
||||
~ * Copyright 2019 http://www.hswebframework.org
|
||||
~ *
|
||||
~ * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ * you may not use this file except in compliance with the License.
|
||||
~ * You may obtain a copy of the License at
|
||||
~ *
|
||||
~ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
~ *
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ * See the License for the specific language governing permissions and
|
||||
~ * limitations under the License.
|
||||
~ */
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hsweb-commons</artifactId>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<description>通用增删改查-通用Dao模块</description>
|
||||
|
||||
<artifactId>hsweb-commons-dao</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>hsweb-commons-dao-api</module>
|
||||
<module>hsweb-commons-dao-mybatis</module>
|
||||
</modules>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework</groupId>
|
||||
<artifactId>hsweb-easy-orm-rdb</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,49 +0,0 @@
|
||||
# 通用实体类模块
|
||||
集成系统通用的实体类,如 树形结构实体,排序实体,创建信息实体
|
||||
|
||||
# 常用实体类
|
||||
|
||||
| 类名 | 说明 |
|
||||
| ------------- |:-------------:|
|
||||
| [`Entity`](src/main/java/org/hswebframework/web/commons/entity/Entity.java) | 实体类的总接口,用来标识为一个实体类 |
|
||||
| [`GenericEntity`](src/main/java/org/hswebframework/web/commons/entity/GenericEntity.java) | 提供基本属性的实体类 |
|
||||
| [`RecordCreationEntity`](src/main/java/org/hswebframework/web/commons/entity/RecordCreationEntity.java) | 可记录创建信息的实体类 |
|
||||
| [`TreeSortSupportEntity`](src/main/java/org/hswebframework/web/commons/entity/TreeSortSupportEntity.java) | 可排序树形结构实体类 |
|
||||
|
||||
# 实体类工厂
|
||||
作用: 为了增加拓展性,各个地方依赖的实体均为接口,实体实例应该调用[EntityFactory](src/main/java/org/hswebframework/web/commons/entity/factory/EntityFactory.java)
|
||||
进行实例化。如: `UserEntity user=entityFactory.newInstance(UserEntity.class);`
|
||||
|
||||
目标: controller,service 不再依赖具体实体实现类。实现类由 dao和springMvc进行提供
|
||||
|
||||
默认工厂实现: [MapperEntityFactory](src/main/java/org/hswebframework/web/commons/entity/factory/MapperEntityFactory.java)
|
||||
该工厂可注册接口和实现类的映射关系,以及提供默认的实现类创建。
|
||||
默认的实现类创建逻辑为。`Class.forName("Simple"+interfaceName);`
|
||||
如:`UserEntity user=entityFactory.newInstance(UserEntity.class)`
|
||||
如果未注册`UserEntity`对应的实现类,则将尝试创建`UserEntity`同包下的`SimpleUserEntity`类实例
|
||||
|
||||
注册接口和实现类映射关系:
|
||||
|
||||
方式1: 调用 mapperEntityFactory进行注册
|
||||
|
||||
```java
|
||||
@javax.annotation.Resource
|
||||
private MapperEntityFactory mapperEntityFactory;
|
||||
|
||||
@javax.annotation.PostConstruct
|
||||
public void init(){
|
||||
mapperEntityFactory.addMapping(UserEntity.class,new Mapper(CustomUserEntity.class,CustomUserEntity::new));
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
方式2: application.yml 配置文件描述
|
||||
|
||||
```yaml
|
||||
entity:
|
||||
mappings:
|
||||
- source-base-package: org.hswebframework.web.entity.authorization
|
||||
target-base-package: com.company.authorization
|
||||
mapping:
|
||||
UserEntity: CustomUserEntity
|
||||
```
|
||||
@@ -1,72 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ /*
|
||||
~ * Copyright 2019 http://www.hswebframework.org
|
||||
~ *
|
||||
~ * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ * you may not use this file except in compliance with the License.
|
||||
~ * You may obtain a copy of the License at
|
||||
~ *
|
||||
~ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
~ *
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ * See the License for the specific language governing permissions and
|
||||
~ * limitations under the License.
|
||||
~ */
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hsweb-commons</artifactId>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hsweb-commons-entity</artifactId>
|
||||
|
||||
<description>通用增删改查-通用实体模块</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>${project.parent.groupId}</groupId>
|
||||
<artifactId>hsweb-core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework</groupId>
|
||||
<artifactId>hsweb-easy-orm-rdb</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework</groupId>
|
||||
<artifactId>hsweb-utils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-utils</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate.validator</groupId>
|
||||
<artifactId>hibernate-validator</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.swagger</groupId>
|
||||
<artifactId>swagger-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<artifactId>hsweb-commons-bean</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public interface CloneableEntity extends Entity, Cloneable {
|
||||
CloneableEntity clone();
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @see DataStatusEnum
|
||||
*/
|
||||
public interface DataStatus {
|
||||
Byte STATUS_ENABLED = 1;
|
||||
Byte STATUS_DISABLED = 0;
|
||||
Byte STATUS_LOCKED = -1;
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.hswebframework.web.dict.EnumDict;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public enum DataStatusEnum implements EnumDict<Byte> {
|
||||
ENABLED((byte) 1, "正常"),
|
||||
DISABLED((byte) 0, "禁用"),
|
||||
LOCK((byte) -1, "锁定"),
|
||||
DELETED((byte) -10, "删除");
|
||||
|
||||
private Byte value;
|
||||
|
||||
private String text;
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import org.hswebframework.web.commons.bean.Bean;
|
||||
import org.hswebframework.web.commons.bean.ValidateBean;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 实体总接口,所有实体需实现此接口
|
||||
*
|
||||
* @author zhouhao
|
||||
* @see org.hswebframework.web.commons.entity.factory.EntityFactory
|
||||
* @see GenericEntity
|
||||
* @see TreeSupportEntity
|
||||
* @see TreeSortSupportEntity
|
||||
* @see Bean
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface Entity extends ValidateBean {
|
||||
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import org.hswebframework.web.bean.ToString;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通用实体,提供实体常用属性
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface GenericEntity<PK> extends CloneableEntity {
|
||||
String id = "id";
|
||||
|
||||
String properties = "properties";
|
||||
|
||||
PK getId();
|
||||
|
||||
void setId(PK id);
|
||||
|
||||
default String toString(String... ignoreProperty) {
|
||||
return ToString.toString(this, ignoreProperty);
|
||||
}
|
||||
|
||||
default Map<String, Object> getProperties() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default void setProperties(Map<String, Object> properties) {
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
default <T> T getProperty(String propertyName, T defaultValue) {
|
||||
Map<String, Object> map = getProperties();
|
||||
if (map == null) {
|
||||
return null;
|
||||
}
|
||||
return (T) map.getOrDefault(propertyName, defaultValue);
|
||||
}
|
||||
|
||||
default <T> T getProperty(String propertyName) {
|
||||
return getProperty(propertyName, null);
|
||||
}
|
||||
|
||||
default void setProperty(String propertyName, Object value) {
|
||||
Map<String, Object> map = getProperties();
|
||||
if (map == null) {
|
||||
map = new LinkedHashMap<>();
|
||||
setProperties(map);
|
||||
}
|
||||
map.put(propertyName, value);
|
||||
}
|
||||
|
||||
default Map<String, Object> cloneProperties() {
|
||||
Map<String, Object> target = new LinkedHashMap<>();
|
||||
Map<String, Object> old = getProperties();
|
||||
if (old == null || old.isEmpty()) {
|
||||
return target;
|
||||
}
|
||||
old.forEach((k, v) -> {
|
||||
if (v instanceof CloneableEntity) {
|
||||
target.put(k, ((CloneableEntity) v).clone());
|
||||
} else {
|
||||
target.put(k, v);
|
||||
}
|
||||
});
|
||||
return target;
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
/**
|
||||
* 逻辑删除
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0.6
|
||||
*/
|
||||
public interface LogicalDeleteEntity {
|
||||
|
||||
Boolean getDeleted();
|
||||
|
||||
void setDeleted(boolean deleted);
|
||||
|
||||
Long getDeleteTime();
|
||||
|
||||
void setDeleteTime(Long deleteTime);
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.commons.entity.param.QueryParamEntity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@ApiModel(description = "分页结果")
|
||||
@Getter
|
||||
@Setter
|
||||
public class PagerResult<E> implements Entity {
|
||||
private static final long serialVersionUID = -6171751136953308027L;
|
||||
|
||||
public static <E> PagerResult<E> empty() {
|
||||
return new PagerResult<>(0, new ArrayList<>());
|
||||
}
|
||||
|
||||
public static <E> PagerResult<E> of(int total, List<E> list) {
|
||||
return new PagerResult<>(total, list);
|
||||
}
|
||||
|
||||
public static <E> PagerResult<E> of(int total, List<E> list, QueryParamEntity entity) {
|
||||
PagerResult pagerResult = new PagerResult<>(total, list);
|
||||
pagerResult.setPageIndex(entity.getThinkPageIndex());
|
||||
pagerResult.setPageSize(entity.getPageSize());
|
||||
return pagerResult;
|
||||
}
|
||||
|
||||
|
||||
@ApiModelProperty("当前页码")
|
||||
private int pageIndex;
|
||||
|
||||
@ApiModelProperty("每页数据数量")
|
||||
private int pageSize;
|
||||
|
||||
@ApiModelProperty("数据总数量")
|
||||
private int total;
|
||||
|
||||
@ApiModelProperty("查询结果")
|
||||
private List<E> data;
|
||||
|
||||
public PagerResult() {
|
||||
}
|
||||
|
||||
public PagerResult(int total, List<E> data) {
|
||||
this.total = total;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import org.hswebframework.web.HttpParameterConverter;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface QueryEntity extends Entity {
|
||||
/**
|
||||
* 转为http查询参数
|
||||
* @return
|
||||
*/
|
||||
default String toHttpQueryParamString() {
|
||||
Map<String, String> result = new HttpParameterConverter(this).convert();
|
||||
StringJoiner joiner = new StringJoiner("&");
|
||||
result.forEach((key, value) -> joiner.add(key.concat("=").concat(value)));
|
||||
return joiner.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
/**
|
||||
* 记录创建信息的实体类,包括创建人和创建时间。
|
||||
* 此实体类与行级权限控制相关联:只能操作自己创建的数据
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface RecordCreationEntity extends Entity {
|
||||
|
||||
String creatorId = "creatorId";
|
||||
String createTime = "createTime";
|
||||
|
||||
String getCreatorId();
|
||||
|
||||
void setCreatorId(String creatorId);
|
||||
|
||||
Long getCreateTime();
|
||||
|
||||
void setCreateTime(Long createTime);
|
||||
|
||||
default void setCreateTimeNow() {
|
||||
setCreateTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
default String getCreatorIdProperty() {
|
||||
return creatorId;
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
/**
|
||||
* 记录修改信息的实体类,包括修改人和修改时间。
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0.6
|
||||
*/
|
||||
public interface RecordModifierEntity extends Entity {
|
||||
|
||||
String modifierId = "modifierId";
|
||||
String modifyTime = "modifyTime";
|
||||
|
||||
String getModifierId();
|
||||
|
||||
void setModifierId(String modifierId);
|
||||
|
||||
Long getModifyTime();
|
||||
|
||||
void setModifyTime(Long modifyTime);
|
||||
|
||||
default void setModifyTimeNow() {
|
||||
setModifyTime(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
default String getModifierIdProperty() {
|
||||
return modifierId;
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class SimpleGenericEntity<PK> implements GenericEntity<PK> {
|
||||
|
||||
private static final long serialVersionUID = 4546315942526096290L;
|
||||
|
||||
private PK id;
|
||||
|
||||
private Map<String, Object> properties;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toString((String[]) null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PK getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(PK id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getProperties() {
|
||||
return properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperties(Map<String, Object> properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getProperty(String propertyName, T defaultValue) {
|
||||
if (null == properties) {
|
||||
return defaultValue;
|
||||
}
|
||||
return (T) properties.getOrDefault(propertyName, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getProperty(String propertyName) {
|
||||
return getProperty(propertyName, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProperty(String propertyName, Object value) {
|
||||
if (null == properties) {
|
||||
properties = new LinkedHashMap<>();
|
||||
}
|
||||
properties.put(propertyName, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@SneakyThrows
|
||||
public SimpleGenericEntity<PK> clone() {
|
||||
return (SimpleGenericEntity) super.clone();
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.events;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class EntityCreatedEvent<E> implements Serializable {
|
||||
|
||||
private E entity;
|
||||
|
||||
private Class<E> entityType;
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.events;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
public class EntityModifyEvent<E> implements Serializable{
|
||||
|
||||
private static final long serialVersionUID = -7158901204884303777L;
|
||||
|
||||
private E before;
|
||||
|
||||
private E after;
|
||||
|
||||
private Class<E> entityType;
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* 默认的实体映射
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DefaultMapperFactory extends Function<Class, MapperEntityFactory.Mapper> {
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
/**
|
||||
* 默认的属性复制器
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface DefaultPropertyCopier extends PropertyCopier<Object, Object> {
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
|
||||
/**
|
||||
* 实体工厂接口,系统各个地方使用此接口来创建实体,在实际编码中也应该使用此接口来创建实体,而不是使用new方式来创建
|
||||
*
|
||||
* @author zhouhao
|
||||
* @see Entity
|
||||
* @see MapperEntityFactory
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface EntityFactory {
|
||||
/**
|
||||
* 根据类型创建实例
|
||||
* <p>
|
||||
* e.g.
|
||||
* <pre>
|
||||
* entityFactory.newInstance(UserEntity.class);
|
||||
* </pre>
|
||||
*
|
||||
* @param entityClass 要创建的class
|
||||
* @param <T> 类型
|
||||
* @return 创建结果
|
||||
*/
|
||||
<T> T newInstance(Class<T> entityClass);
|
||||
|
||||
|
||||
/**
|
||||
* 根据类型创建实例,如果类型无法创建,则使用默认类型进行创建
|
||||
* <p>
|
||||
* e.g.
|
||||
* <pre>
|
||||
* entityFactory.newInstance(UserEntity.class,SimpleUserEntity.class);
|
||||
* </pre>
|
||||
*
|
||||
* @param entityClass 要创建的class
|
||||
* @param defaultClass 默认class,当{@code entityClass}无法创建时使用此类型进行创建
|
||||
* @param <T> 类型
|
||||
* @return 实例
|
||||
*/
|
||||
<T> T newInstance(Class<T> entityClass, Class<? extends T> defaultClass);
|
||||
|
||||
/**
|
||||
* 创建实体并设置默认的属性
|
||||
*
|
||||
* @param entityClass 实体类型
|
||||
* @param defaultProperties 默认属性
|
||||
* @param <S> 默认属性的类型
|
||||
* @param <T> 实体类型
|
||||
* @return 创建结果
|
||||
* @see EntityFactory#copyProperties(Object, Object)
|
||||
*/
|
||||
default <S, T> T newInstance(Class<T> entityClass, S defaultProperties) {
|
||||
return copyProperties(defaultProperties, newInstance(entityClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建实体并设置默认的属性
|
||||
*
|
||||
* @param entityClass 实体类型
|
||||
* @param defaultClass 默认class
|
||||
* @param defaultProperties 默认属性
|
||||
* @param <S> 默认属性的类型
|
||||
* @param <T> 实体类型
|
||||
* @return 创建结果
|
||||
* @see EntityFactory#copyProperties(Object, Object)
|
||||
*/
|
||||
default <S, T> T newInstance(Class<T> entityClass, Class<? extends T> defaultClass, S defaultProperties) {
|
||||
return copyProperties(defaultProperties, newInstance(entityClass, defaultClass));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据类型获取实体的真实的实体类型,
|
||||
* 可通过此方法获取获取已拓展的实体类型,如:<br>
|
||||
* <code>
|
||||
* factory.getInstanceType(MyBeanInterface.class);
|
||||
* </code>
|
||||
*
|
||||
* @param entityClass 类型
|
||||
* @param <T> 泛型
|
||||
* @return 实体类型
|
||||
*/
|
||||
<T> Class<T> getInstanceType(Class<T> entityClass);
|
||||
|
||||
/**
|
||||
* 拷贝对象的属性
|
||||
*
|
||||
* @param source 要拷贝到的对象
|
||||
* @param target 被拷贝的对象
|
||||
* @param <S> 要拷贝对象的类型
|
||||
* @param <T> 被拷贝对象的类型
|
||||
* @return 被拷贝的对象
|
||||
*/
|
||||
<S, T> T copyProperties(S source, T target);
|
||||
}
|
||||
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.hswebframework.web.exception.NotFoundException;
|
||||
import org.hswebframework.utils.ClassUtils;
|
||||
import org.hswebframework.web.bean.BeanFactory;
|
||||
import org.hswebframework.web.bean.FastBeanCopier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MapperEntityFactory implements EntityFactory, BeanFactory {
|
||||
private Map<Class, Mapper> realTypeMapper = new HashMap<>();
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
private Map<String, PropertyCopier> copierCache = new HashMap<>();
|
||||
|
||||
private static final DefaultMapperFactory DEFAULT_MAPPER_FACTORY = clazz -> {
|
||||
String simpleClassName = clazz.getPackage().getName().concat(".Simple").concat(clazz.getSimpleName());
|
||||
try {
|
||||
return defaultMapper(Class.forName(simpleClassName));
|
||||
} catch (ClassNotFoundException ignore) {
|
||||
// throw new NotFoundException(e.getMessage());
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* 默认的属性复制器
|
||||
*/
|
||||
private static final DefaultPropertyCopier DEFAULT_PROPERTY_COPIER = FastBeanCopier::copy;
|
||||
|
||||
private DefaultMapperFactory defaultMapperFactory = DEFAULT_MAPPER_FACTORY;
|
||||
|
||||
private DefaultPropertyCopier defaultPropertyCopier = DEFAULT_PROPERTY_COPIER;
|
||||
|
||||
|
||||
public MapperEntityFactory() {
|
||||
}
|
||||
|
||||
public <T> MapperEntityFactory(Map<Class<T>, Mapper> realTypeMapper) {
|
||||
this.realTypeMapper.putAll(realTypeMapper);
|
||||
}
|
||||
|
||||
public <T> MapperEntityFactory addMapping(Class<T> target, Mapper<? extends T> mapper) {
|
||||
realTypeMapper.put(target, mapper);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MapperEntityFactory addCopier(PropertyCopier copier) {
|
||||
Class source = ClassUtils.getGenericType(copier.getClass(), 0);
|
||||
Class target = ClassUtils.getGenericType(copier.getClass(), 1);
|
||||
if (source == null || source == Object.class) {
|
||||
throw new UnsupportedOperationException("generic type " + source + " not support");
|
||||
}
|
||||
if (target == null || target == Object.class) {
|
||||
throw new UnsupportedOperationException("generic type " + target + " not support");
|
||||
}
|
||||
addCopier(source, target, copier);
|
||||
return this;
|
||||
}
|
||||
|
||||
public <S, T> MapperEntityFactory addCopier(Class<S> source, Class<T> target, PropertyCopier<S, T> copier) {
|
||||
copierCache.put(getCopierCacheKey(source, target), copier);
|
||||
return this;
|
||||
}
|
||||
|
||||
private String getCopierCacheKey(Class source, Class target) {
|
||||
return source.getName().concat("->").concat(target.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S, T> T copyProperties(S source, T target) {
|
||||
Objects.requireNonNull(source);
|
||||
Objects.requireNonNull(target);
|
||||
try {
|
||||
PropertyCopier<S, T> copier = copierCache.<S, T>get(getCopierCacheKey(source.getClass(), target.getClass()));
|
||||
if (null != copier) {
|
||||
return copier.copyProperties(source, target);
|
||||
}
|
||||
|
||||
return (T) defaultPropertyCopier.copyProperties(source, target);
|
||||
} catch (Exception e) {
|
||||
logger.warn("copy properties error", e);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
protected <T> Mapper<T> initCache(Class<T> beanClass) {
|
||||
Mapper<T> mapper = null;
|
||||
Class<T> realType = null;
|
||||
ServiceLoader<T> serviceLoader = ServiceLoader.load(beanClass, this.getClass().getClassLoader());
|
||||
Iterator<T> iterator = serviceLoader.iterator();
|
||||
if (iterator.hasNext()) {
|
||||
realType = (Class<T>) iterator.next().getClass();
|
||||
}
|
||||
//尝试使用 Simple类,如: package.SimpleUserBean
|
||||
if (realType == null) {
|
||||
mapper = defaultMapperFactory.apply(beanClass);
|
||||
}
|
||||
if (!Modifier.isInterface(beanClass.getModifiers()) && !Modifier.isAbstract(beanClass.getModifiers())) {
|
||||
realType = beanClass;
|
||||
}
|
||||
if (mapper == null && realType != null) {
|
||||
if (logger.isDebugEnabled() && realType != beanClass) {
|
||||
logger.debug("use instance {} for {}", realType, beanClass);
|
||||
}
|
||||
mapper = new Mapper<>(realType, new DefaultInstanceGetter(realType));
|
||||
}
|
||||
if (mapper != null) {
|
||||
realTypeMapper.put(beanClass, mapper);
|
||||
}
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T newInstance(Class<T> beanClass) {
|
||||
return newInstance(beanClass, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T newInstance(Class<T> beanClass, Class<? extends T> defaultClass) {
|
||||
if (beanClass == null) {
|
||||
return null;
|
||||
}
|
||||
Mapper<T> mapper = realTypeMapper.get(beanClass);
|
||||
if (mapper != null) {
|
||||
return mapper.getInstanceGetter().get();
|
||||
}
|
||||
mapper = initCache(beanClass);
|
||||
if (mapper != null) {
|
||||
return mapper.getInstanceGetter().get();
|
||||
}
|
||||
if (defaultClass != null) {
|
||||
return newInstance(defaultClass);
|
||||
}
|
||||
if (Map.class == beanClass) {
|
||||
return (T) new HashMap<>();
|
||||
}
|
||||
if (List.class == beanClass) {
|
||||
return (T) new ArrayList<>();
|
||||
}
|
||||
if (Set.class == beanClass) {
|
||||
return (T) new HashSet<>();
|
||||
}
|
||||
|
||||
throw new NotFoundException("can't create instance for " + beanClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Class<T> getInstanceType(Class<T> beanClass) {
|
||||
Mapper<T> mapper = realTypeMapper.get(beanClass);
|
||||
if (null != mapper) {
|
||||
return mapper.getTarget();
|
||||
}
|
||||
mapper = initCache(beanClass);
|
||||
if (mapper != null) {
|
||||
return mapper.getTarget();
|
||||
}
|
||||
|
||||
return Modifier.isAbstract(beanClass.getModifiers())
|
||||
|| Modifier.isInterface(beanClass.getModifiers())
|
||||
? null : beanClass;
|
||||
}
|
||||
|
||||
public void setDefaultMapperFactory(DefaultMapperFactory defaultMapperFactory) {
|
||||
Objects.requireNonNull(defaultMapperFactory);
|
||||
this.defaultMapperFactory = defaultMapperFactory;
|
||||
}
|
||||
|
||||
public void setDefaultPropertyCopier(DefaultPropertyCopier defaultPropertyCopier) {
|
||||
this.defaultPropertyCopier = defaultPropertyCopier;
|
||||
}
|
||||
|
||||
public static class Mapper<T> {
|
||||
Class<T> target;
|
||||
Supplier<T> instanceGetter;
|
||||
|
||||
public Mapper(Class<T> target, Supplier<T> instanceGetter) {
|
||||
this.target = target;
|
||||
this.instanceGetter = instanceGetter;
|
||||
}
|
||||
|
||||
public Class<T> getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public Supplier<T> getInstanceGetter() {
|
||||
return instanceGetter;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Mapper<T> defaultMapper(Class<T> target) {
|
||||
return new Mapper<>(target, defaultInstanceGetter(target));
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> defaultInstanceGetter(Class<T> clazz) {
|
||||
return new DefaultInstanceGetter<>(clazz);
|
||||
}
|
||||
|
||||
static class DefaultInstanceGetter<T> implements Supplier<T> {
|
||||
Class<T> type;
|
||||
|
||||
public DefaultInstanceGetter(Class<T> type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public T get() {
|
||||
return type.newInstance();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
/**
|
||||
* 属性复制接口,用于自定义属性复制
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 3.0
|
||||
*/
|
||||
public interface PropertyCopier<S, T> {
|
||||
T copyProperties(S source, T target);
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.param;
|
||||
|
||||
import org.hswebframework.ezorm.core.dsl.Delete;
|
||||
import org.hswebframework.ezorm.core.dsl.Update;
|
||||
import org.hswebframework.ezorm.core.param.Param;
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
import org.hswebframework.web.commons.entity.QueryEntity;
|
||||
|
||||
/**
|
||||
* 查询参数实体,使用<a href="https://github.com/hs-web/hsweb-easy-orm">easyorm</a>进行动态查询参数构建<br>
|
||||
* 可通过静态方法创建:<br>
|
||||
* {@link DeleteParamEntity#build()}<br>
|
||||
*
|
||||
* @author zhouhao
|
||||
* @see Param
|
||||
* @see Entity
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DeleteParamEntity extends Param implements QueryEntity {
|
||||
private static final long serialVersionUID = 6120598637420234301L;
|
||||
|
||||
/**
|
||||
* 创建一个无条件的删除条件实体
|
||||
* 创建后需自行指定条件({@link DeleteParamEntity#where(String, Object)})
|
||||
* 否则可能无法执行更新(dao实现应该禁止无条件的删除)
|
||||
*
|
||||
* @return DeleteParamEntity
|
||||
*/
|
||||
public static DeleteParamEntity build() {
|
||||
return new DeleteParamEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public static Delete<DeleteParamEntity> newDelete() {
|
||||
return new Delete<>(new DeleteParamEntity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toHttpQueryParamString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,161 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.param;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.ezorm.core.NestConditional;
|
||||
import org.hswebframework.ezorm.core.dsl.Query;
|
||||
import org.hswebframework.ezorm.core.param.QueryParam;
|
||||
import org.hswebframework.ezorm.core.param.Term;
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
import org.hswebframework.web.commons.entity.QueryEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* 查询参数实体,使用<a href="https://github.com/hs-web/hsweb-easy-orm">easyorm</a>进行动态查询参数构建<br>
|
||||
* 可通过静态方法创建:<br>
|
||||
* {@link QueryParamEntity#empty()}<br>
|
||||
* {@link QueryParamEntity#single(String, Object)}<br>
|
||||
* 如:
|
||||
* <code>
|
||||
* QueryParamEntity.single("id",id);
|
||||
* </code>
|
||||
*
|
||||
* @author zhouhao
|
||||
* @see QueryParam
|
||||
* @see Entity
|
||||
* @since 3.0
|
||||
*/
|
||||
public class QueryParamEntity extends QueryParam implements QueryEntity {
|
||||
|
||||
private static final long serialVersionUID = 8097500947924037523L;
|
||||
|
||||
@Getter
|
||||
private String termExpression;
|
||||
|
||||
/**
|
||||
* 创建一个空的查询参数实体,该实体无任何参数.
|
||||
*
|
||||
* @return 无条件的参数实体
|
||||
*/
|
||||
public static QueryParamEntity empty() {
|
||||
return new QueryParamEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个含有单个条件的参数实体,条件默认为is
|
||||
*
|
||||
* @param field 参数名称
|
||||
* @param value 参数值
|
||||
* @return 单个条件的参数实体
|
||||
* @see QueryParam#where(String, Object)
|
||||
*/
|
||||
public static QueryParamEntity single(String field, Object value) {
|
||||
return of(field, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see this#single(String, Object)
|
||||
*/
|
||||
public static QueryParamEntity of(String field, Object value) {
|
||||
return empty().where(field, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public static <T> Query<T, QueryParamEntity> newQuery() {
|
||||
return Query.empty(new QueryParamEntity());
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public <T> Query<T, QueryParamEntity> toQuery() {
|
||||
return Query.empty(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将已有的条件包装到一个嵌套的条件里,并返回一个Query对象.例如:
|
||||
* <pre>
|
||||
* entity.toNestQuery().and("userId",userId);
|
||||
* </pre>
|
||||
* <p>
|
||||
* 原有条件: name=? or type=?
|
||||
* <p>
|
||||
* 执行后条件: (name=? or type=?) and userId=?
|
||||
*
|
||||
* @see this#toNestQuery(Consumer)
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public <T> Query<T, QueryParamEntity> toNestQuery() {
|
||||
return toNestQuery(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将已有的条件包装到一个嵌套的条件里,并返回一个Query对象.例如:
|
||||
* <pre>
|
||||
* entity.toNestQuery(query->query.and("userId",userId));
|
||||
* </pre>
|
||||
* <p>
|
||||
* 原有条件: name=? or type=?
|
||||
* <p>
|
||||
* 执行后条件: userId=? (name=? or type=?)
|
||||
*
|
||||
* @param before 在包装之前执行,将条件包装到已有条件之前
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public <T> Query<T, QueryParamEntity> toNestQuery(Consumer<Query<T, QueryParamEntity>> before) {
|
||||
List<Term> terms = getTerms();
|
||||
setTerms(new ArrayList<>());
|
||||
Query<T, QueryParamEntity> query = toQuery();
|
||||
if (null != before) {
|
||||
before.accept(query);
|
||||
}
|
||||
return query
|
||||
.nest()
|
||||
.each(terms, NestConditional::accept)
|
||||
.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置条件表达式,可以通过表达式的方式快速构建查询条件. 表达式是类似sql条件的语法,如:
|
||||
* <pre>
|
||||
* name is 测试 and age gte 10
|
||||
* </pre>
|
||||
* <pre>
|
||||
* name is 测试 and (age gt 10 or age lte 90 )
|
||||
* </pre>
|
||||
*
|
||||
* @param termExpression 表达式
|
||||
* @see 3.0.5
|
||||
*/
|
||||
public void setTermExpression(String termExpression) {
|
||||
this.termExpression = termExpression;
|
||||
setTerms(TermExpressionParser.parse(termExpression));
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Term> getTerms() {
|
||||
List<Term> terms = super.getTerms();
|
||||
if (CollectionUtils.isEmpty(terms) && StringUtils.hasText(termExpression)) {
|
||||
setTerms(terms = TermExpressionParser.parse(termExpression));
|
||||
}
|
||||
return terms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toHttpQueryParamString();
|
||||
}
|
||||
|
||||
public QueryParamEntity noPaging() {
|
||||
setPaging(false);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,184 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.param;
|
||||
|
||||
import org.hswebframework.ezorm.core.NestConditional;
|
||||
import org.hswebframework.ezorm.core.dsl.Query;
|
||||
import org.hswebframework.ezorm.core.param.Term;
|
||||
import org.hswebframework.ezorm.core.param.TermType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 动态条件表达式解析器
|
||||
* name=测试 and age=test
|
||||
*/
|
||||
public class TermExpressionParser {
|
||||
|
||||
public static List<Term> parse(String expression) {
|
||||
Query<?, QueryParamEntity> conditional = QueryParamEntity.newQuery();
|
||||
|
||||
NestConditional<?> nest = null;
|
||||
|
||||
// 字符容器
|
||||
char[] buf = new char[128];
|
||||
// 记录词项的长度, Arrays.copyOf使用
|
||||
byte len = 0;
|
||||
// 空格数量?
|
||||
byte spaceLen = 0;
|
||||
// 当前列
|
||||
char[] currentColumn = null;
|
||||
// 当前列对应的值
|
||||
char[] currentValue = null;
|
||||
// 当前条件类型 eq btw in ...
|
||||
String currentTermType = null;
|
||||
// 当前链接类型 and / or
|
||||
String currentType = "and";
|
||||
// 是否是引号, 单引号 / 双引号
|
||||
byte quotationMarks = 0;
|
||||
// 表达式字符数组
|
||||
char[] all = expression.toCharArray();
|
||||
|
||||
for (char c : all) {
|
||||
|
||||
if (c == '\'' || c == '"') {
|
||||
if (quotationMarks != 0) {
|
||||
// 碰到(结束的)单/双引号, 标志归零, 跳过
|
||||
quotationMarks = 0;
|
||||
continue;
|
||||
}
|
||||
// 碰到(开始的)单/双引号, 做记录, 跳过
|
||||
quotationMarks++;
|
||||
continue;
|
||||
} else if (c == '(') {
|
||||
nest = (nest == null ?
|
||||
(currentType.equals("or") ? conditional.orNest() : conditional.nest()) :
|
||||
(currentType.equals("or") ? nest.orNest() : nest.nest()));
|
||||
len = 0;
|
||||
continue;
|
||||
} else if (c == ')') {
|
||||
if (nest == null) {
|
||||
continue;
|
||||
}
|
||||
if (null != currentColumn) {
|
||||
currentValue = Arrays.copyOf(buf, len);
|
||||
nest.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
|
||||
currentColumn = null;
|
||||
currentTermType = null;
|
||||
}
|
||||
Object end = nest.end();
|
||||
nest = end instanceof NestConditional ? ((NestConditional) end) : null;
|
||||
len = 0;
|
||||
spaceLen++;
|
||||
continue;
|
||||
} else if (c == '=' || c == '>' || c == '<') {
|
||||
if (currentTermType != null) {
|
||||
currentTermType += String.valueOf(c);
|
||||
//spaceLen--;
|
||||
} else {
|
||||
currentTermType = String.valueOf(c);
|
||||
}
|
||||
|
||||
if (currentColumn == null) {
|
||||
currentColumn = Arrays.copyOf(buf, len);
|
||||
}
|
||||
spaceLen++;
|
||||
len = 0;
|
||||
continue;
|
||||
} else if (c == ' ') {
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
if (quotationMarks != 0) {
|
||||
// 如果当前字符是空格,并且前面迭代时碰到过单/双引号, 不处理并且添加到buf中
|
||||
buf[len++] = c;
|
||||
continue;
|
||||
}
|
||||
spaceLen++;
|
||||
if (currentColumn == null && (spaceLen == 1 || spaceLen % 5 == 0)) {
|
||||
currentColumn = Arrays.copyOf(buf, len);
|
||||
len = 0;
|
||||
continue;
|
||||
}
|
||||
if (null != currentColumn) {
|
||||
if (null == currentTermType) {
|
||||
currentTermType = new String(Arrays.copyOf(buf, len));
|
||||
len = 0;
|
||||
continue;
|
||||
}
|
||||
currentValue = Arrays.copyOf(buf, len);
|
||||
if (nest != null) {
|
||||
nest.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
|
||||
} else {
|
||||
conditional.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
|
||||
}
|
||||
currentColumn = null;
|
||||
currentTermType = null;
|
||||
len = 0;
|
||||
continue;
|
||||
} else if (len == 2 || len == 3) {
|
||||
String type = new String(Arrays.copyOf(buf, len));
|
||||
if (type.equalsIgnoreCase("or")) {
|
||||
currentType = "or";
|
||||
if (nest != null) {
|
||||
nest.or();
|
||||
} else {
|
||||
conditional.or();
|
||||
}
|
||||
len = 0;
|
||||
continue;
|
||||
} else if (type.equalsIgnoreCase("and")) {
|
||||
currentType = "and";
|
||||
if (nest != null) {
|
||||
nest.and();
|
||||
} else {
|
||||
conditional.and();
|
||||
}
|
||||
len = 0;
|
||||
continue;
|
||||
} else {
|
||||
currentColumn = Arrays.copyOf(buf, len);
|
||||
len = 0;
|
||||
spaceLen++;
|
||||
}
|
||||
} else {
|
||||
currentColumn = Arrays.copyOf(buf, len);
|
||||
len = 0;
|
||||
spaceLen++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buf[len++] = c;
|
||||
}
|
||||
if (null != currentColumn) {
|
||||
currentValue = Arrays.copyOf(buf, len);
|
||||
if (nest != null) {
|
||||
nest.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
|
||||
} else {
|
||||
conditional.accept(new String(currentColumn), convertTermType(currentTermType), new String(currentValue));
|
||||
}
|
||||
}
|
||||
return conditional.getParam().getTerms();
|
||||
}
|
||||
|
||||
private static String convertTermType(String termType) {
|
||||
if (termType == null) {
|
||||
return TermType.eq;
|
||||
}
|
||||
switch (termType) {
|
||||
case "=":
|
||||
return TermType.eq;
|
||||
case ">":
|
||||
return TermType.gt;
|
||||
case "<":
|
||||
return TermType.lt;
|
||||
case ">=":
|
||||
return TermType.gte;
|
||||
case "<=":
|
||||
return TermType.lte;
|
||||
default:
|
||||
return termType;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.param;
|
||||
|
||||
import org.hswebframework.ezorm.core.dsl.Query;
|
||||
import org.hswebframework.ezorm.core.dsl.Update;
|
||||
import org.hswebframework.ezorm.core.param.UpdateParam;
|
||||
import org.hswebframework.web.commons.entity.Entity;
|
||||
import org.hswebframework.web.commons.entity.QueryEntity;
|
||||
|
||||
/**
|
||||
* 修改参数实体,使用<a href="https://github.com/hs-web/hsweb-easy-orm">easyorm</a>进行动态参数构建
|
||||
*
|
||||
* @author zhouhao
|
||||
* @see UpdateParam
|
||||
* @see Entity
|
||||
* @since 3.0
|
||||
*/
|
||||
public class UpdateParamEntity<T> extends UpdateParam<T> implements QueryEntity {
|
||||
private static final long serialVersionUID = -4074863219482678510L;
|
||||
|
||||
public UpdateParamEntity() {
|
||||
}
|
||||
|
||||
public UpdateParamEntity(T data) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个无任何条件并指定数据的更新参数实体
|
||||
* 创建后需自行指定条件({@link UpdateParamEntity#where(String, Object)})
|
||||
* 否则可能无法执行更新(dao实现应该禁止无条件的更新)
|
||||
*
|
||||
* @param data 要更新的数据
|
||||
* @param <T> 数据泛型
|
||||
* @return 更新参数实体
|
||||
*/
|
||||
public static <T> UpdateParamEntity<T> build(T data) {
|
||||
return new UpdateParamEntity<>(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个单个条件并指定数据的更新参数实体,条件默认为is:
|
||||
* <br>例如:<br>
|
||||
* <code>
|
||||
* // where id = #{id}
|
||||
* <br>
|
||||
* UpdateParamBean.build(data,"id",id);
|
||||
* </code>
|
||||
*
|
||||
* @param data 要更新的数据
|
||||
* @param field 条件名
|
||||
* @param value 条件值
|
||||
* @param <T> 数据泛型
|
||||
* @return 更新参数实体
|
||||
*/
|
||||
public static <T> UpdateParamEntity<T> build(T data, String field, Object value) {
|
||||
return new UpdateParamEntity<>(data).where(field, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.0.4
|
||||
*/
|
||||
public static <T> Update<T, UpdateParamEntity<T>> newUpdate() {
|
||||
return new Update<>(new UpdateParamEntity<>());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toHttpQueryParamString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import lombok.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MenuEntity extends SimpleTreeSortSupportEntity<Integer> {
|
||||
private static final long serialVersionUID = 5548107788893085691L;
|
||||
|
||||
private String name;
|
||||
|
||||
private List<MenuEntity> children;
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.LongAdder;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class TreeSupportEntityTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
MenuEntity parent = MenuEntity.builder().build();
|
||||
parent.setName("menu-1");
|
||||
parent.setId(1);
|
||||
parent.setParentId(-1);
|
||||
|
||||
MenuEntity m101 = MenuEntity.builder().build();
|
||||
m101.setName("menu-101");
|
||||
m101.setId(101);
|
||||
m101.setParentId(1);
|
||||
|
||||
MenuEntity m102 = MenuEntity.builder().build();
|
||||
m102.setName("menu-102");
|
||||
m102.setId(102);
|
||||
m102.setParentId(1);
|
||||
|
||||
MenuEntity m10201 = MenuEntity.builder().build();
|
||||
m10201.setName("menu-10201");
|
||||
m10201.setId(10201);
|
||||
m10201.setParentId(102);
|
||||
|
||||
//list转为树形结构
|
||||
List<MenuEntity> tree = TreeSupportEntity
|
||||
.list2tree(Arrays.asList(parent, m101, m102, m10201), MenuEntity::setChildren, (Predicate<MenuEntity>) menu -> menu.getParentId().equals(-1));
|
||||
|
||||
Assert.assertEquals(tree.get(0).getChildren().get(0).getId(), Integer.valueOf(101));
|
||||
Assert.assertEquals(tree.get(0).getChildren().get(1).getId(), Integer.valueOf(102));
|
||||
|
||||
Assert.assertEquals(tree.get(0).getChildren().get(1).getChildren().get(0).getId(), Integer.valueOf(10201));
|
||||
|
||||
System.out.println(JSON.toJSONString(tree, SerializerFeature.PrettyFormat));
|
||||
|
||||
LongAdder adder=new LongAdder();
|
||||
TreeSupportEntity.forEach(tree,menu->{
|
||||
adder.increment();
|
||||
});
|
||||
Assert.assertEquals(adder.intValue(),4);
|
||||
|
||||
List<MenuEntity> list = new ArrayList<>();
|
||||
|
||||
//将树形结构展平为list
|
||||
TreeSupportEntity.expandTree2List(tree.get(0), list, () -> (int) Math.round(Math.random() * 1000000), MenuEntity::setChildren);
|
||||
|
||||
System.out.println(JSON.toJSONString(list, SerializerFeature.PrettyFormat));
|
||||
|
||||
Assert.assertEquals(list.size(), 4);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class MapperEntityFactoryTests {
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateEntity() {
|
||||
MapperEntityFactory entityFactory = new MapperEntityFactory();
|
||||
|
||||
|
||||
entityFactory.addMapping(TestEntity.class, entityFactory.initCache(NewTestEntity.class));
|
||||
|
||||
TestEntity entity = entityFactory.newInstance(TestEntity.class);
|
||||
|
||||
Assert.assertEquals(entity.getClass(), NewTestEntity.class);
|
||||
|
||||
|
||||
entity = entityFactory.copyProperties(new HashMap<String, Object>() {
|
||||
private static final long serialVersionUID = 6458422824954290386L;
|
||||
|
||||
{
|
||||
put("name", "张三");
|
||||
put("nickName", "小张");
|
||||
}
|
||||
}, entity);
|
||||
|
||||
Assert.assertEquals(entity.getName(), "张三");
|
||||
Assert.assertEquals(((NewTestEntity) entity).getNickName(), "小张");
|
||||
|
||||
|
||||
entityFactory.addCopier(new CustomPropertyCopier());
|
||||
|
||||
HashMap<String, Object> data = new HashMap<>();
|
||||
data.put("name", "李四");
|
||||
data.put("nickName", "小李");
|
||||
entityFactory.copyProperties(data, entity);
|
||||
|
||||
Assert.assertEquals(entity.getName(), "李四");
|
||||
Assert.assertEquals(((NewTestEntity) entity).getNickName(), "小李");
|
||||
|
||||
}
|
||||
|
||||
class CustomPropertyCopier implements PropertyCopier<HashMap, NewTestEntity> {
|
||||
|
||||
@Override
|
||||
public NewTestEntity copyProperties(HashMap source, NewTestEntity target) {
|
||||
target.setName((String) source.get("name"));
|
||||
target.setNickName((String) source.get("nickName"));
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class NewTestEntity extends TestEntity {
|
||||
private static final long serialVersionUID = -8151514416436801617L;
|
||||
private String nickName;
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.factory;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hswebframework.web.commons.entity.SimpleGenericEntity;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
public class TestEntity extends SimpleGenericEntity<String> {
|
||||
private static final long serialVersionUID = 2468328156748007412L;
|
||||
|
||||
private String name;
|
||||
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package org.hswebframework.web.commons.entity.param;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import org.hswebframework.ezorm.core.param.Term;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class TermExpressionParserTest {
|
||||
|
||||
@Test
|
||||
public void testSimple() {
|
||||
String expression = "name=测试 or age=10";
|
||||
List<Term> terms = TermExpressionParser.parse(expression);
|
||||
|
||||
Assert.assertNotNull(terms);
|
||||
Assert.assertEquals(terms.size(), 2);
|
||||
Assert.assertEquals(terms.get(0).getColumn(), "name");
|
||||
Assert.assertEquals(terms.get(0).getValue(), "测试");
|
||||
|
||||
Assert.assertEquals(terms.get(1).getColumn(), "age");
|
||||
Assert.assertEquals(terms.get(1).getValue(), "10");
|
||||
Assert.assertEquals(terms.get(1).getType(), Term.Type.or);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNest() {
|
||||
String expression = "name = 测试 and (age > 10 or age <= 20) and test like test2 and (age gt age2 or age btw age3,age4 or (age > 10 or age <= 20))";
|
||||
System.out.println(expression);
|
||||
List<Term> terms = TermExpressionParser.parse(expression);
|
||||
System.out.println(JSON.toJSONString(terms, SerializerFeature.PrettyFormat));
|
||||
Assert.assertNotNull(terms);
|
||||
Assert.assertEquals(terms.size(), 4);
|
||||
Assert.assertEquals(terms.get(1).getTerms().size(),2);
|
||||
Assert.assertEquals(terms.get(0).getColumn(), "name");
|
||||
Assert.assertEquals(terms.get(0).getValue(), "测试");
|
||||
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(0).getColumn(), "age");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(0).getTermType(), "gt");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(0).getValue(), "10");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getColumn(), "age");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getTermType(), "lte");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getValue(), "20");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getType(), Term.Type.or);
|
||||
|
||||
Assert.assertEquals(terms.get(2).getColumn(), "test");
|
||||
Assert.assertEquals(terms.get(2).getValue(), "test2");
|
||||
Assert.assertEquals(terms.get(2).getTermType(), "like");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试日期字符串空格解析,'2019-07-26 12:00:00'
|
||||
*/
|
||||
@Test
|
||||
public void testDateSpace() {
|
||||
String expression = "(name=测试 or age=10) and (birth btw \"2019-07-26 12:00:00, 2019-08-04 12:00:00\" or startTime <= '2019-08-04 12:00:00') and finishTime >= '2019-08-01 00:00:00'";
|
||||
List<Term> terms = TermExpressionParser.parse(expression);
|
||||
System.out.println(JSON.toJSONString(terms, SerializerFeature.PrettyFormat));
|
||||
|
||||
Assert.assertEquals(terms.size(), 3);
|
||||
Assert.assertEquals(terms.get(0).getTerms().size(), 2);
|
||||
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(0).getColumn(), "birth");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(0).getTermType(), "btw");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(0).getValue(), "2019-07-26 12:00:00, 2019-08-04 12:00:00");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getColumn(), "startTime");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getTermType(), "lte");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getValue(), "2019-08-04 12:00:00");
|
||||
Assert.assertEquals(terms.get(1).getTerms().get(1).getType(), Term.Type.or);
|
||||
|
||||
Assert.assertEquals(terms.get(2).getColumn(), "finishTime");
|
||||
Assert.assertEquals(terms.get(2).getValue(), "2019-08-01 00:00:00");
|
||||
Assert.assertEquals(terms.get(2).getTermType(), "gte");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ /*
|
||||
~ * Copyright 2019 http://www.hswebframework.org
|
||||
~ *
|
||||
~ * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ * you may not use this file except in compliance with the License.
|
||||
~ * You may obtain a copy of the License at
|
||||
~ *
|
||||
~ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
~ *
|
||||
~ * Unless required by applicable law or agreed to in writing, software
|
||||
~ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ * See the License for the specific language governing permissions and
|
||||
~ * limitations under the License.
|
||||
~ */
|
||||
-->
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hsweb-commons</artifactId>
|
||||
<groupId>org.hswebframework.web</groupId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hsweb-commons-utils</artifactId>
|
||||
|
||||
<description>通用模块-工具类</description>
|
||||
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<directory>src/test/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</testResource>
|
||||
</testResources>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.projectreactor</groupId>
|
||||
<artifactId>reactor-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework</groupId>
|
||||
<artifactId>hsweb-expands-script</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>commons-beanutils</groupId>
|
||||
<artifactId>commons-beanutils</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hswebframework</groupId>
|
||||
<artifactId>hsweb-easy-orm-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019 http://www.hswebframework.org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
public final class AopUtils {
|
||||
|
||||
private AopUtils() {
|
||||
}
|
||||
|
||||
public static <T extends Annotation> T findMethodAnnotation(Class targetClass, Method method, Class<T> annClass) {
|
||||
Method m = method;
|
||||
T a = AnnotationUtils.findAnnotation(m, annClass);
|
||||
if (a != null) {
|
||||
return a;
|
||||
}
|
||||
m = ClassUtils.getMostSpecificMethod(m, targetClass);
|
||||
a = AnnotationUtils.findAnnotation(m, annClass);
|
||||
if (a == null) {
|
||||
List<Class> supers = new ArrayList<>(Arrays.asList(targetClass.getInterfaces()));
|
||||
if (targetClass.getSuperclass() != Object.class) {
|
||||
supers.add(targetClass.getSuperclass());
|
||||
}
|
||||
|
||||
for (Class aClass : supers) {
|
||||
if(aClass==null){
|
||||
continue;
|
||||
}
|
||||
Method ims[] = new Method[1];
|
||||
|
||||
ReflectionUtils.doWithMethods(aClass, im -> {
|
||||
if (im.getName().equals(method.getName()) && im.getParameterCount() == method.getParameterCount()) {
|
||||
ims[0] = im;
|
||||
}
|
||||
});
|
||||
|
||||
if (ims[0] != null) {
|
||||
a = findMethodAnnotation(aClass, ims[0], annClass);
|
||||
if (a != null) {
|
||||
return a;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
public static <T extends Annotation> T findAnnotation(Class targetClass, Class<T> annClass) {
|
||||
return AnnotationUtils.findAnnotation(targetClass, annClass);
|
||||
}
|
||||
|
||||
public static <T extends Annotation> T findAnnotation(Class targetClass, Method method, Class<T> annClass) {
|
||||
T a = findMethodAnnotation(targetClass, method, annClass);
|
||||
if (a != null) {
|
||||
return a;
|
||||
}
|
||||
return findAnnotation(targetClass, annClass);
|
||||
}
|
||||
|
||||
public static <T extends Annotation> T findAnnotation(JoinPoint pjp, Class<T> annClass) {
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
Method m = signature.getMethod();
|
||||
Class<?> targetClass = pjp.getTarget().getClass();
|
||||
return findAnnotation(targetClass, m, annClass);
|
||||
}
|
||||
|
||||
public static String getMethodBody(JoinPoint pjp) {
|
||||
StringBuilder methodName = new StringBuilder(pjp.getSignature().getName()).append("(");
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
String[] names = signature.getParameterNames();
|
||||
Class[] args = signature.getParameterTypes();
|
||||
for (int i = 0, len = args.length; i < len; i++) {
|
||||
if (i != 0) {
|
||||
methodName.append(",");
|
||||
}
|
||||
methodName.append(args[i].getSimpleName()).append(" ").append(names[i]);
|
||||
}
|
||||
return methodName.append(")").toString();
|
||||
}
|
||||
|
||||
public static Map<String, Object> getArgsMap(JoinPoint pjp) {
|
||||
MethodSignature signature = (MethodSignature) pjp.getSignature();
|
||||
Map<String, Object> args = new LinkedHashMap<>();
|
||||
String names[] = signature.getParameterNames();
|
||||
for (int i = 0, len = names.length; i < len; i++) {
|
||||
args.put(names[i], pjp.getArgs()[i]);
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 2.0
|
||||
*/
|
||||
@Component
|
||||
public class ApplicationContextHolder implements ApplicationContextAware {
|
||||
private static ApplicationContext context;
|
||||
|
||||
public static ApplicationContext get() {
|
||||
if (null == context) {
|
||||
throw new UnsupportedOperationException("ApplicationContext not ready!");
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
if (null == ApplicationContextHolder.context) {
|
||||
ApplicationContextHolder.context = applicationContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* List工具,用于构建list等操作
|
||||
* <pre>
|
||||
* Lists.buildList("1","2")
|
||||
* .add("3")
|
||||
* .add("4","5","6")
|
||||
* .get();
|
||||
* </pre>
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class Lists {
|
||||
|
||||
public static <V> ListBuilder<V> buildList(Supplier<List<V>> supplier) {
|
||||
return buildList(supplier.get());
|
||||
}
|
||||
|
||||
public static <V> ListBuilder<V> buildList(V... array) {
|
||||
return buildList(array.length == 0 ? new ArrayList<>() : new ArrayList<>(Arrays.asList(array)));
|
||||
}
|
||||
|
||||
public static <V> ListBuilder<V> buildList(List<V> target) {
|
||||
return new ListBuilder<>(target);
|
||||
}
|
||||
|
||||
public static class ListBuilder<V> {
|
||||
private final List<V> target;
|
||||
|
||||
private ListBuilder(List<V> target) {
|
||||
Objects.requireNonNull(target);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public ListBuilder<V> add(V value, V... more) {
|
||||
this.target.add(value);
|
||||
if (more.length > 0) {
|
||||
addAll(Arrays.asList(more));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ListBuilder<V> addAll(Collection<V> value) {
|
||||
this.target.addAll(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public List<V> get() {
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* map工具类,用于构造map等操作
|
||||
* <p>
|
||||
* <pre>
|
||||
* Maps.<String, Object>buildMap()
|
||||
* .put("name", "age")
|
||||
* .put("age", 1)
|
||||
* .get()
|
||||
* </pre>
|
||||
*
|
||||
* @author zhouhao
|
||||
*/
|
||||
public final class Maps {
|
||||
|
||||
private Maps() {
|
||||
}
|
||||
|
||||
public static <K, V> MapBuilder<K, V> buildMap(Map<K, V> target) {
|
||||
return new MapBuilder<>(target);
|
||||
}
|
||||
|
||||
public static <K, V> MapBuilder<K, V> buildMap() {
|
||||
return new MapBuilder<>(new HashMap<K, V>());
|
||||
}
|
||||
|
||||
public static <K, V> MapBuilder<K, V> buildMap(Supplier<Map<K, V>> mapSupplier) {
|
||||
return new MapBuilder<>(mapSupplier.get());
|
||||
}
|
||||
|
||||
public static class MapBuilder<K, V> {
|
||||
final Map<K, V> target;
|
||||
|
||||
private MapBuilder(Map<K, V> target) {
|
||||
Objects.requireNonNull(target);
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public MapBuilder<K, V> put(K key, V value) {
|
||||
this.target.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<K, V> get() {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class RegexUtils {
|
||||
private static Set<Character> SPECIAL_WORDS = new HashSet<>(Arrays.asList('\\', '$', '(', ')', '*', '+', '.', '[', ']', '?', '^', '{', '}', '|'));
|
||||
|
||||
public static String escape(String regex) {
|
||||
if (regex == null || regex.isEmpty()) {
|
||||
return regex;
|
||||
}
|
||||
char[] chars = regex.toCharArray();
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (char aChar : chars) {
|
||||
if (SPECIAL_WORDS.contains(aChar)) {
|
||||
builder.append('\\');
|
||||
}
|
||||
builder.append(aChar);
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
*/
|
||||
public class Sqls {
|
||||
|
||||
public static List<String> parse(String sqlText) {
|
||||
String[] list = sqlText.split("[\n]");
|
||||
List<String> sqlList = new ArrayList<>();
|
||||
List<String> tmp = new ArrayList<>();
|
||||
Stream.of(list)
|
||||
.filter(s -> !s.startsWith("--") && s.trim().length() != 0)
|
||||
.forEach(s1 -> {
|
||||
if (s1.trim().endsWith(";")) {
|
||||
s1 = s1.trim();
|
||||
s1 = s1.substring(0, s1.length() - 1);
|
||||
if (!StringUtils.isEmpty(s1))
|
||||
tmp.add(s1);
|
||||
sqlList.add(String.join("\n", tmp.toArray(new String[0])));
|
||||
tmp.clear();
|
||||
} else {
|
||||
if (!StringUtils.isEmpty(s1))
|
||||
tmp.add(s1);
|
||||
}
|
||||
});
|
||||
if (!tmp.isEmpty()) {
|
||||
sqlList.add(String.join("\n", tmp.toArray(new String[0])));
|
||||
tmp.clear();
|
||||
}
|
||||
return sqlList;
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
/*
|
||||
*
|
||||
* * Copyright 2019 http://www.hswebframework.org
|
||||
* *
|
||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* * you may not use this file except in compliance with the License.
|
||||
* * You may obtain a copy of the License at
|
||||
* *
|
||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
||||
* *
|
||||
* * Unless required by applicable law or agreed to in writing, software
|
||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* * See the License for the specific language governing permissions and
|
||||
* * limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.hswebframework.web;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* ThreadLocal 工具类,通过在ThreadLocal存储map信息,来实现在ThreadLocal中维护多个信息
|
||||
* <br>e.g.<code>
|
||||
* ThreadLocalUtils.put("key",value);<br>
|
||||
* ThreadLocalUtils.get("key");<br>
|
||||
* ThreadLocalUtils.remove("key");<br>
|
||||
* ThreadLocalUtils.getAndRemove("key");<br>
|
||||
* ThreadLocalUtils.get("key",()->defaultValue);<br>
|
||||
* ThreadLocalUtils.clear();<br>
|
||||
* </code>
|
||||
*
|
||||
* @author zhouhao
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final class ThreadLocalUtils {
|
||||
|
||||
private ThreadLocalUtils() {
|
||||
}
|
||||
|
||||
private static final ThreadLocal<Map<String, Object>> local = ThreadLocal.withInitial(HashMap::new);
|
||||
|
||||
/**
|
||||
* @return threadLocal中的全部值
|
||||
*/
|
||||
public static Map<String, Object> getAll() {
|
||||
return new HashMap<>(local.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一个值到ThreadLocal
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
* @param <T> 值的类型
|
||||
* @return 被放入的值
|
||||
* @see Map#put(Object, Object)
|
||||
*/
|
||||
public static <T> T put(String key, T value) {
|
||||
local.get().put(key, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除参数对应的值
|
||||
*
|
||||
* @param key
|
||||
* @see Map#remove(Object)
|
||||
*/
|
||||
public static void remove(String key) {
|
||||
local.get().remove(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空ThreadLocal
|
||||
*
|
||||
* @see Map#clear()
|
||||
*/
|
||||
public static void clear() {
|
||||
local.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ThreadLocal中获取值
|
||||
*
|
||||
* @param key 键
|
||||
* @param <T> 值泛型
|
||||
* @return 值, 不存在则返回null, 如果类型与泛型不一致, 可能抛出{@link ClassCastException}
|
||||
* @see Map#get(Object)
|
||||
* @see ClassCastException
|
||||
*/
|
||||
public static <T> T get(String key) {
|
||||
return ((T) local.get().get(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从ThreadLocal中获取值,并指定一个当值不存在的提供者
|
||||
*
|
||||
* @see Supplier
|
||||
* @since 3.0
|
||||
*/
|
||||
public static <T> T get(String key, Supplier<T> supplierOnNull) {
|
||||
return ((T) local.get().computeIfAbsent(key, k -> supplierOnNull.get()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个值后然后删除掉
|
||||
*
|
||||
* @param key 键
|
||||
* @param <T> 值类型
|
||||
* @return 值, 不存在则返回null
|
||||
* @see this#get(String)
|
||||
* @see this#remove(String)
|
||||
*/
|
||||
public static <T> T getAndRemove(String key) {
|
||||
try {
|
||||
return get(key);
|
||||
} finally {
|
||||
remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package org.hswebframework.web.context;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface Context {
|
||||
|
||||
<T> Optional<T> get(ContextKey<T> key);
|
||||
|
||||
<T> T getOrDefault(ContextKey<T> key,T defaultValue);
|
||||
|
||||
<T> void put(ContextKey<T> key,T value);
|
||||
|
||||
Map<String,Object> getAll();
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package org.hswebframework.web.context;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
@AllArgsConstructor
|
||||
public final class ContextKey<T> {
|
||||
|
||||
@Getter
|
||||
private String key;
|
||||
|
||||
public static <T> ContextKey<T> of(String key) {
|
||||
return new ContextKey<>(key);
|
||||
}
|
||||
|
||||
public static <T> ContextKey<T> of(Class<T> key) {
|
||||
return new ContextKey<>(key.getName());
|
||||
}
|
||||
|
||||
public static ContextKey<String> string(String key) {
|
||||
return of(key);
|
||||
}
|
||||
|
||||
public static ContextKey<Integer> integer(String key) {
|
||||
return of(key);
|
||||
}
|
||||
|
||||
public static ContextKey<Boolean> bool(String key) {
|
||||
return of(key);
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
package org.hswebframework.web.context;
|
||||
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public class ContextUtils {
|
||||
|
||||
|
||||
public static Mono<Context> currentContext() {
|
||||
return Mono.subscriberContext()
|
||||
.<Context>handle((context, sink) -> {
|
||||
if (context.hasKey(Context.class)) {
|
||||
sink.next(context.get(Context.class));
|
||||
}
|
||||
})
|
||||
.subscriberContext(acceptContext(ctx->{
|
||||
|
||||
}));
|
||||
}
|
||||
|
||||
public static Function<reactor.util.context.Context, reactor.util.context.Context> acceptContext(Consumer<Context> contextConsumer) {
|
||||
return context -> {
|
||||
if (!context.hasKey(Context.class)) {
|
||||
context = context.put(Context.class, new MapContext());
|
||||
}
|
||||
contextConsumer.accept(context.get(Context.class));
|
||||
return context;
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.hswebframework.web.context;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@SuppressWarnings("all")
|
||||
class MapContext implements Context {
|
||||
|
||||
private Map<String, Object> map = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public <T> Optional<T> get(ContextKey<T> key) {
|
||||
return Optional.ofNullable(map.get(key.getKey()))
|
||||
.map(v -> ((T) v));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getOrDefault(ContextKey<T> key, T defaultValue) {
|
||||
return (T) map.computeIfAbsent(key.getKey(), __ -> defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void put(ContextKey<T> key, T value) {
|
||||
map.put(key.getKey(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getAll() {
|
||||
return new HashMap<>(map);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ExpressionUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testAnalytical() throws Exception {
|
||||
String result = ExpressionUtils.analytical("test${1+2} ${''} ${1+4+5}", "spel");
|
||||
|
||||
Assert.assertEquals(result, "test3 10");
|
||||
|
||||
result = ExpressionUtils.analytical("test${#param}", Collections.singletonMap("param", "3"), "spel");
|
||||
Assert.assertEquals(result, "test3");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SneakyThrows
|
||||
public void benchmark() {
|
||||
|
||||
String expression = "test${1+2} ${1+4+5}";
|
||||
|
||||
ExpressionUtils.analytical(expression, Collections.emptyMap(), "spel");
|
||||
|
||||
long time = System.currentTimeMillis();
|
||||
for (int i = 0; i < 100000; i++) {
|
||||
ExpressionUtils.analytical(expression, Collections.emptyMap(), "spel");
|
||||
}
|
||||
|
||||
System.out.println(System.currentTimeMillis() - time);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.hswebframework.ezorm.core.dsl.Query;
|
||||
import org.hswebframework.ezorm.core.param.QueryParam;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class HttpParameterConverterTests {
|
||||
|
||||
@Test
|
||||
public void testConvertMap() {
|
||||
Map<String, Object> target = new HashMap<>();
|
||||
|
||||
Map<String, Object> info = new HashMap<>();
|
||||
info.put("nickName", "小宋");
|
||||
info.put("address", "重庆");
|
||||
|
||||
|
||||
Map<String, Object> loginInfo = new HashMap<>();
|
||||
loginInfo.put("lastLoginIp", "127.0.0.1");
|
||||
loginInfo.put("lastLoginTime", new Date());
|
||||
loginInfo.put("lastLoginIp5Times", Arrays.asList("127.0.0.1", "localhost"));
|
||||
|
||||
info.put("loginInfo", loginInfo);
|
||||
|
||||
target.put("name", "admin");
|
||||
target.put("age", 30);
|
||||
target.put("money", new BigDecimal("1000000.00"));
|
||||
target.put("createDate", new Date());
|
||||
target.put("roles", Arrays.asList(1, 2, 3));
|
||||
target.put("info", info);
|
||||
|
||||
HttpParameterConverter converter = new HttpParameterConverter(target);
|
||||
|
||||
Map<String, String> result = converter.convert();
|
||||
|
||||
System.out.println(result);
|
||||
|
||||
Assert.assertEquals(result.get("roles[0]"), "1");
|
||||
Assert.assertEquals(result.get("roles[1]"), "2");
|
||||
Assert.assertEquals(result.get("roles[2]"), "3");
|
||||
Assert.assertEquals(result.get("name"), "admin");
|
||||
Assert.assertEquals(result.get("info.nickName"), "小宋");
|
||||
Assert.assertEquals(result.get("info.address"), "重庆");
|
||||
|
||||
Assert.assertEquals(result.get("info.loginInfo.lastLoginIp"), "127.0.0.1");
|
||||
Assert.assertEquals(result.get("info.loginInfo.lastLoginIp5Times[0]"), "127.0.0.1");
|
||||
Assert.assertEquals(result.get("info.loginInfo.lastLoginIp5Times[1]"), "localhost");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConvertObject() {
|
||||
QueryParam param = Query.of(new QueryParam())
|
||||
.where("name", "张三")
|
||||
.and().like("address", "%重庆%")
|
||||
.nest()
|
||||
.lt("age", 18)
|
||||
.or()
|
||||
.gt("age", 60)
|
||||
.end()
|
||||
.getParam();
|
||||
|
||||
HttpParameterConverter converter = new HttpParameterConverter(param);
|
||||
|
||||
Map<String, String> result = converter.convert();
|
||||
|
||||
System.out.println(result);
|
||||
|
||||
Assert.assertEquals(result.get("terms[0].column"), "name");
|
||||
Assert.assertEquals(result.get("terms[0].value"), "张三");
|
||||
|
||||
Assert.assertEquals(result.get("terms[1].termType"), "like");
|
||||
Assert.assertEquals(result.get("terms[1].value"), "%重庆%");
|
||||
|
||||
Assert.assertEquals(result.get("terms[2].terms[0].termType"), "lt");
|
||||
Assert.assertEquals(result.get("terms[2].terms[0].value"), "18");
|
||||
|
||||
Assert.assertEquals(result.get("terms[1].value"), "%重庆%");
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedList;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ListsTests {
|
||||
|
||||
@Test
|
||||
public void testCreate() {
|
||||
|
||||
assertEquals(Lists.buildList(2).add(1)
|
||||
.get().get(0), (Integer) 2);
|
||||
|
||||
|
||||
assertEquals(Lists.buildList(new ArrayList<>()).add(2,1)
|
||||
.get().get(0), 2);
|
||||
|
||||
assertEquals(Lists.buildList(ArrayList::new)
|
||||
.add(2,1)
|
||||
.get()
|
||||
.get(0), 2);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class MapsTests {
|
||||
|
||||
@Test
|
||||
public void testCreateMap() {
|
||||
assertEquals(Maps.buildMap()
|
||||
.put("1", 1)
|
||||
.get().get("1"), 1);
|
||||
|
||||
assertEquals(Maps.buildMap(new HashMap<>())
|
||||
.put("1", 1)
|
||||
.get().get("1"), 1);
|
||||
|
||||
assertEquals(Maps.buildMap(HashMap::new)
|
||||
.put("1", 1)
|
||||
.get().get("1"), 1);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
|
||||
/**
|
||||
* @author zhouhao
|
||||
* @since 3.0.6
|
||||
*/
|
||||
public class ModuleUtilsTest {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
ModuleUtils.ModuleInfo moduleInfo = ModuleUtils.getModuleByClass(ModuleUtilsTest.class);
|
||||
Assert.assertNotNull(moduleInfo);
|
||||
Assert.assertFalse(moduleInfo.isNone());
|
||||
Assert.assertEquals(moduleInfo.getArtifactId(),"hsweb-commons-utils");
|
||||
System.out.println(moduleInfo.getGitLocation());
|
||||
System.out.println(moduleInfo.getGitClassLocation(Maps.class,10,12));
|
||||
ModuleUtils.ModuleInfo noneInfo = ModuleUtils.getModuleByClass(Logger.class);
|
||||
Assert.assertNotNull(noneInfo);
|
||||
Assert.assertTrue(noneInfo.isNone());
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class RegexUtilsTests {
|
||||
|
||||
@Test
|
||||
public void test() {
|
||||
Arrays.asList('\\', '$', '(', ')', '*', '+', '.', '[', ']', '?', '^', '{', '}', '|')
|
||||
.forEach((s) -> assertEquals(RegexUtils.escape(String.valueOf(s)), "\\" + s));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class SqlsTests {
|
||||
|
||||
@Test
|
||||
public void testParse() {
|
||||
String sql = "select 1;\ndelete from user;";
|
||||
|
||||
List<String> strings = Sqls.parse(sql);
|
||||
System.out.println(strings);
|
||||
Assert.assertTrue(strings.size() == 2);
|
||||
|
||||
Assert.assertTrue("select 1".equals(strings.get(0)));
|
||||
Assert.assertTrue("delete from user".equals(strings.get(1)));
|
||||
|
||||
|
||||
sql = "select 1;\ndelete from user;\nselect * from user \nwhere name = 1 \n or name =2";
|
||||
|
||||
strings = Sqls.parse(sql);
|
||||
System.out.println(strings);
|
||||
Assert.assertTrue(strings.size() == 3);
|
||||
Assert.assertEquals(strings.get(2),"select * from user \nwhere name = 1 \n or name =2");
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ThreadLocalUtilsTests {
|
||||
|
||||
@Test
|
||||
public void testAll() {
|
||||
ThreadLocalUtils.put("test", "1");
|
||||
|
||||
Assert.assertEquals(ThreadLocalUtils.get("test"), "1");
|
||||
|
||||
ThreadLocalUtils.get("test2", () -> "2");
|
||||
|
||||
Assert.assertEquals(ThreadLocalUtils.get("test2"), "2");
|
||||
|
||||
Assert.assertEquals(ThreadLocalUtils.getAndRemove("test2"), "2");
|
||||
|
||||
Assert.assertTrue(ThreadLocalUtils.get("test2") == null);
|
||||
|
||||
ThreadLocalUtils.remove("test");
|
||||
|
||||
Assert.assertTrue(ThreadLocalUtils.get("test") == null);
|
||||
|
||||
ThreadLocalUtils.put("test", "1");
|
||||
ThreadLocalUtils.put("test2", "2");
|
||||
|
||||
Assert.assertTrue(ThreadLocalUtils.getAll().size()==2);
|
||||
ThreadLocalUtils.clear();
|
||||
|
||||
Assert.assertTrue(ThreadLocalUtils.getAll().size()==0);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package org.hswebframework.web;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Map;
|
||||
|
||||
public class WebUtilTest {
|
||||
|
||||
@Test
|
||||
public void queryStringToMap() throws UnsupportedEncodingException {
|
||||
String parameter = "key1=value1&key2=value2&key3=&key4=key5=1";
|
||||
Map<String, String> map = WebUtil.queryStringToMap(parameter, "utf-8");
|
||||
System.out.println(map);
|
||||
Assert.assertEquals(map.get("key1"), "value1");
|
||||
Assert.assertEquals(map.get("key2"), "value2");
|
||||
Assert.assertEquals(map.get("key3"), "");
|
||||
Assert.assertEquals(map.get("key4"), "key5=1");
|
||||
|
||||
parameter = "key1=%e5%80%bc1&key2=%e5%80%bc2";
|
||||
map = WebUtil.queryStringToMap(parameter, "utf-8");
|
||||
System.out.println(map);
|
||||
Assert.assertEquals(map.get("key1"), "值1");
|
||||
Assert.assertEquals(map.get("key2"), "值2");
|
||||
|
||||
parameter = "key1=%D6%B51&key2=%D6%B52";
|
||||
map = WebUtil.queryStringToMap(parameter, "gbk");
|
||||
System.out.println(map);
|
||||
Assert.assertEquals(map.get("key1"), "值1");
|
||||
Assert.assertEquals(map.get("key2"), "值2");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"groupId": "${project.groupId}",
|
||||
"artifactId": "${project.artifactId}",
|
||||
"path": "hsweb-commons/hsweb-commons-utils",
|
||||
|
||||
"gitCommitHash": "${git.commit.hash}",
|
||||
"gitRepository": "http://github.com/hs-web/hsweb-framework",
|
||||
"version": "${project.version}"
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="http://www.padual.com/java/logback.xsd"
|
||||
debug="false" scan="true" scanPeriod="30 second">
|
||||
<root level="warn">
|
||||
|
||||
</root>
|
||||
</configuration>
|
||||
@@ -32,13 +32,6 @@
|
||||
<artifactId>hsweb-commons</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<modules>
|
||||
<module>hsweb-commons-entity</module>
|
||||
<module>hsweb-commons-dao</module>
|
||||
<module>hsweb-commons-service</module>
|
||||
<module>hsweb-commons-controller</module>
|
||||
<module>hsweb-commons-utils</module>
|
||||
<module>hsweb-commons-model</module>
|
||||
<module>hsweb-commons-bean</module>
|
||||
<module>hsweb-commons-crud</module>
|
||||
</modules>
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.hswebframework.web;
|
||||
package org.hswebframework.web.utils;
|
||||
|
||||
import org.hswebframework.expands.script.engine.DynamicScriptEngine;
|
||||
import org.hswebframework.expands.script.engine.DynamicScriptEngineFactory;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.hswebframework.web;
|
||||
package org.hswebframework.web.utils;
|
||||
|
||||
import org.apache.commons.beanutils.BeanMap;
|
||||
import org.hswebframework.utils.time.DateFormatter;
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.hswebframework.web;
|
||||
package org.hswebframework.web.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user