初始提交通用Mapper+注解关联(注解实现关联: 元数据/字段/一对一的表/一对多的表)
This commit is contained in:
parent
6d9c601c33
commit
732adc9d69
32
build.gradle
32
build.gradle
|
@ -1,6 +1,6 @@
|
|||
buildscript {
|
||||
ext {
|
||||
springBootVersion = '2.1.2.RELEASE'
|
||||
springBootVersion = '2.1.3.RELEASE'
|
||||
}
|
||||
repositories {
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
|
@ -9,30 +9,30 @@ buildscript {
|
|||
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
// 全局配置
|
||||
allprojects {
|
||||
group 'com.diboot'
|
||||
version '2.0-alpha'
|
||||
|
||||
apply plugin: 'idea'
|
||||
}
|
||||
|
||||
repositories {
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
}
|
||||
|
||||
// 子项目的配置
|
||||
subprojects {
|
||||
apply plugin: 'java'
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
targetCompatibility = 1.8
|
||||
|
||||
[compileJava,compileTestJava,javadoc]*.options*.encoding = 'UTF-8'
|
||||
repositories {
|
||||
jcenter()
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
}
|
||||
ext {//依赖版本
|
||||
springBootVersion = "2.1.2.RELEASE"
|
||||
mysqlConnectorVersion = "8.0.13"
|
||||
mybatisStarterVersion = "1.3.2"
|
||||
mybatisPlusVersion = "3.0.7.1"
|
||||
fastjsonVersion = "1.2.54"
|
||||
lombokVersion = "1.18.4"
|
||||
springBootVersion = "2.1.4.RELEASE"
|
||||
mysqlConnectorVersion = "8.0.15"
|
||||
mybatisStarterVersion = "2.0.1"
|
||||
mybatisPlusVersion = "3.1.0"
|
||||
fastjsonVersion = "1.2.57"
|
||||
lombokVersion = "1.18.6"
|
||||
}
|
||||
dependencies {
|
||||
compileOnly("org.projectlombok:lombok:$lombokVersion")
|
||||
|
@ -50,7 +50,7 @@ subprojects {
|
|||
compile("com.alibaba:fastjson:$fastjsonVersion")
|
||||
// Apache Commons
|
||||
compile("org.apache.commons:commons-lang3:3.8.1")
|
||||
|
||||
|
||||
// 测试实现
|
||||
testCompile("org.springframework.boot:spring-boot-starter-test:$springBootVersion")
|
||||
testCompile("junit:junit:4.12")
|
||||
|
|
|
@ -1,13 +1,3 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
maven{ url 'http://maven.aliyun.com/nexus/content/groups/public/'}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
||||
|
|
|
@ -0,0 +1,144 @@
|
|||
package com.diboot.core.binding;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.binding.parser.MiddleTable;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.IGetter;
|
||||
import com.diboot.core.util.S;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关系绑定Binder父类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
public abstract class BaseBinder<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseBinder.class);
|
||||
/***
|
||||
* 需要绑定到的VO注解对象List
|
||||
*/
|
||||
protected List annoObjectList;
|
||||
/***
|
||||
* VO注解对象中的外键属性
|
||||
*/
|
||||
protected String annoObjectForeignKey;
|
||||
/**
|
||||
* 被关联对象的Service实例
|
||||
*/
|
||||
protected BaseService<T> referencedService;
|
||||
/***
|
||||
* DO对象中的主键属性名
|
||||
*/
|
||||
protected String referencedEntityPrimaryKey;
|
||||
/**
|
||||
* 初始化QueryWrapper
|
||||
*/
|
||||
protected QueryWrapper queryWrapper;
|
||||
|
||||
/**
|
||||
* 多对多关联的桥接表,如 user_role<br>
|
||||
* 多对多注解示例: id=user_role.user_id AND user_role.role_id=id
|
||||
*/
|
||||
protected MiddleTable middleTable;
|
||||
|
||||
/**
|
||||
* join连接条件,指定当前VO的取值方法和关联entity的取值方法
|
||||
* @param annoObjectFkGetter 当前VO的取值方法
|
||||
* @param referencedEntityPkGetter 关联entity的取值方法
|
||||
* @param <T1> 当前VO的对象类型
|
||||
* @param <T2> 关联对象entity类型
|
||||
* @return
|
||||
*/
|
||||
public <T1,T2> BaseBinder<T> joinOn(IGetter<T1> annoObjectFkGetter, IGetter<T2> referencedEntityPkGetter){
|
||||
return joinOn(BeanUtils.convertToFieldName(annoObjectFkGetter), BeanUtils.convertToFieldName(referencedEntityPkGetter));
|
||||
}
|
||||
|
||||
/**
|
||||
* join连接条件,指定当前VO的取值方法和关联entity的取值方法
|
||||
* @param annoObjectForeignKey 当前VO的取值属性名
|
||||
* @param referencedEntityPrimaryKey 关联entity的属性
|
||||
* @return
|
||||
*/
|
||||
public BaseBinder<T> joinOn(String annoObjectForeignKey, String referencedEntityPrimaryKey){
|
||||
this.annoObjectForeignKey = S.toLowerCaseCamel(annoObjectForeignKey);
|
||||
this.referencedEntityPrimaryKey = S.toLowerCaseCamel(referencedEntityPrimaryKey);
|
||||
return this;
|
||||
}
|
||||
|
||||
public BaseBinder<T> andEQ(String fieldName, Object value){
|
||||
queryWrapper.eq(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andNE(String fieldName, Object value){
|
||||
queryWrapper.ne(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andGT(String fieldName, Object value){
|
||||
queryWrapper.gt(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andGE(String fieldName, Object value){
|
||||
queryWrapper.ge(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andLT(String fieldName, Object value){
|
||||
queryWrapper.lt(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andLE(String fieldName, Object value){
|
||||
queryWrapper.le(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andIsNotNull(String fieldName){
|
||||
queryWrapper.isNotNull(S.toSnakeCase(fieldName));
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andIsNull(String fieldName){
|
||||
queryWrapper.isNull(S.toSnakeCase(fieldName));
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andBetween(String fieldName, Object begin, Object end){
|
||||
queryWrapper.between(S.toSnakeCase(fieldName), begin, end);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andLike(String fieldName, String value){
|
||||
queryWrapper.like(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andIn(String fieldName, Collection valueList){
|
||||
queryWrapper.in(S.toSnakeCase(fieldName), valueList);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andNotIn(String fieldName, Collection valueList){
|
||||
queryWrapper.notIn(S.toSnakeCase(fieldName), valueList);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andNotBetween(String fieldName, Object begin, Object end){
|
||||
queryWrapper.notBetween(S.toSnakeCase(fieldName), begin, end);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andNotLike(String fieldName, String value){
|
||||
queryWrapper.notLike(S.toSnakeCase(fieldName), value);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> andApply(String applySql){
|
||||
queryWrapper.apply(applySql);
|
||||
return this;
|
||||
}
|
||||
public BaseBinder<T> withMiddleTable(MiddleTable middleTable){
|
||||
this.middleTable = middleTable;
|
||||
return this;
|
||||
}
|
||||
|
||||
/***
|
||||
* 执行绑定, 交由子类实现
|
||||
*/
|
||||
public abstract void bind();
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package com.diboot.core.binding;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.ISetter;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Entity实体绑定Binder,用于绑定当前一个entity到目标对象的属性
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
public class EntityBinder<T> extends BaseBinder<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(EntityBinder.class);
|
||||
|
||||
/***
|
||||
* 给待绑定list中VO对象赋值的setter属性名
|
||||
*/
|
||||
protected String annoObjectField;
|
||||
|
||||
public EntityBinder(){}
|
||||
/***
|
||||
* 构造方法
|
||||
* @param referencedService
|
||||
* @param voList
|
||||
*/
|
||||
public EntityBinder(BaseService<T> referencedService, List voList){
|
||||
this.referencedService = referencedService;
|
||||
this.annoObjectList = voList;
|
||||
this.queryWrapper = new QueryWrapper<T>();
|
||||
}
|
||||
|
||||
/***
|
||||
* 指定VO绑定属性赋值的setter方法
|
||||
* @param voSetter VO中调用赋值的setter方法
|
||||
* @param <T1> VO类型
|
||||
* @param <R> set方法参数类型
|
||||
* @return
|
||||
*/
|
||||
public <T1,R> BaseBinder<T> set(ISetter<T1, R> voSetter){
|
||||
return set(BeanUtils.convertToFieldName(voSetter));
|
||||
}
|
||||
|
||||
/***
|
||||
* 指定VO绑定属性赋值的set属性
|
||||
* @param annoObjectField VO中调用赋值的setter属性
|
||||
* @return
|
||||
*/
|
||||
public BaseBinder<T> set(String annoObjectField){
|
||||
this.annoObjectField = annoObjectField;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind() {
|
||||
if(V.isEmpty(annoObjectList)){
|
||||
return;
|
||||
}
|
||||
if(referencedEntityPrimaryKey == null){
|
||||
log.warn("调用错误:必须调用joinOn()方法连接两个字段.");
|
||||
}
|
||||
// 提取主键pk列表
|
||||
List pkList = BeanUtils.collectToList(annoObjectList, S.toLowerCaseCamel(annoObjectForeignKey));
|
||||
if(V.isEmpty(pkList)){
|
||||
return;
|
||||
}
|
||||
// 构建查询条件
|
||||
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), pkList);
|
||||
// 查询entity列表
|
||||
List<T> list = referencedService.getEntityList(queryWrapper);
|
||||
// 绑定结果
|
||||
bindingResult(S.toLowerCaseCamel(referencedEntityPrimaryKey), list);
|
||||
}
|
||||
|
||||
/***
|
||||
* 绑定结果
|
||||
* @param doPkPropName
|
||||
* @param list
|
||||
*/
|
||||
protected void bindingResult(String doPkPropName, List<T> list) {
|
||||
Map<Object, T> valueEntityMap = new HashMap<>(list.size());
|
||||
for(T entity : list){
|
||||
Object pkValue = BeanUtils.getProperty(entity, doPkPropName);
|
||||
valueEntityMap.put(pkValue, entity);
|
||||
}
|
||||
// 绑定
|
||||
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityMap);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.diboot.core.binding;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
public class EntityListBinder<T> extends EntityBinder<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(EntityListBinder.class);
|
||||
|
||||
/***
|
||||
* 构造方法
|
||||
* @param serviceInstance
|
||||
* @param voList
|
||||
*/
|
||||
public EntityListBinder(BaseService<T> serviceInstance, List voList){
|
||||
this.referencedService = serviceInstance;
|
||||
this.annoObjectList = voList;
|
||||
this.queryWrapper = new QueryWrapper<T>();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void bindingResult(String fkName, List<T> list) {
|
||||
Map<Object, List<T>> valueEntityListMap = new HashMap<>(list.size());
|
||||
for(T entity : list){
|
||||
Object keyValue = BeanUtils.getProperty(entity, fkName);
|
||||
List<T> entityList = valueEntityListMap.get(keyValue);
|
||||
if(entityList == null){
|
||||
entityList = new ArrayList<>();
|
||||
valueEntityListMap.put(keyValue, entityList);
|
||||
}
|
||||
entityList.add(entity);
|
||||
}
|
||||
// 绑定
|
||||
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityListMap);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package com.diboot.core.binding;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 关联字段绑定
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
public class FieldBinder<T> extends BaseBinder<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(FieldBinder.class);
|
||||
|
||||
/**
|
||||
* VO对象绑定赋值的属性名列表
|
||||
*/
|
||||
private List<String> annoObjectSetterPropNameList;
|
||||
/**
|
||||
* DO/Entity对象对应的getter取值属性名列表
|
||||
*/
|
||||
private List<String> referencedGetterColumnNameList;
|
||||
|
||||
/***
|
||||
* 构造方法
|
||||
* @param serviceInstance
|
||||
* @param voList
|
||||
*/
|
||||
public FieldBinder(BaseService<T> serviceInstance, List voList){
|
||||
this.referencedService = serviceInstance;
|
||||
this.annoObjectList = voList;
|
||||
this.queryWrapper = new QueryWrapper<T>();
|
||||
}
|
||||
|
||||
/***
|
||||
* 指定VO绑定属性赋值的setter和DO/Entity取值的getter方法
|
||||
* @param toVoSetter VO中调用赋值的setter方法
|
||||
* @param <T1> VO类型
|
||||
* @param <T2> DO类型
|
||||
* @param <R> set方法参数类型
|
||||
* @return
|
||||
*/
|
||||
public <T1,T2,R> FieldBinder<T> link(IGetter<T2> fromDoGetter, ISetter<T1, R> toVoSetter){
|
||||
return link(BeanUtils.convertToFieldName(fromDoGetter), BeanUtils.convertToFieldName(toVoSetter));
|
||||
}
|
||||
|
||||
/***
|
||||
* 指定VO绑定赋值的setter属性名和DO/Entity取值的getter属性名
|
||||
* @param toVoField VO中调用赋值的setter属性名
|
||||
* @return
|
||||
*/
|
||||
public FieldBinder<T> link(String fromDoField, String toVoField){
|
||||
if(annoObjectSetterPropNameList == null){
|
||||
annoObjectSetterPropNameList = new ArrayList<>();
|
||||
}
|
||||
annoObjectSetterPropNameList.add(toVoField);
|
||||
if(referencedGetterColumnNameList == null){
|
||||
referencedGetterColumnNameList = new ArrayList<>();
|
||||
}
|
||||
referencedGetterColumnNameList.add(S.toSnakeCase(fromDoField));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind() {
|
||||
if(V.isEmpty(annoObjectList)){
|
||||
return;
|
||||
}
|
||||
if(referencedGetterColumnNameList == null){
|
||||
log.error("调用错误:字段绑定必须调用link()指定字段赋值和取值的setter/getter方法!");
|
||||
return;
|
||||
}
|
||||
// 解析默认主键字段名
|
||||
String referencedEntityPkName = S.toSnakeCase(referencedEntityPrimaryKey);
|
||||
String annoObjectFkFieldName = S.toLowerCaseCamel(annoObjectForeignKey);
|
||||
// 提取主键pk列表
|
||||
List pkList = BeanUtils.collectToList(annoObjectList, annoObjectFkFieldName);
|
||||
// 构建查询条件
|
||||
List<String> selectColumns = new ArrayList<>(referencedGetterColumnNameList.size()+1);
|
||||
selectColumns.add(referencedEntityPkName);
|
||||
selectColumns.addAll(referencedGetterColumnNameList);
|
||||
queryWrapper.select(S.toStringArray(selectColumns)).in(referencedEntityPkName, pkList);
|
||||
// 获取匹配结果的mapList
|
||||
List<Map<String, Object>> mapList = referencedService.getMapList(queryWrapper);
|
||||
if(V.isEmpty(mapList)){
|
||||
return;
|
||||
}
|
||||
// 将结果list转换成map
|
||||
Map<Object, Map<String, Object>> referencedEntityPk2DataMap = new HashMap<>(mapList.size());
|
||||
for(Map<String, Object> map : mapList){
|
||||
if(map.get(referencedEntityPkName) != null){
|
||||
Object pkVal = map.get(referencedEntityPkName);
|
||||
// 将数字类型转换成字符串,以便解决类型不一致的问题
|
||||
Object formatPkVal = getFormatKey(pkVal);
|
||||
referencedEntityPk2DataMap.put(formatPkVal, map);
|
||||
}
|
||||
}
|
||||
// 遍历list并赋值
|
||||
for(Object annoObject : annoObjectList){
|
||||
Object annoObjectId = BeanUtils.getProperty(annoObject, annoObjectFkFieldName);
|
||||
// 将数字类型转换成字符串,以便解决类型不一致的问题
|
||||
Object formatAnnoObjectId = getFormatKey(annoObjectId);
|
||||
Map<String, Object> relationMap = referencedEntityPk2DataMap.get(formatAnnoObjectId);
|
||||
if(relationMap != null){
|
||||
for(int i = 0; i< annoObjectSetterPropNameList.size(); i++){
|
||||
BeanUtils.setProperty(annoObject, annoObjectSetterPropNameList.get(i), relationMap.get(referencedGetterColumnNameList.get(i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取统一定义的key(避免Mybatis自动转换BigInteger和Long的差异问题)
|
||||
*/
|
||||
private Object getFormatKey(Object annoObjectId){
|
||||
if(annoObjectId instanceof BigInteger || annoObjectId instanceof Long || annoObjectId instanceof Integer) {
|
||||
return String.valueOf(annoObjectId);
|
||||
}
|
||||
return annoObjectId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.diboot.core.binding.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 绑定Entity 注解定义
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/21
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface BindEntity {
|
||||
/***
|
||||
* 对应的service类
|
||||
* @return
|
||||
*/
|
||||
Class entity();
|
||||
|
||||
/***
|
||||
* JOIN连接条件
|
||||
* @return
|
||||
*/
|
||||
String condition();
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package com.diboot.core.binding.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/21
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface BindEntityList {
|
||||
/***
|
||||
* 对应的entity类
|
||||
* @return
|
||||
*/
|
||||
Class entity();
|
||||
|
||||
/***
|
||||
* JOIN连接条件
|
||||
* @return
|
||||
*/
|
||||
String condition();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.diboot.core.binding.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/21
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface BindField {
|
||||
/***
|
||||
* 绑定的Entity类
|
||||
* @return
|
||||
*/
|
||||
Class entity();
|
||||
|
||||
/***
|
||||
* 绑定字段
|
||||
* @return
|
||||
*/
|
||||
String field();
|
||||
|
||||
/***
|
||||
* JOIN连接条件
|
||||
* @return
|
||||
*/
|
||||
String condition();
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.diboot.core.binding.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/21
|
||||
*/
|
||||
@Target({ElementType.FIELD})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface BindMetadata {
|
||||
|
||||
/***
|
||||
* 绑定元数据类型
|
||||
* @return
|
||||
*/
|
||||
String type();
|
||||
|
||||
/***
|
||||
* 元数据项取值字段
|
||||
* @return
|
||||
*/
|
||||
String field();
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
package com.diboot.core.binding.manager;
|
||||
|
||||
import com.diboot.core.binding.BaseBinder;
|
||||
import com.diboot.core.binding.FieldBinder;
|
||||
import com.diboot.core.binding.annotation.BindEntity;
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.core.binding.annotation.BindField;
|
||||
import com.diboot.core.binding.annotation.BindMetadata;
|
||||
import com.diboot.core.binding.parser.BindAnnotationGroup;
|
||||
import com.diboot.core.binding.parser.ConditionManager;
|
||||
import com.diboot.core.binding.parser.FieldAnnotation;
|
||||
import com.diboot.core.entity.Metadata;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.service.MetadataService;
|
||||
import com.diboot.core.util.ContextHelper;
|
||||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 绑定管理器
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/3/30
|
||||
*/
|
||||
public class AnnotationBindingManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(AnnotationBindingManager.class);
|
||||
|
||||
/**
|
||||
* 自动绑定关联对象
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <VO> void autoBind(List<VO> voList){
|
||||
if(V.isEmpty(voList)){
|
||||
return;
|
||||
}
|
||||
// 获取VO类
|
||||
Class voClass = voList.get(0).getClass();
|
||||
BindAnnotationGroup bindAnnotationGroup = BindAnnotationCacheManager.getBindAnnotationGroup(voClass);
|
||||
if(bindAnnotationGroup.isNotEmpty()){
|
||||
// 绑定元数据
|
||||
List<FieldAnnotation> metadataAnnoList = bindAnnotationGroup.getBindMetadataAnnotations();
|
||||
if(metadataAnnoList != null){
|
||||
for(FieldAnnotation annotation : metadataAnnoList){
|
||||
doBindingMetadata(voList, annotation);
|
||||
}
|
||||
}
|
||||
// 绑定Field字段名
|
||||
List<FieldAnnotation> fieldAnnoList = bindAnnotationGroup.getBindFieldAnnotations();
|
||||
if(fieldAnnoList != null){
|
||||
doBindingField(voList, fieldAnnoList);
|
||||
}
|
||||
// 绑定Entity实体
|
||||
List<FieldAnnotation> entityAnnoList = bindAnnotationGroup.getBindEntityAnnotations();
|
||||
if(entityAnnoList != null){
|
||||
for(FieldAnnotation anno : entityAnnoList){
|
||||
doBindingEntity(voList, anno);
|
||||
}
|
||||
}
|
||||
// 绑定Entity实体List
|
||||
List<FieldAnnotation> entitiesAnnoList = bindAnnotationGroup.getBindEntityListAnnotations();
|
||||
if(entitiesAnnoList != null){
|
||||
for(FieldAnnotation anno : entitiesAnnoList){
|
||||
doBindingEntityList(voList, anno);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 绑定元数据
|
||||
* @param voList
|
||||
* @param fieldAnno
|
||||
* @param <VO>
|
||||
*/
|
||||
private static <VO> void doBindingMetadata(List<VO> voList, FieldAnnotation fieldAnno) {
|
||||
MetadataService metadataService = (MetadataService) ContextHelper.getBean(MetadataService.class);
|
||||
if(metadataService != null){
|
||||
BindMetadata annotation = (BindMetadata) fieldAnno.getAnnotation();
|
||||
metadataService.bindItemLabel(voList, fieldAnno.getFieldName(), annotation.field(), annotation.type());
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 绑定字段
|
||||
* @param voList
|
||||
* @param fieldAnnoList
|
||||
* @param <VO>
|
||||
*/
|
||||
private static <VO> void doBindingField(List<VO> voList, List<FieldAnnotation> fieldAnnoList) {
|
||||
//多个字段,合并查询,以减少SQL数
|
||||
Map<String, List<FieldAnnotation>> clazzToListMap = new HashMap<>();
|
||||
for(FieldAnnotation anno : fieldAnnoList){
|
||||
BindField bindField = (BindField) anno.getAnnotation();
|
||||
String key = bindField.entity().getName() + ":" + bindField.condition();
|
||||
List<FieldAnnotation> list = clazzToListMap.computeIfAbsent(key, k -> new ArrayList<>());
|
||||
list.add(anno);
|
||||
}
|
||||
// 解析条件并且执行绑定
|
||||
for(Map.Entry<String, List<FieldAnnotation>> entry : clazzToListMap.entrySet()){
|
||||
List<FieldAnnotation> list = entry.getValue();
|
||||
BindField bindAnnotation = (BindField) list.get(0).getAnnotation();
|
||||
BaseService service = getService(bindAnnotation);
|
||||
FieldBinder binder = service.bindingFieldTo(voList);
|
||||
for(FieldAnnotation anno : list){
|
||||
BindField bindField = (BindField) anno.getAnnotation();
|
||||
binder.link(bindField.field(), anno.getFieldName());
|
||||
}
|
||||
parseConditionsAndBinding(binder, bindAnnotation.condition());
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 绑定Entity
|
||||
* @param voList
|
||||
* @param fieldAnnotation
|
||||
* @param <VO>
|
||||
*/
|
||||
private static <VO> void doBindingEntity(List<VO> voList, FieldAnnotation fieldAnnotation) {
|
||||
BindEntity annotation = (BindEntity) fieldAnnotation.getAnnotation();
|
||||
// 绑定关联对象entity
|
||||
BaseService service = getService(annotation);
|
||||
if(service != null){
|
||||
// 字段名
|
||||
String voFieldName = fieldAnnotation.getFieldName();
|
||||
// 构建binder
|
||||
BaseBinder binder = service.bindingEntityTo(voList).set(voFieldName);
|
||||
// 解析条件并且执行绑定
|
||||
parseConditionsAndBinding(binder, annotation.condition());
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 绑定Entity
|
||||
* @param voList
|
||||
* @param fieldAnnotation
|
||||
* @param <VO>
|
||||
*/
|
||||
private static <VO> void doBindingEntityList(List<VO> voList, FieldAnnotation fieldAnnotation) {
|
||||
BindEntityList bindAnnotation = (BindEntityList) fieldAnnotation.getAnnotation();
|
||||
// 绑定关联对象entity
|
||||
BaseService service = getService(bindAnnotation);
|
||||
if(service != null){
|
||||
// 字段名
|
||||
String voFieldName = fieldAnnotation.getFieldName();
|
||||
// 构建binder
|
||||
BaseBinder binder = service.bindingEntityListTo(voList).set(voFieldName);
|
||||
// 解析条件并且执行绑定
|
||||
parseConditionsAndBinding(binder, bindAnnotation.condition());
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 解析条件并且执行绑定
|
||||
* @param condition
|
||||
* @param binder
|
||||
*/
|
||||
private static void parseConditionsAndBinding(BaseBinder binder, String condition){
|
||||
try{
|
||||
ConditionManager.parseConditions(condition, binder);
|
||||
binder.bind();
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("解析注解条件与绑定执行异常", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Entity获取对应的Service实现类
|
||||
* @param annotation
|
||||
* @return
|
||||
*/
|
||||
private static BaseService getService(Annotation annotation){
|
||||
Class<?> entityClass = null;
|
||||
if(annotation instanceof BindMetadata){
|
||||
entityClass = Metadata.class;
|
||||
}
|
||||
else if(annotation instanceof BindField){
|
||||
BindField bindAnnotation = (BindField)annotation;
|
||||
entityClass = bindAnnotation.entity();
|
||||
}
|
||||
else if(annotation instanceof BindEntity){
|
||||
BindEntity bindAnnotation = (BindEntity)annotation;
|
||||
entityClass = bindAnnotation.entity();
|
||||
}
|
||||
else if(annotation instanceof BindEntityList){
|
||||
BindEntityList bindAnnotation = (BindEntityList)annotation;
|
||||
entityClass = bindAnnotation.entity();
|
||||
}
|
||||
else{
|
||||
log.warn("非预期的注解: "+ annotation.getClass().getSimpleName());
|
||||
return null;
|
||||
}
|
||||
// 根据entity获取Service
|
||||
BaseService service = ContextHelper.getServiceByEntity(entityClass);
|
||||
if(service == null){
|
||||
log.error("未能识别到Entity: "+entityClass.getName()+" 的Service实现!");
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package com.diboot.core.binding.manager;
|
||||
|
||||
import com.diboot.core.binding.parser.BindAnnotationGroup;
|
||||
import com.diboot.core.util.V;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* VO对象中的绑定注解 缓存管理类
|
||||
* @author Mazhicheng<br>
|
||||
* @version 1.0<br>
|
||||
* @date 2019/04/03 <br>
|
||||
*/
|
||||
public class BindAnnotationCacheManager {
|
||||
/**
|
||||
* VO类-绑定注解缓存
|
||||
*/
|
||||
private static Map<Class, BindAnnotationGroup> allVoBindAnnotationCacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取指定class对应的Bind相关注解
|
||||
* @param voClass
|
||||
* @return
|
||||
*/
|
||||
public static BindAnnotationGroup getBindAnnotationGroup(Class voClass){
|
||||
BindAnnotationGroup group = allVoBindAnnotationCacheMap.get(voClass);
|
||||
if(group == null){
|
||||
// 获取注解并缓存
|
||||
group = new BindAnnotationGroup();
|
||||
// 获取当前VO的注解
|
||||
Field[] fields = voClass.getDeclaredFields();
|
||||
if(fields != null){
|
||||
for (Field field : fields) {
|
||||
//遍历属性
|
||||
Annotation[] annotations = field.getDeclaredAnnotations();
|
||||
if (V.isEmpty(annotations)) {
|
||||
continue;
|
||||
}
|
||||
for (Annotation annotation : annotations) {
|
||||
group.addBindAnnotation(field.getName(), annotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
allVoBindAnnotationCacheMap.put(voClass, group);
|
||||
}
|
||||
// 返回归类后的注解对象
|
||||
return group;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.diboot.core.binding.manager;
|
||||
|
||||
/**
|
||||
* 实体类与表名之间的关联关系
|
||||
* @author Mazhicheng<br>
|
||||
* @version 1.0<br>
|
||||
* @date 2019/04/03 <br>
|
||||
*/
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 实体类与表名之间的关联关系
|
||||
* @author Mazhicheng<br>
|
||||
* @version 1.0<br>
|
||||
* @date 2019/04/03 <br>
|
||||
*/
|
||||
public class EntityToTableCacheManager {
|
||||
/**
|
||||
* entity类-table表名的映射关系
|
||||
*/
|
||||
private static Map<String, String> CLASSNAME_TABLENAME_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取表名
|
||||
* @param entityClass
|
||||
* @return
|
||||
*/
|
||||
public static String getTableName(Class entityClass){
|
||||
String tableName = CLASSNAME_TABLENAME_MAP.get(entityClass.getName());
|
||||
if(V.isEmpty(tableName)){
|
||||
// 获取当前VO的注解
|
||||
TableName annotation = (TableName) entityClass.getAnnotation(TableName.class);
|
||||
if(annotation != null){
|
||||
tableName = annotation.value();
|
||||
}
|
||||
else{
|
||||
tableName = S.toSnakeCase(entityClass.getSimpleName());
|
||||
}
|
||||
CLASSNAME_TABLENAME_MAP.put(entityClass.getName(), tableName);
|
||||
}
|
||||
return tableName;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package com.diboot.core.binding.parser;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntity;
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.core.binding.annotation.BindField;
|
||||
import com.diboot.core.binding.annotation.BindMetadata;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* VO绑定注解的归类分组,用于缓存解析后的结果
|
||||
* @author Mazhicheng<br>
|
||||
* @version 1.0<br>
|
||||
* @date 2019/04/03 <br>
|
||||
*/
|
||||
public class BindAnnotationGroup {
|
||||
/**
|
||||
* Metadata注解
|
||||
*/
|
||||
private List<FieldAnnotation> bindMetadataAnnotations;
|
||||
/**
|
||||
* 字段关联注解
|
||||
*/
|
||||
private List<FieldAnnotation> bindFieldAnnotations;
|
||||
/**
|
||||
* 实体关联注解
|
||||
*/
|
||||
private List<FieldAnnotation> bindEntityAnnotations;
|
||||
/**
|
||||
* 实体集合关联注解
|
||||
*/
|
||||
private List<FieldAnnotation> bindEntityListAnnotations;
|
||||
|
||||
/**
|
||||
* 添加注解
|
||||
* @param fieldName
|
||||
* @param annotation
|
||||
*/
|
||||
public void addBindAnnotation(String fieldName, Annotation annotation){
|
||||
if(annotation instanceof BindMetadata){
|
||||
if(bindMetadataAnnotations == null){
|
||||
bindMetadataAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindMetadataAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
}
|
||||
else if(annotation instanceof BindField){
|
||||
if(bindFieldAnnotations == null){
|
||||
bindFieldAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindFieldAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
}
|
||||
else if(annotation instanceof BindEntity){
|
||||
if(bindEntityAnnotations == null){
|
||||
bindEntityAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindEntityAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
}
|
||||
else if(annotation instanceof BindEntityList){
|
||||
if(bindEntityListAnnotations == null){
|
||||
bindEntityListAnnotations = new ArrayList<>();
|
||||
}
|
||||
bindEntityListAnnotations.add(new FieldAnnotation(fieldName, annotation));
|
||||
}
|
||||
}
|
||||
|
||||
public List<FieldAnnotation> getBindMetadataAnnotations() {
|
||||
return bindMetadataAnnotations;
|
||||
}
|
||||
|
||||
public List<FieldAnnotation> getBindFieldAnnotations() {
|
||||
return bindFieldAnnotations;
|
||||
}
|
||||
|
||||
public List<FieldAnnotation> getBindEntityAnnotations() {
|
||||
return bindEntityAnnotations;
|
||||
}
|
||||
|
||||
public List<FieldAnnotation> getBindEntityListAnnotations() {
|
||||
return bindEntityListAnnotations;
|
||||
}
|
||||
|
||||
public boolean isNotEmpty() {
|
||||
return bindMetadataAnnotations != null || bindFieldAnnotations != null || bindEntityAnnotations != null || bindEntityListAnnotations != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,318 @@
|
|||
package com.diboot.core.binding.parser;
|
||||
|
||||
import com.diboot.core.binding.BaseBinder;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import net.sf.jsqlparser.expression.BinaryExpression;
|
||||
import net.sf.jsqlparser.expression.Expression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 条件表达式的管理器
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/4/1
|
||||
*/
|
||||
public class ConditionManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(ConditionManager.class);
|
||||
|
||||
/**
|
||||
* 表达式缓存Map
|
||||
*/
|
||||
private static Map<String, List<Expression>> expressionParseResultMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 获取解析后的Expression列表
|
||||
* @param condition
|
||||
* @return
|
||||
*/
|
||||
private static List<Expression> getExpressionList(String condition){
|
||||
if(V.isEmpty(condition)){
|
||||
return null;
|
||||
}
|
||||
List<Expression> expressionList = expressionParseResultMap.get(condition);
|
||||
if(expressionList == null){
|
||||
ConditionParser visitor = new ConditionParser();
|
||||
try{
|
||||
Expression expression = CCJSqlParserUtil.parseCondExpression(condition);
|
||||
expression.accept(visitor);
|
||||
expressionList = visitor.getExpressList();
|
||||
expressionParseResultMap.put(condition, expressionList);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("关联条件解析异常", e);
|
||||
}
|
||||
}
|
||||
return expressionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 附加条件到binder
|
||||
* @param binder
|
||||
* @throws Exception
|
||||
*/
|
||||
public static <T> void parseConditions(String condition, BaseBinder<T> binder) throws Exception{
|
||||
List<Expression> expressionList = getExpressionList(condition);
|
||||
if(V.isEmpty(expressionList)){
|
||||
log.warn("无法解析注解条件: {} ", condition);
|
||||
return;
|
||||
}
|
||||
// 解析中间表关联
|
||||
MiddleTable middleTable = parseMiddleTable(expressionList);
|
||||
if(middleTable != null){
|
||||
binder.withMiddleTable(middleTable);
|
||||
}
|
||||
// 解析直接关联
|
||||
for(Expression operator : expressionList){
|
||||
if(operator instanceof EqualsTo){
|
||||
EqualsTo express = (EqualsTo)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.getRightExpression() instanceof Column){
|
||||
String entityColumn = getColumnName(express.getRightExpression().toString());
|
||||
binder.joinOn(annoColumn, entityColumn);
|
||||
}
|
||||
else{
|
||||
binder.andEQ(annoColumn, express.getRightExpression().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof NotEqualsTo){
|
||||
NotEqualsTo express = (NotEqualsTo)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.getRightExpression() instanceof Column){
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " != " + S.toSnakeCase(express.getRightExpression().toString()));
|
||||
}
|
||||
else{
|
||||
binder.andNE(annoColumn, express.getRightExpression().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof GreaterThan){
|
||||
GreaterThan express = (GreaterThan)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.getRightExpression() instanceof Column){
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " > "+ S.toSnakeCase(express.getRightExpression().toString()));
|
||||
}
|
||||
else{
|
||||
binder.andGT(annoColumn, express.getRightExpression().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof GreaterThanEquals){
|
||||
GreaterThanEquals express = (GreaterThanEquals)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.getRightExpression() instanceof Column){
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " >= "+ express.getRightExpression().toString());
|
||||
}
|
||||
else{
|
||||
binder.andGE(annoColumn, express.getRightExpression().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof MinorThan){
|
||||
MinorThan express = (MinorThan)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.getRightExpression() instanceof Column){
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " < "+ express.getRightExpression().toString());
|
||||
}
|
||||
else{
|
||||
binder.andLT(annoColumn, express.getRightExpression().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof MinorThanEquals){
|
||||
MinorThanEquals express = (MinorThanEquals)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.getRightExpression() instanceof Column){
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " <= "+ express.getRightExpression().toString());
|
||||
}
|
||||
else{
|
||||
binder.andLE(annoColumn, express.getRightExpression().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof IsNullExpression){
|
||||
IsNullExpression express = (IsNullExpression)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.isNot() == false){
|
||||
binder.andIsNull(annoColumn);
|
||||
}
|
||||
else{
|
||||
binder.andIsNotNull(annoColumn);
|
||||
}
|
||||
}
|
||||
else if(operator instanceof InExpression){
|
||||
InExpression express = (InExpression)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.isNot() == false){
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " IN " + express.getRightItemsList().toString());
|
||||
}
|
||||
else{
|
||||
binder.andApply(S.toSnakeCase(annoColumn) + " NOT IN " + express.getRightItemsList().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof Between){
|
||||
Between express = (Between)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.isNot() == false){
|
||||
binder.andBetween(annoColumn, express.getBetweenExpressionStart().toString(), express.getBetweenExpressionEnd().toString());
|
||||
}
|
||||
else{
|
||||
binder.andNotBetween(annoColumn, express.getBetweenExpressionStart().toString(), express.getBetweenExpressionEnd().toString());
|
||||
}
|
||||
}
|
||||
else if(operator instanceof LikeExpression){
|
||||
LikeExpression express = (LikeExpression)operator;
|
||||
String annoColumn = getColumnName(express.getLeftExpression().toString());
|
||||
if(express.isNot() == false){
|
||||
binder.andLike(annoColumn, express.getStringExpression());
|
||||
}
|
||||
else{
|
||||
binder.andNotLike(annoColumn, express.getStringExpression());
|
||||
}
|
||||
}
|
||||
else{
|
||||
log.warn("不支持的条件: "+operator.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析中间表
|
||||
* @param expressionList
|
||||
* @return
|
||||
*/
|
||||
private static MiddleTable parseMiddleTable(List<Expression> expressionList) {
|
||||
// 单一条件不是中间表条件
|
||||
if(expressionList.size() <= 1){
|
||||
return null;
|
||||
}
|
||||
// 统计出现次数
|
||||
Map<String, Integer> tableNameCountMap = new HashMap<>();
|
||||
for(Expression operator : expressionList){
|
||||
if(operator instanceof EqualsTo){
|
||||
EqualsTo express = (EqualsTo)operator;
|
||||
// 均为列
|
||||
if(express.getLeftExpression() instanceof Column && express.getRightExpression() instanceof Column){
|
||||
// 统计左侧列中出现的表名
|
||||
String leftColumn = express.getLeftExpression().toString();
|
||||
countTableName(tableNameCountMap, leftColumn);
|
||||
// 统计右侧列中出现的表名
|
||||
String rightColumn = express.getRightExpression().toString();
|
||||
countTableName(tableNameCountMap, rightColumn);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tableNameCountMap.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
String tableName = null;
|
||||
int count = 0;
|
||||
for(Map.Entry<String, Integer> entry : tableNameCountMap.entrySet()){
|
||||
if(entry.getValue() > count){
|
||||
count = entry.getValue();
|
||||
tableName = entry.getKey();
|
||||
}
|
||||
}
|
||||
// 提取到表
|
||||
MiddleTable middleTable = new MiddleTable(tableName);
|
||||
String leftHandColumn = null, rightHandColumn = null;
|
||||
for(Expression operator : expressionList){
|
||||
if(operator instanceof EqualsTo){
|
||||
EqualsTo express = (EqualsTo)operator;
|
||||
// 均为列
|
||||
if(express.getLeftExpression() instanceof Column && express.getRightExpression() instanceof Column){
|
||||
// 如果左侧为中间表字段
|
||||
String leftColumn = express.getLeftExpression().toString();
|
||||
if(leftColumn.startsWith(tableName+".")){
|
||||
// 绑定右手边连接列
|
||||
rightHandColumn = S.substringAfter(leftColumn, ".");
|
||||
//TODO entityPkField =
|
||||
}
|
||||
// 如果右侧为中间表字段
|
||||
String rightColumn = express.getRightExpression().toString();
|
||||
if(rightColumn.startsWith(tableName+".")){
|
||||
// 绑定左手边连接列
|
||||
leftHandColumn = S.substringAfter(leftColumn, ".");
|
||||
// TODO annoObjectFkField =
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
String leftExpression = null;
|
||||
if(operator instanceof NotEqualsTo){
|
||||
NotEqualsTo express = (NotEqualsTo)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof GreaterThan){
|
||||
GreaterThan express = (GreaterThan)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof GreaterThanEquals){
|
||||
GreaterThanEquals express = (GreaterThanEquals)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof MinorThan){
|
||||
MinorThan express = (MinorThan)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof MinorThanEquals){
|
||||
MinorThanEquals express = (MinorThanEquals)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof IsNullExpression){
|
||||
IsNullExpression express = (IsNullExpression)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof InExpression){
|
||||
InExpression express = (InExpression)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof Between){
|
||||
Between express = (Between)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
else if(operator instanceof LikeExpression){
|
||||
LikeExpression express = (LikeExpression)operator;
|
||||
leftExpression = express.getLeftExpression().toString();
|
||||
}
|
||||
if(leftExpression != null && leftExpression.startsWith(tableName+".")){
|
||||
middleTable.addAdditionalCondition(operator.toString());
|
||||
// TODO 移除
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void countTableName(Map<String, Integer> tableNameCountMap, String columnStr) {
|
||||
if(columnStr.contains(".")){
|
||||
String tempTableName = S.substringBefore(columnStr, ".");
|
||||
// 如果是中间表(非this,self标识的当前表)
|
||||
if(!"this".equals(tempTableName) && !"self".equals(tempTableName)){
|
||||
Integer count = tableNameCountMap.get(tempTableName);
|
||||
if(count == null){
|
||||
count = 0;
|
||||
}
|
||||
tableNameCountMap.put(tempTableName, count++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注解列
|
||||
* @return
|
||||
*/
|
||||
private static String getColumnName(String annoColumn){
|
||||
if(annoColumn.contains(".")){
|
||||
annoColumn = S.substringAfter(annoColumn, ".");
|
||||
}
|
||||
return annoColumn;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
package com.diboot.core.binding.parser;
|
||||
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import net.sf.jsqlparser.expression.*;
|
||||
import net.sf.jsqlparser.expression.operators.arithmetic.*;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.AndExpression;
|
||||
import net.sf.jsqlparser.expression.operators.conditional.OrExpression;
|
||||
import net.sf.jsqlparser.expression.operators.relational.*;
|
||||
import net.sf.jsqlparser.schema.Column;
|
||||
import net.sf.jsqlparser.statement.select.SubSelect;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关联注解条件解析器
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/3/30
|
||||
*/
|
||||
public class ConditionParser implements ExpressionVisitor,ItemsListVisitor {
|
||||
|
||||
public ConditionParser() {
|
||||
}
|
||||
|
||||
private List<String> errorMsgList = null;
|
||||
private List<Expression> expressList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 添加错误信息
|
||||
* @param errorMsg
|
||||
*/
|
||||
private void addError(String errorMsg){
|
||||
if(errorMsgList == null){
|
||||
errorMsgList = new ArrayList<>();
|
||||
}
|
||||
if(!errorMsgList.contains(errorMsg)){
|
||||
errorMsgList.add(errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取解析后的结果
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public List<Expression> getExpressList() throws Exception{
|
||||
if(V.notEmpty(errorMsgList)){
|
||||
throw new Exception(S.join(errorMsgList, "; "));
|
||||
}
|
||||
return expressList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(AndExpression andExpression) {
|
||||
andExpression.getLeftExpression().accept(this);
|
||||
andExpression.getRightExpression().accept(this);
|
||||
}
|
||||
|
||||
// ----- 支持的条件
|
||||
@Override
|
||||
public void visit(EqualsTo equalsTo) {
|
||||
if(!(equalsTo.getLeftExpression() instanceof Column)){
|
||||
addError("=条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(equalsTo);
|
||||
}
|
||||
@Override
|
||||
public void visit(NotEqualsTo notEqualsTo) {
|
||||
if(!(notEqualsTo.getLeftExpression() instanceof Column)){
|
||||
addError("!=条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(notEqualsTo);
|
||||
}
|
||||
@Override
|
||||
public void visit(GreaterThan greaterThan) {
|
||||
if(!(greaterThan.getLeftExpression() instanceof Column)){
|
||||
addError(">条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(greaterThan);
|
||||
}
|
||||
@Override
|
||||
public void visit(GreaterThanEquals greaterThanEquals) {
|
||||
if(!(greaterThanEquals.getLeftExpression() instanceof Column)){
|
||||
addError(">=条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(greaterThanEquals);
|
||||
}
|
||||
@Override
|
||||
public void visit(MinorThan minorThan) {
|
||||
if(!(minorThan.getLeftExpression() instanceof Column)){
|
||||
addError("<条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(minorThan);
|
||||
}
|
||||
@Override
|
||||
public void visit(MinorThanEquals minorThanEquals) {
|
||||
if(!(minorThanEquals.getLeftExpression() instanceof Column)){
|
||||
addError("<=条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(minorThanEquals);
|
||||
}
|
||||
@Override
|
||||
public void visit(IsNullExpression isNullExpression) {
|
||||
if(!(isNullExpression.getLeftExpression() instanceof Column)){
|
||||
addError("IsNull条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(isNullExpression);
|
||||
}
|
||||
@Override
|
||||
public void visit(InExpression inExpression) {
|
||||
if(!(inExpression.getLeftExpression() instanceof Column)){
|
||||
addError("IN条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(inExpression);
|
||||
}
|
||||
@Override
|
||||
public void visit(Between between) {
|
||||
if(!(between.getLeftExpression() instanceof Column)){
|
||||
addError("Between条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(between);
|
||||
}
|
||||
@Override
|
||||
public void visit(LikeExpression likeExpression) {
|
||||
if(!(likeExpression.getLeftExpression() instanceof Column)){
|
||||
addError("Like条件左侧必须为字段/列名");
|
||||
}
|
||||
expressList.add(likeExpression);
|
||||
}
|
||||
|
||||
//------- 暂不支持的条件
|
||||
@Override
|
||||
public void visit(OrExpression orExpression) {
|
||||
addError("暂不支持 OR 关联条件");
|
||||
}
|
||||
// ------ 忽略的条件
|
||||
@Override
|
||||
public void visit(Column tableColumn) {
|
||||
}
|
||||
@Override
|
||||
public void visit(SubSelect subSelect) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(ExpressionList expressionList) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(NamedExpressionList namedExpressionList) {
|
||||
|
||||
}
|
||||
@Override
|
||||
public void visit(MultiExpressionList multiExprList) {
|
||||
}
|
||||
@Override
|
||||
public void visit(CaseExpression caseExpression) {
|
||||
}
|
||||
@Override
|
||||
public void visit(WhenClause whenClause) {
|
||||
}
|
||||
@Override
|
||||
public void visit(ExistsExpression existsExpression) {
|
||||
}
|
||||
@Override
|
||||
public void visit(AllComparisonExpression allComparisonExpression) {
|
||||
}
|
||||
@Override
|
||||
public void visit(AnyComparisonExpression anyComparisonExpression) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Concat concat) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Matches matches) {
|
||||
}
|
||||
@Override
|
||||
public void visit(BitwiseAnd bitwiseAnd) {
|
||||
}
|
||||
@Override
|
||||
public void visit(BitwiseOr bitwiseOr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(BitwiseXor bitwiseXor) {
|
||||
}
|
||||
@Override
|
||||
public void visit(CastExpression cast) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Modulo modulo) {
|
||||
}
|
||||
@Override
|
||||
public void visit(AnalyticExpression aexpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(ExtractExpression eexpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(IntervalExpression iexpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(OracleHierarchicalExpression oexpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(RegExpMatchOperator rexpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(JsonExpression jsonExpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(JsonOperator jsonExpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(RegExpMySQLOperator regExpMySQLOperator) {
|
||||
}
|
||||
@Override
|
||||
public void visit(UserVariable var) {
|
||||
}
|
||||
@Override
|
||||
public void visit(NumericBind bind) {
|
||||
}
|
||||
@Override
|
||||
public void visit(KeepExpression aexpr) {
|
||||
}
|
||||
@Override
|
||||
public void visit(MySQLGroupConcat groupConcat) {
|
||||
}
|
||||
@Override
|
||||
public void visit(ValueListExpression valueList) {
|
||||
}
|
||||
@Override
|
||||
public void visit(RowConstructor rowConstructor) {
|
||||
}
|
||||
@Override
|
||||
public void visit(OracleHint hint) {
|
||||
}
|
||||
@Override
|
||||
public void visit(TimeKeyExpression timeKeyExpression) {
|
||||
}
|
||||
@Override
|
||||
public void visit(DateTimeLiteralExpression literal) {
|
||||
}
|
||||
@Override
|
||||
public void visit(NotExpression aThis) {
|
||||
}
|
||||
@Override
|
||||
public void visit(BitwiseRightShift aThis) {
|
||||
}
|
||||
@Override
|
||||
public void visit(BitwiseLeftShift aThis) {
|
||||
}
|
||||
@Override
|
||||
public void visit(NullValue nullValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Function function) {
|
||||
}
|
||||
@Override
|
||||
public void visit(SignedExpression signedExpression) {
|
||||
}
|
||||
@Override
|
||||
public void visit(JdbcParameter jdbcParameter) {
|
||||
}
|
||||
@Override
|
||||
public void visit(JdbcNamedParameter jdbcNamedParameter) {
|
||||
}
|
||||
@Override
|
||||
public void visit(DoubleValue doubleValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(LongValue longValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(HexValue hexValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(DateValue dateValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(TimeValue timeValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(TimestampValue timestampValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Parenthesis parenthesis) {
|
||||
}
|
||||
@Override
|
||||
public void visit(StringValue stringValue) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Addition addition) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Division division) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Multiplication multiplication) {
|
||||
}
|
||||
@Override
|
||||
public void visit(Subtraction subtraction) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.diboot.core.binding.parser;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* 字段名与注解的包装对象关系 <br>
|
||||
*
|
||||
* @author Mazhicheng<br>
|
||||
* @version 1.0<br>
|
||||
* @date 2019/04/04 <br>
|
||||
*/
|
||||
public class FieldAnnotation{
|
||||
/**
|
||||
* 字段名
|
||||
*/
|
||||
private String fieldName;
|
||||
/**
|
||||
* 注解
|
||||
*/
|
||||
private Annotation annotation;
|
||||
|
||||
public FieldAnnotation(String fieldName, Annotation annotation){
|
||||
this.fieldName = fieldName;
|
||||
this.annotation = annotation;
|
||||
}
|
||||
|
||||
public String getFieldName() {
|
||||
return fieldName;
|
||||
}
|
||||
|
||||
public Annotation getAnnotation() {
|
||||
return annotation;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package com.diboot.core.binding.parser;
|
||||
|
||||
import com.diboot.core.config.Cons;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <Description> <br>
|
||||
*
|
||||
* @author Mazhicheng<br>
|
||||
* @version 1.0<br>
|
||||
* @date 2019/04/01 <br>
|
||||
*/
|
||||
public class MiddleTable {
|
||||
/**
|
||||
* 中间表
|
||||
*/
|
||||
private String table;
|
||||
/**
|
||||
* 与注解VO的外键关联的连接字段
|
||||
*/
|
||||
private String leftHandColumn;
|
||||
/**
|
||||
* 与被引用Entity属性主键的连接字段
|
||||
*/
|
||||
private String rightHandColumn;
|
||||
/**
|
||||
* 附加条件
|
||||
*/
|
||||
private List<String> additionalConditions;
|
||||
|
||||
public MiddleTable(String table){
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
public String getTable() {
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接(左手连接VO的外键,右手连接Entity属性的主键)
|
||||
* @param leftHandColumn
|
||||
* @param rightHandColumn
|
||||
* @return
|
||||
*/
|
||||
public MiddleTable connect(String leftHandColumn, String rightHandColumn) {
|
||||
this.leftHandColumn = leftHandColumn;
|
||||
this.rightHandColumn = rightHandColumn;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加中间表查询所需的附加条件
|
||||
* @param additionalCondition
|
||||
*/
|
||||
public MiddleTable addAdditionalCondition(String additionalCondition) {
|
||||
if(this.additionalConditions == null){
|
||||
this.additionalConditions = new ArrayList<>();
|
||||
}
|
||||
this.additionalConditions.add(additionalCondition);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换查询SQL
|
||||
* @param annoForeignKeyList 注解外键值的列表,用于拼接SQL查询
|
||||
* @return
|
||||
*/
|
||||
public String toSQL(List annoForeignKeyList){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT ").append(this.leftHandColumn).append( Cons.SEPARATOR_COMMA)
|
||||
.append(this.rightHandColumn).append(" FROM ").append(this.table)
|
||||
.append(" WHERE ").append(this.leftHandColumn).append(" IN(")
|
||||
//TODO 生成IN
|
||||
.append(")");
|
||||
if(this.additionalConditions != null){
|
||||
for(String condition : this.additionalConditions){
|
||||
sb.append(" AND ").append(condition);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.diboot.core.config;
|
||||
|
||||
import com.diboot.core.util.PropertiesUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/***
|
||||
* 系统默认配置
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class BaseConfig {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseConfig.class);
|
||||
|
||||
/**
|
||||
* 从默认的/指定的 Properties文件获取配置
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String getProperty(String key, String... propertiesFileName){
|
||||
return PropertiesUtils.get(key, propertiesFileName);
|
||||
}
|
||||
|
||||
/***
|
||||
* 从默认的/指定的 Properties文件获取boolean值
|
||||
* @param key
|
||||
* @param propertiesFileName
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTrue(String key, String... propertiesFileName){
|
||||
return PropertiesUtils.getBoolean(key, propertiesFileName);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取int类型
|
||||
* @param key
|
||||
* @param propertiesFileName
|
||||
* @return
|
||||
*/
|
||||
public static int getInteger(String key, String... propertiesFileName){
|
||||
return PropertiesUtils.getInteger(key, propertiesFileName);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取截取长度
|
||||
* @return
|
||||
*/
|
||||
public static int getCutLength(){
|
||||
Integer length = PropertiesUtils.getInteger("system.default.cutLength");
|
||||
if(length != null){
|
||||
return length;
|
||||
}
|
||||
return 20;
|
||||
}
|
||||
|
||||
/***
|
||||
* 默认页数
|
||||
* @return
|
||||
*/
|
||||
public static int getPageSize() {
|
||||
Integer length = PropertiesUtils.getInteger("pagination.default.pageSize");
|
||||
if(length != null){
|
||||
return length;
|
||||
}
|
||||
return 20;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取批量插入的每批次数量
|
||||
* @return
|
||||
*/
|
||||
public static int getBatchSize() {
|
||||
return 1000;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.diboot.core.config;
|
||||
|
||||
/**
|
||||
* 基础常量定义
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class Cons {
|
||||
/**
|
||||
* 默认字符集UTF-8
|
||||
*/
|
||||
public static final String CHARSET_UTF8 = "UTF-8";
|
||||
/**
|
||||
* 分隔符 ,
|
||||
*/
|
||||
public static final String SEPARATOR_COMMA = ",";
|
||||
|
||||
public static final String SEPARATOR_UNDERSCORE = "_";
|
||||
/***
|
||||
* 默认字段名定义
|
||||
*/
|
||||
public enum FieldName{
|
||||
/**
|
||||
* 主键属性名
|
||||
*/
|
||||
id,
|
||||
/**
|
||||
* 默认的上级ID属性名
|
||||
*/
|
||||
parentId,
|
||||
/**
|
||||
* 子节点属性名
|
||||
*/
|
||||
children
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,435 @@
|
|||
package com.diboot.core.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.ObjectError;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.*;
|
||||
|
||||
/***
|
||||
* Controller的父类
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
@Controller
|
||||
public class BaseController {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseController.class);
|
||||
|
||||
/***
|
||||
* 分页参数列表
|
||||
*/
|
||||
protected static final List<String> PARAM_PAGES = Arrays.asList("_pageIndex", "_pageSize", "_totalCount", "_orderBy");
|
||||
/***
|
||||
* 字段
|
||||
*/
|
||||
protected static final String PARAM_FIELDS = "_fields";
|
||||
|
||||
/**
|
||||
* ID参数名
|
||||
*/
|
||||
protected static final String PARAM_ID = Cons.FieldName.id.name();
|
||||
|
||||
/**
|
||||
* 错误关键字
|
||||
*/
|
||||
protected static final String ERROR = "error";
|
||||
|
||||
/**
|
||||
* 解析所有的验证错误信息,转换为JSON
|
||||
* @param result
|
||||
* @return
|
||||
*/
|
||||
protected String getBindingError(BindingResult result){
|
||||
if(result == null || !result.hasErrors()){
|
||||
return null;
|
||||
}
|
||||
List<ObjectError> errors = result.getAllErrors();
|
||||
List<String> allErrors = new ArrayList<>(errors.size());
|
||||
for(ObjectError error : errors){
|
||||
allErrors.add(error.getDefaultMessage().replaceAll("\"", "'"));
|
||||
}
|
||||
return S.join(allErrors);
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建查询wrapper
|
||||
* @param request
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public <T extends BaseEntity> QueryWrapper<T> buildQuery(HttpServletRequest request) throws Exception{
|
||||
if(!RequestMethod.GET.name().equalsIgnoreCase(request.getMethod())){
|
||||
log.warn("调用错误: 非GET请求,无需构建查询条件!");
|
||||
return null;
|
||||
}
|
||||
//TODO 是否需要先拿到Entity定义的属性列表,只映射该列表中的属性?
|
||||
QueryWrapper query = new QueryWrapper<T>();
|
||||
Map<String, Object> requestMap = getParamsMap(request);
|
||||
if(V.notEmpty(requestMap)){
|
||||
if(requestMap.containsKey(PARAM_FIELDS) && V.notEmpty(requestMap.get(PARAM_FIELDS))){
|
||||
if(requestMap.get(PARAM_FIELDS) instanceof String){
|
||||
String fields = (String) requestMap.get(PARAM_FIELDS);
|
||||
query.select(fields);
|
||||
}
|
||||
}
|
||||
for(Map.Entry<String, Object> entry : requestMap.entrySet()){
|
||||
Object value = entry.getValue();
|
||||
if(!entry.getKey().startsWith("_") && value != null){
|
||||
if(value instanceof Set || value instanceof List || value.getClass().isArray()){
|
||||
query.in(S.toSnakeCase(entry.getKey()), value);
|
||||
}
|
||||
else if(value instanceof String){
|
||||
query.eq(S.toSnakeCase(entry.getKey()), value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建分页对象
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
protected Pagination buildPagination(HttpServletRequest request) throws Exception{
|
||||
return buildPagination(request, true);
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建分页对象
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
protected Pagination buildPagination(HttpServletRequest request, boolean newInstanceIfNull) throws Exception{
|
||||
Pagination page = newInstanceIfNull? new Pagination() : null;
|
||||
Map<String, Object> pageParamMap = getParamsMap(request, PARAM_PAGES);
|
||||
if(V.notEmpty(pageParamMap)){
|
||||
if(page == null){
|
||||
page = new Pagination();
|
||||
}
|
||||
BeanUtils.bindProperties(page, pageParamMap);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取请求参数Map
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> getParamsMap(HttpServletRequest request) throws Exception{
|
||||
return getParamsMap(request, null);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取请求参数Map
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
private Map<String, Object> getParamsMap(HttpServletRequest request, List<String> paramList) throws Exception{
|
||||
Map<String, Object> result = new HashMap<>(8);
|
||||
Enumeration paramNames = request.getParameterNames();
|
||||
while (paramNames.hasMoreElements()){
|
||||
String paramName = (String) paramNames.nextElement();
|
||||
// 如果非要找的参数,则跳过
|
||||
if(V.notEmpty(paramList) && !paramList.contains(paramName)){
|
||||
continue;
|
||||
}
|
||||
String[] values = request.getParameterValues(paramName);
|
||||
if(V.notEmpty(values)){
|
||||
if(values.length == 1){
|
||||
if(V.notEmpty(values[0])){
|
||||
String paramValue = java.net.URLDecoder.decode(values[0], Cons.CHARSET_UTF8);
|
||||
result.put(paramName, paramValue);
|
||||
}
|
||||
}
|
||||
else{
|
||||
String[] valueArray = new String[values.length];
|
||||
for(int i=0; i<values.length; i++){
|
||||
valueArray[i] = java.net.URLDecoder.decode(values[i], Cons.CHARSET_UTF8);
|
||||
}
|
||||
// 多个值需传递到后台SQL的in语句
|
||||
result.put(paramName, valueArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取请求URI (去除contextPath)
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
protected static String getRequestMappingURI(HttpServletRequest request){
|
||||
String contextPath = request.getContextPath();
|
||||
if(V.notEmpty(contextPath)){
|
||||
return S.replace(request.getRequestURI(), contextPath, "");
|
||||
}
|
||||
return request.getRequestURI();
|
||||
}
|
||||
|
||||
/***
|
||||
* 返回json格式错误信息
|
||||
* @param response
|
||||
* @param jsonResult
|
||||
*/
|
||||
protected static void responseJson(HttpServletResponse response, JsonResult jsonResult){
|
||||
// 处理异步请求
|
||||
PrintWriter pw = null;
|
||||
try {
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
|
||||
pw = response.getWriter();
|
||||
pw.write(JSON.stringify(jsonResult));
|
||||
pw.flush();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("处理异步请求异常", e);
|
||||
}
|
||||
finally {
|
||||
if (pw != null) {
|
||||
pw.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 将请求参数值转换为Map
|
||||
* @param request
|
||||
* @return
|
||||
*/
|
||||
public static Map<String, Object> convertParams2Map(HttpServletRequest request){
|
||||
Map<String, Object> result = new HashMap<>(8);
|
||||
if(request == null){
|
||||
return result;
|
||||
}
|
||||
Enumeration paramNames = request.getParameterNames();
|
||||
while (paramNames.hasMoreElements()){
|
||||
String paramName = (String) paramNames.nextElement();
|
||||
String[] values = request.getParameterValues(paramName);
|
||||
if(V.notEmpty(values)){
|
||||
if(values.length == 1){
|
||||
result.put(paramName, values[0]);
|
||||
}
|
||||
else{
|
||||
// 多个值需传递到后台SQL的in语句
|
||||
result.put(paramName, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/***
|
||||
* 将请求参数值绑定成Model
|
||||
* @param request
|
||||
*/
|
||||
public static void buildEntity(BaseEntity entity, HttpServletRequest request){
|
||||
Map<String, Object> propMap = convertParams2Map(request);
|
||||
BeanUtils.bindProperties(entity, propMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 打印所有参数信息
|
||||
* @param request
|
||||
*/
|
||||
protected static void dumpParams(HttpServletRequest request){
|
||||
Map<String, String[]> params = request.getParameterMap();
|
||||
if(params != null && !params.isEmpty()){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for(Map.Entry<String, String[]> entry : params.entrySet()){
|
||||
String[] values = entry.getValue();
|
||||
if(values != null && values.length > 0){
|
||||
sb.append(entry.getKey() + "=" + S.join(values)+"; ");
|
||||
}
|
||||
}
|
||||
log.debug(sb.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取Long参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public Long getLong(HttpServletRequest request, String param){
|
||||
return S.toLong(request.getParameter(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取Long参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public long getLong(HttpServletRequest request, String param, Long defaultValue){
|
||||
return S.toLong(request.getParameter(param), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取Int参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public Integer getInteger(HttpServletRequest request, String param){
|
||||
return S.toInt(request.getParameter(param));
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取Int参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public int getInt(HttpServletRequest request, String param, Integer defaultValue){
|
||||
return S.toInt(request.getParameter(param), defaultValue);
|
||||
}
|
||||
|
||||
/***
|
||||
* 从request中获取boolean值
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public boolean getBoolean(HttpServletRequest request, String param){
|
||||
return S.toBoolean(request.getParameter(param));
|
||||
}
|
||||
|
||||
/***
|
||||
* 从request中获取boolean值
|
||||
* @param request
|
||||
* @param param
|
||||
* @param defaultBoolean
|
||||
* @return
|
||||
*/
|
||||
public boolean getBoolean(HttpServletRequest request, String param, boolean defaultBoolean){
|
||||
return S.toBoolean(request.getParameter(param), defaultBoolean);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取Double参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public Double getDouble(HttpServletRequest request, String param){
|
||||
if(V.notEmpty(request.getParameter(param))){
|
||||
return Double.parseDouble(request.getParameter(param));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取Double参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public Double getDouble(HttpServletRequest request, String param, Double defaultValue){
|
||||
if(V.notEmpty(request.getParameter(param))){
|
||||
return Double.parseDouble(request.getParameter(param));
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取String参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public String getString(HttpServletRequest request, String param){
|
||||
if(V.notEmpty(request.getParameter(param))){
|
||||
return request.getParameter(param);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取String参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @param defaultValue
|
||||
* @return
|
||||
*/
|
||||
public String getString(HttpServletRequest request, String param, String defaultValue){
|
||||
if(V.notEmpty(request.getParameter(param))){
|
||||
return request.getParameter(param);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从request获取String[]参数
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public String[] getStringArray(HttpServletRequest request, String param){
|
||||
if(request.getParameterValues(param) != null){
|
||||
return request.getParameterValues(param);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 从request里获取String列表
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public List<String> getStringList(HttpServletRequest request, String param){
|
||||
String[] strArray = getStringArray(request, param);
|
||||
if(V.isEmpty(strArray)){
|
||||
return null;
|
||||
}
|
||||
return Arrays.asList(strArray);
|
||||
}
|
||||
|
||||
/***
|
||||
* 从request里获取Long列表
|
||||
* @param request
|
||||
* @param param
|
||||
* @return
|
||||
*/
|
||||
public List<Long> getLongList(HttpServletRequest request, String param){
|
||||
String[] strArray = getStringArray(request, param);
|
||||
if(V.isEmpty(strArray)){
|
||||
return null;
|
||||
}
|
||||
List<Long> longList = new ArrayList<>();
|
||||
for(String str : strArray){
|
||||
if(V.notEmpty(str)){
|
||||
longList.add(Long.parseLong(str));
|
||||
}
|
||||
}
|
||||
return longList;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package com.diboot.core.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
* 增删改查通用管理功能-父类
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
@RestController
|
||||
public abstract class BaseCrudRestController extends BaseController {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseCrudRestController.class);
|
||||
|
||||
/**
|
||||
* 获取service实例
|
||||
* @return
|
||||
*/
|
||||
protected abstract BaseService getService();
|
||||
|
||||
/***
|
||||
* 获取某资源的集合
|
||||
* <p>
|
||||
* url参数示例: /metadata/list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @param request
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected <T> JsonResult getEntityList(HttpServletRequest request, Wrapper queryWrapper) throws Exception {
|
||||
// 查询当前页的数据
|
||||
List entityList = getService().getEntityList(queryWrapper);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, entityList);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取某资源的集合
|
||||
* <p>
|
||||
* url参数示例: /metadata/list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @param request
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected <T> JsonResult getEntityListWithPaging(HttpServletRequest request, Wrapper queryWrapper, Class<T> clazz) throws Exception {
|
||||
// 构建分页
|
||||
Pagination pagination = buildPagination(request);
|
||||
log.debug(JSON.stringify(pagination));
|
||||
// 查询当前页的数据
|
||||
List entityList = getService().getEntityList(queryWrapper, pagination);
|
||||
// 转换为VO
|
||||
entityList = BeanUtils.convertList(entityList, clazz);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, entityList).bindPagination(pagination);
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据id获取某资源对象
|
||||
* @param id
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected JsonResult getEntity(Long id) throws Exception {
|
||||
Object entity = getService().getEntity(id);
|
||||
return new JsonResult(Status.OK, entity);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建资源对象
|
||||
* @param entity
|
||||
* @param result
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected JsonResult createEntity(BaseEntity entity, BindingResult result, ModelMap modelMap) throws Exception {
|
||||
// Model属性值验证结果
|
||||
if(result != null && result.hasErrors()) {
|
||||
return new JsonResult(Status.FAIL_INVALID_PARAM, super.getBindingError(result));
|
||||
}
|
||||
if(modelMap.get(ERROR) != null){
|
||||
return new JsonResult(Status.FAIL_VALIDATION, (String) modelMap.get(ERROR));
|
||||
}
|
||||
// 执行保存操作
|
||||
boolean success = getService().createEntity(entity);
|
||||
if(success){
|
||||
// 组装返回结果
|
||||
Map<String, Object> data = new HashMap<>(2);
|
||||
data.put(PARAM_ID, entity.getId());
|
||||
return new JsonResult(Status.OK, data);
|
||||
}
|
||||
else{
|
||||
log.warn("创建操作未成功,model="+entity.getClass().getSimpleName());
|
||||
// 组装返回结果
|
||||
return new JsonResult(Status.FAIL_OPERATION);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据ID更新资源对象
|
||||
* @param entity
|
||||
* @param result
|
||||
* @return JsonResult
|
||||
* @throws Exception
|
||||
*/
|
||||
protected JsonResult updateEntity(BaseEntity entity, BindingResult result, ModelMap modelMap) throws Exception{
|
||||
// Model属性值验证结果
|
||||
if(result.hasErrors()) {
|
||||
return new JsonResult(Status.FAIL_INVALID_PARAM, super.getBindingError(result));
|
||||
}
|
||||
if(modelMap.get(ERROR) != null){
|
||||
return new JsonResult(Status.FAIL_VALIDATION, (String) modelMap.get(ERROR));
|
||||
}
|
||||
// 执行保存操作
|
||||
boolean success = getService().updateEntity(entity);
|
||||
if(success){
|
||||
// 组装返回结果
|
||||
Map<String, Object> data = new HashMap<>(2);
|
||||
data.put(PARAM_ID, entity.getId());
|
||||
return new JsonResult(Status.OK, data);
|
||||
}
|
||||
else{
|
||||
log.warn("更新操作失败,model="+entity.getClass().getSimpleName()+", id="+entity.getId());
|
||||
// 返回操作结果
|
||||
return new JsonResult(Status.FAIL_OPERATION);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据id删除资源对象
|
||||
* @param id
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
protected JsonResult deleteEntity(Serializable id) throws Exception{
|
||||
if(id == null) {
|
||||
return new JsonResult(Status.FAIL_INVALID_PARAM, "请选择需要删除的条目!");
|
||||
}
|
||||
// 是否有权限删除
|
||||
BaseEntity model = (BaseEntity) getService().getEntity(id);
|
||||
// 执行删除操作
|
||||
String error = beforeDelete(model);
|
||||
if(error != null){
|
||||
// 返回json
|
||||
return new JsonResult(Status.FAIL_OPERATION, error);
|
||||
}
|
||||
// 执行删除操作
|
||||
boolean success = getService().deleteEntity(id);
|
||||
if(success){
|
||||
log.info("删除操作成功,model="+model.getClass().getSimpleName()+", id="+id);
|
||||
// 组装返回结果
|
||||
Map<String, Object> data = new HashMap<>(2);
|
||||
data.put(PARAM_ID, model.getId());
|
||||
return new JsonResult(Status.OK, data);
|
||||
}
|
||||
else{
|
||||
log.warn("删除操作未成功,model="+model.getClass().getSimpleName()+", id="+id);
|
||||
return new JsonResult(Status.FAIL_OPERATION);
|
||||
}
|
||||
}
|
||||
|
||||
//============= 供子类继承重写的方法 =================
|
||||
/***
|
||||
* 是否有删除权限,如不可删除返回错误提示信息,如 Status.FAIL_NO_PERMISSION.label()
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
protected String beforeDelete(BaseEntity entity){
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.diboot.core.controller;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
/**
|
||||
* 异常处理类
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class ExceptionController extends BaseController{
|
||||
private static final Logger log = LoggerFactory.getLogger(ExceptionController.class);
|
||||
|
||||
/***
|
||||
* 默认异常处理
|
||||
* @param request
|
||||
* @param ex
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public void handleException(HttpServletRequest request, HttpServletResponse response, Exception ex) {
|
||||
// 记录日志
|
||||
log.error("发生异常:", ex);
|
||||
|
||||
String requestUrl = (String) request.getAttribute("javax.servlet.error.request_uri");
|
||||
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
|
||||
Object exception = request.getAttribute("javax.servlet.error.exception");
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("request_uri: [").append(requestUrl).append("] Error occured : ").append("status_code=").append(statusCode)
|
||||
.append(";message=").append(request.getAttribute("javax.servlet.error.message")).append(";exception=").append(exception);
|
||||
log.warn(sb.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package com.diboot.core.entity;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableLogic;
|
||||
import com.diboot.core.util.JSON;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Entity基础父类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
*/
|
||||
public abstract class BaseEntity implements Serializable {
|
||||
private static final long serialVersionUID = 10203L;
|
||||
|
||||
/***
|
||||
* 默认主键字段id,类型为Long型自增,转json时转换为String
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Long id;
|
||||
|
||||
/***
|
||||
* 默认逻辑删除标记,deleted=0有效
|
||||
*/
|
||||
@TableLogic
|
||||
@JSONField(serialize = false)
|
||||
private boolean deleted = false;
|
||||
|
||||
/***
|
||||
* 默认记录创建时间字段,新建时由数据库赋值
|
||||
*/
|
||||
@TableField(update="now()")
|
||||
private Date createTime;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return this.createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public boolean isDeleted() {
|
||||
return deleted;
|
||||
}
|
||||
|
||||
public void setDeleted(boolean deleted) {
|
||||
this.deleted = deleted;
|
||||
}
|
||||
|
||||
/***
|
||||
* 是否为新建
|
||||
* @return
|
||||
*/
|
||||
@JSONField(serialize = false)
|
||||
public boolean isNew(){
|
||||
return getId() != null;
|
||||
}
|
||||
|
||||
/***
|
||||
* model对象转为map
|
||||
* @return
|
||||
*/
|
||||
public Map<String, Object> toMap(){
|
||||
String jsonStr = JSON.stringify(this);
|
||||
return JSON.toMap(jsonStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* model对象转为String
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public String toString(){
|
||||
return this.getClass().getName()+ ":"+this.getId();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package com.diboot.core.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.util.V;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 附带extdata扩展字段的Entity父类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
*/
|
||||
public abstract class BaseExtEntity extends BaseEntity {
|
||||
private static final long serialVersionUID = 10204L;
|
||||
|
||||
@TableField
|
||||
private String extdata; //扩展数据
|
||||
|
||||
@TableField(exist = false)
|
||||
private Map<String, Object> extdataMap;
|
||||
|
||||
public String getExtdata() {
|
||||
if(V.isEmpty(this.extdataMap)){
|
||||
return null;
|
||||
}
|
||||
return JSON.toJSONString(this.extdataMap);
|
||||
}
|
||||
|
||||
public void setExtdata(String extdata) {
|
||||
if(V.notEmpty(extdata)){
|
||||
this.extdataMap = JSON.toLinkedHashMap(extdata);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 从extdata JSON中提取扩展属性值
|
||||
* @param extAttrName
|
||||
* @return
|
||||
*/
|
||||
public Object getFromExt(String extAttrName){
|
||||
if(this.extdataMap == null){
|
||||
return null;
|
||||
}
|
||||
return this.extdataMap.get(extAttrName);
|
||||
}
|
||||
|
||||
/***
|
||||
* 添加扩展属性和值到extdata JSON中
|
||||
* @param extAttrName
|
||||
* @param extAttrValue
|
||||
*/
|
||||
public void addIntoExt(String extAttrName, Object extAttrValue){
|
||||
if(extAttrName == null && extAttrValue == null){
|
||||
return;
|
||||
}
|
||||
if(this.extdataMap == null){
|
||||
this.extdataMap = new LinkedHashMap<>();
|
||||
}
|
||||
this.extdataMap.put(extAttrName, extAttrValue);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package com.diboot.core.entity;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Model的List包装类,用于接收List并绑定校验的情况
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2018/11/8
|
||||
*/
|
||||
public class EntityList<T extends BaseEntity> {
|
||||
|
||||
@Valid
|
||||
private final List<T> entityList;
|
||||
|
||||
public EntityList(final T... entities){
|
||||
this.entityList = Arrays.asList(entities);
|
||||
}
|
||||
|
||||
public EntityList(final List<T> entityList){
|
||||
this.entityList = entityList;
|
||||
}
|
||||
|
||||
public List<T> getModelList(){
|
||||
return entityList;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
package com.diboot.core.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 元数据实体
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
*/
|
||||
public class Metadata extends BaseExtEntity {
|
||||
private static final long serialVersionUID = 11301L;
|
||||
|
||||
/***
|
||||
* 上级ID
|
||||
*/
|
||||
@NotNull(message = "上级ID不能为空,如无请设为0")
|
||||
@TableField
|
||||
private Long parentId = 0L;
|
||||
|
||||
/***
|
||||
* 元数据类型
|
||||
*/
|
||||
@NotNull(message = "元数据类型不能为空!")
|
||||
@Length(max = 50, message = "元数据类型长度超长!")
|
||||
@TableField
|
||||
private String type;
|
||||
|
||||
/***
|
||||
* 元数据项的显示名称
|
||||
*/
|
||||
@NotNull(message = "元数据项名称不能为空!")
|
||||
@Length(max = 100, message = "元数据项名称长度超长!")
|
||||
@TableField
|
||||
private String itemName;
|
||||
|
||||
/***
|
||||
* 元数据项的存储值(编码)
|
||||
*/
|
||||
@Length(max = 100, message = "元数据项编码长度超长!")
|
||||
@TableField
|
||||
private String itemValue;
|
||||
|
||||
/***
|
||||
* 备注信息
|
||||
*/
|
||||
@Length(max = 200, message = "元数据备注长度超长!")
|
||||
@TableField
|
||||
private String comment;
|
||||
|
||||
/***
|
||||
* 排序号
|
||||
*/
|
||||
@TableField
|
||||
private int sortId = 99;
|
||||
|
||||
/***
|
||||
* 是否为系统预置(预置不可删除)
|
||||
*/
|
||||
@TableField
|
||||
private boolean system = true;
|
||||
|
||||
/***
|
||||
* 是否可编辑
|
||||
*/
|
||||
@TableField
|
||||
private boolean editable = false;
|
||||
|
||||
public Long getParentId() {
|
||||
return parentId;
|
||||
}
|
||||
|
||||
public void setParentId(Long parentId) {
|
||||
this.parentId = parentId;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getItemName() {
|
||||
return itemName;
|
||||
}
|
||||
|
||||
public void setItemName(String itemName) {
|
||||
this.itemName = itemName;
|
||||
}
|
||||
|
||||
public String getItemValue() {
|
||||
return itemValue;
|
||||
}
|
||||
|
||||
public void setItemValue(String itemValue) {
|
||||
this.itemValue = itemValue;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
return comment;
|
||||
}
|
||||
|
||||
public void setComment(String comment) {
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public int getSortId() {
|
||||
return sortId;
|
||||
}
|
||||
|
||||
public void setSortId(int sortId) {
|
||||
this.sortId = sortId;
|
||||
}
|
||||
|
||||
public boolean isSystem() {
|
||||
return system;
|
||||
}
|
||||
|
||||
public void setSystem(boolean system) {
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
public boolean isEditable() {
|
||||
return editable;
|
||||
}
|
||||
|
||||
public void setEditable(boolean editable) {
|
||||
this.editable = editable;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.diboot.core.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* 基础CRUD的父类Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface BaseCrudMapper<T> extends BaseMapper<T> {
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.core.mapper;
|
||||
|
||||
import com.diboot.core.entity.Metadata;
|
||||
|
||||
/**
|
||||
* 元数据Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface MetadataMapper extends BaseCrudMapper<Metadata> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.diboot.core.plugin;
|
||||
|
||||
/**
|
||||
* 插件管理器
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2018/10/23
|
||||
*/
|
||||
public interface PluginManager {
|
||||
|
||||
}
|
|
@ -0,0 +1,190 @@
|
|||
package com.diboot.core.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.diboot.core.binding.EntityBinder;
|
||||
import com.diboot.core.binding.EntityListBinder;
|
||||
import com.diboot.core.binding.FieldBinder;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 基础服务Service
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public interface BaseService<T>{
|
||||
|
||||
/**
|
||||
* 获取Entity实体
|
||||
* @param id 主键
|
||||
* @return entity
|
||||
*/
|
||||
T getEntity(Serializable id);
|
||||
|
||||
/**
|
||||
* 创建Entity实体
|
||||
* @param entity
|
||||
* @return true:成功, false:失败
|
||||
*/
|
||||
boolean createEntity(T entity);
|
||||
|
||||
/***
|
||||
* 批量创建Entity
|
||||
* @param entityList 实体对象列表
|
||||
* @return true:成功, false: 失败
|
||||
*/
|
||||
boolean createEntities(Collection<T> entityList);
|
||||
|
||||
/**
|
||||
* 更新Entity实体
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
boolean updateEntity(T entity);
|
||||
|
||||
/**
|
||||
* 更新Entity实体(更新符合条件的所有非空字段)
|
||||
* @param entity
|
||||
* @param updateCriteria
|
||||
* @return
|
||||
*/
|
||||
boolean updateEntity(T entity, Wrapper updateCriteria);
|
||||
|
||||
/**
|
||||
* 更新Entity实体(仅更新updateWrapper.set指定的字段)
|
||||
* @param updateWrapper
|
||||
* @return
|
||||
*/
|
||||
boolean updateEntity(Wrapper updateWrapper);
|
||||
|
||||
/***
|
||||
* 创建或更新entity(entity.id存在则新建,否则更新)
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
boolean createOrUpdateEntity(T entity);
|
||||
|
||||
/**
|
||||
* 根据主键删除实体
|
||||
* @param id 主键
|
||||
* @return true:成功, false:失败
|
||||
*/
|
||||
boolean deleteEntity(Serializable id);
|
||||
|
||||
/**
|
||||
* 按条件删除实体
|
||||
* @param queryWrapper
|
||||
* @return
|
||||
*/
|
||||
boolean deleteEntities(Wrapper queryWrapper) throws Exception;
|
||||
|
||||
/**
|
||||
* 获取符合条件的entity记录总数
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
int getEntityListCount(Wrapper queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取model列表
|
||||
* @param queryWrapper
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
List<T> getEntityList(Wrapper queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取model列表
|
||||
* @param queryWrapper
|
||||
* @param pagination
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
List<T> getEntityList(Wrapper queryWrapper, Pagination pagination);
|
||||
|
||||
/**
|
||||
* 获取指定数量的entity记录
|
||||
* @param queryWrapper
|
||||
* @param limitCount
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
List<T> getEntityListLimit(Wrapper queryWrapper, int limitCount);
|
||||
|
||||
/**
|
||||
* 获取指定属性的Map列表
|
||||
* @param queryWrapper
|
||||
* @return
|
||||
*/
|
||||
List<Map<String, Object>> getMapList(Wrapper queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取指定属性的Map列表
|
||||
* @param queryWrapper
|
||||
* @param pagination
|
||||
* @return
|
||||
*/
|
||||
List<Map<String, Object>> getMapList(Wrapper queryWrapper, Pagination pagination);
|
||||
|
||||
/***
|
||||
* 获取键值对的列表,用于构建select下拉选项等
|
||||
*
|
||||
* @param queryWrapper
|
||||
* @return
|
||||
*/
|
||||
List<KeyValue> getKeyValueList(Wrapper queryWrapper);
|
||||
|
||||
/**
|
||||
* 获取View Object对象
|
||||
* @param id 主键
|
||||
* @param voClass vo类
|
||||
* @return entity
|
||||
*/
|
||||
<VO> VO getViewObject(Serializable id, Class<VO> voClass);
|
||||
|
||||
/**
|
||||
* 获取View Object对象列表
|
||||
* @param entityList
|
||||
* @param voClass vo类
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
<VO> List<VO> getViewObjectList(List<T> entityList, Class<VO> voClass);
|
||||
|
||||
/**
|
||||
* 根据查询条件获取vo列表
|
||||
* @param queryWrapper
|
||||
* @param pagination
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
<VO> List<VO> getViewObjectList(Wrapper queryWrapper, Pagination pagination, Class<VO> voClass);
|
||||
|
||||
/***
|
||||
* 绑定字段值到VO列表的元素中
|
||||
* @param voList
|
||||
* @return
|
||||
*/
|
||||
FieldBinder<T> bindingFieldTo(List voList);
|
||||
|
||||
/***
|
||||
* 绑定entity对象到VO列表元素中
|
||||
* @param voList
|
||||
* @return
|
||||
*/
|
||||
EntityBinder<T> bindingEntityTo(List voList);
|
||||
|
||||
/***
|
||||
* 绑定entity对象列表到VO列表元素中(适用于VO-Entity一对多的关联)
|
||||
* @param voList vo列表
|
||||
* @return
|
||||
*/
|
||||
EntityListBinder<T> bindingEntityListTo(List voList);
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package com.diboot.core.service;
|
||||
|
||||
import com.diboot.core.entity.Metadata;
|
||||
import com.diboot.core.util.IGetter;
|
||||
import com.diboot.core.util.ISetter;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 元数据Service
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public interface MetadataService extends BaseService<Metadata>{
|
||||
|
||||
/***
|
||||
* 获取对应类型的键值对
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
List<KeyValue> getKeyValueList(String type);
|
||||
|
||||
/***
|
||||
* 绑定itemName字段到VoList
|
||||
* @param voList
|
||||
* @param setFieldLabelFn
|
||||
* @param getFieldIdFn
|
||||
* @param <T1>
|
||||
* @param <T2>
|
||||
* @param <S>
|
||||
*/
|
||||
<T1,T2,S> void bindItemLabel(List voList, ISetter<T1, S> setFieldLabelFn,
|
||||
IGetter<T2> getFieldIdFn, String type);
|
||||
|
||||
/***
|
||||
* 绑定itemName字段到VoList
|
||||
* @param voList
|
||||
* @param setFieldName
|
||||
* @param getFieldName
|
||||
*/
|
||||
void bindItemLabel(List voList, String setFieldName, String getFieldName, String type);
|
||||
}
|
|
@ -0,0 +1,292 @@
|
|||
package com.diboot.core.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.diboot.core.binding.manager.AnnotationBindingManager;
|
||||
import com.diboot.core.binding.EntityBinder;
|
||||
import com.diboot.core.binding.EntityListBinder;
|
||||
import com.diboot.core.binding.FieldBinder;
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Pagination;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/***
|
||||
* CRUD通用接口实现类
|
||||
* @author Mazc
|
||||
* @param <M> mapper类
|
||||
* @param <T> entity类
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class BaseServiceImpl<M extends BaseCrudMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {
|
||||
private static final Logger log = LoggerFactory.getLogger(BaseServiceImpl.class);
|
||||
|
||||
/***
|
||||
* VO类与注解的缓存
|
||||
*/
|
||||
private static Map<String, Map<String, Annotation>> CLASS_ANNOTATION_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
/***
|
||||
* 获取当前的Mapper对象
|
||||
* @return
|
||||
*/
|
||||
protected M getMapper(){
|
||||
return baseMapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getEntity(Serializable id){
|
||||
return super.getById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createEntity(T entity) {
|
||||
if(entity == null){
|
||||
warning("createModel", "参数entity为null");
|
||||
return false;
|
||||
}
|
||||
return super.save(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean createEntities(Collection entityList){
|
||||
if(V.isEmpty(entityList)){
|
||||
warning("createEntities", "参数entityList为空!");
|
||||
return false;
|
||||
}
|
||||
// 批量插入
|
||||
return super.saveBatch(entityList, BaseConfig.getBatchSize());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateEntity(T entity) {
|
||||
boolean success = super.updateById(entity);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateEntity(T entity, Wrapper updateWrapper) {
|
||||
boolean success = super.update(entity, updateWrapper);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean updateEntity(Wrapper updateWrapper) {
|
||||
boolean success = super.update(null, updateWrapper);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean createOrUpdateEntity(T entity) {
|
||||
boolean success = super.saveOrUpdate(entity);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteEntity(Serializable id) {
|
||||
boolean success = super.removeById(id);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteEntities(Wrapper queryWrapper) throws Exception{
|
||||
// 执行
|
||||
boolean success = super.remove(queryWrapper);
|
||||
return success;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEntityListCount(Wrapper queryWrapper) {
|
||||
return super.count(queryWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getEntityList(Wrapper queryWrapper) {
|
||||
return getEntityList(queryWrapper, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getEntityList(Wrapper queryWrapper, Pagination pagination) {
|
||||
if(pagination != null){
|
||||
IPage<T> page = convertToIPage(pagination);
|
||||
page = super.page(page, queryWrapper);
|
||||
// 如果重新执行了count进行查询,则更新pagination中的总数
|
||||
if(page.isSearchCount()){
|
||||
pagination.set_totalCount(page.getTotal());
|
||||
}
|
||||
return page.getRecords();
|
||||
}
|
||||
else{
|
||||
List<T> list = super.list(queryWrapper);
|
||||
if(list == null){
|
||||
list = Collections.emptyList();
|
||||
}
|
||||
else if(list.size() > BaseConfig.getBatchSize()){
|
||||
log.warn("单次查询记录数量过大,返回结果数={}", list.size());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> getEntityListLimit(Wrapper queryWrapper, int limitCount) {
|
||||
IPage<T> page = new Page<>(1, limitCount);
|
||||
page = super.page(page, queryWrapper);
|
||||
return page.getRecords();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getMapList(Wrapper queryWrapper) {
|
||||
return getMapList(queryWrapper, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getMapList(Wrapper queryWrapper, Pagination pagination) {
|
||||
if(pagination != null){
|
||||
IPage<T> page = convertToIPage(pagination);
|
||||
IPage<Map<String, Object>> resultPage = super.pageMaps(page, queryWrapper);
|
||||
// 如果重新执行了count进行查询,则更新pagination中的总数
|
||||
if(page.isSearchCount()){
|
||||
pagination.set_totalCount(page.getTotal());
|
||||
}
|
||||
return resultPage.getRecords();
|
||||
}
|
||||
else{
|
||||
List<Map<String, Object>> list = super.listMaps(queryWrapper);
|
||||
if(list == null){
|
||||
list = Collections.emptyList();
|
||||
}
|
||||
else if(list.size() > BaseConfig.getBatchSize()){
|
||||
log.warn("单次查询记录数量过大,返回结果数={}", list.size());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<KeyValue> getKeyValueList(Wrapper queryWrapper) {
|
||||
String sqlSelect = queryWrapper.getSqlSelect();
|
||||
if(V.isEmpty(sqlSelect) || S.countMatches(sqlSelect, Cons.SEPARATOR_COMMA) != 1){
|
||||
log.error("调用错误: getKeyValueList必须用select依次指定返回的键值字段,如: new QueryWrapper<Metadata>().lambda().select(Metadata::getItemName, Metadata::getItemValue)");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 获取mapList
|
||||
List<Map<String, Object>> mapList = super.listMaps(queryWrapper);
|
||||
if(mapList == null){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 转换为Key-Value键值对
|
||||
String[] keyValueArray = sqlSelect.split(Cons.SEPARATOR_COMMA);
|
||||
List<KeyValue> keyValueList = new ArrayList<>(mapList.size());
|
||||
for(Map<String, Object> map : mapList){
|
||||
if(map.get(keyValueArray[0]) != null){
|
||||
KeyValue kv = new KeyValue((String)map.get(keyValueArray[0]), map.get(keyValueArray[1]));
|
||||
keyValueList.add(kv);
|
||||
}
|
||||
}
|
||||
return keyValueList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldBinder<T> bindingFieldTo(List voList){
|
||||
return new FieldBinder<>(this, voList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityBinder<T> bindingEntityTo(List voList){
|
||||
return new EntityBinder<>(this, voList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityListBinder<T> bindingEntityListTo(List voList){
|
||||
return new EntityListBinder<>(this, voList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取View Object对象
|
||||
* @param id 主键
|
||||
* @return entity
|
||||
*/
|
||||
@Override
|
||||
public <VO> VO getViewObject(Serializable id, Class<VO> voClass){
|
||||
T entity = getEntity(id);
|
||||
if(entity == null){
|
||||
return null;
|
||||
}
|
||||
List<T> enityList = new ArrayList<>();
|
||||
enityList.add(entity);
|
||||
// 绑定
|
||||
List<VO> voList = getViewObjectList(enityList, voClass);
|
||||
return voList.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取View Object对象列表
|
||||
* @param entityList
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public <VO> List<VO> getViewObjectList(List<T> entityList, Class<VO> voClass){
|
||||
// 转换为VO列表
|
||||
List<VO> voList = BeanUtils.convertList(entityList, voClass);
|
||||
// 自动绑定关联对象
|
||||
AnnotationBindingManager.autoBind(voList);
|
||||
return voList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <VO> List<VO> getViewObjectList(Wrapper queryWrapper, Pagination pagination, Class<VO> voClass) {
|
||||
List<T> entityList = getEntityList(queryWrapper, null);
|
||||
// 转换为VO列表
|
||||
List<VO> voList = BeanUtils.convertList(entityList, voClass);
|
||||
// 自动绑定关联对象
|
||||
AnnotationBindingManager.autoBind(voList);
|
||||
return voList;
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为IPage
|
||||
* @param pagination
|
||||
* @return
|
||||
*/
|
||||
protected IPage<T> convertToIPage(Pagination pagination){
|
||||
if(pagination == null){
|
||||
return null;
|
||||
}
|
||||
IPage<T> page = new Page<T>()
|
||||
.setCurrent(pagination.get_pageIndex())
|
||||
.setSize(pagination.get_pageSize())
|
||||
// 如果前端传递过来了缓存的总数,则本次不再count统计
|
||||
.setTotal(pagination.get_totalCount() > 0? -1 : pagination.get_totalCount())
|
||||
.setAscs(S.toSnakeCase(pagination.getAscList()))
|
||||
.setDescs(S.toSnakeCase(pagination.getDescList()));
|
||||
return page;
|
||||
}
|
||||
|
||||
/***
|
||||
* 打印警告信息
|
||||
* @param method
|
||||
* @param message
|
||||
*/
|
||||
private void warning(String method, String message){
|
||||
log.warn(this.getClass().getName() + "."+ method +" 调用错误: "+message+", 请检查!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
package com.diboot.core.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.entity.Metadata;
|
||||
import com.diboot.core.mapper.MetadataMapper;
|
||||
import com.diboot.core.service.MetadataService;
|
||||
import com.diboot.core.util.*;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 元数据相关service实现
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
@Service
|
||||
public class MetadataServiceImpl extends BaseServiceImpl<MetadataMapper, Metadata> implements MetadataService{
|
||||
private static final Logger log = LoggerFactory.getLogger(MetadataServiceImpl.class);
|
||||
|
||||
private static final String FIELD_NAME_ITEM_NAME = BeanUtils.convertToFieldName(Metadata::getItemName);
|
||||
private static final String FIELD_NAME_ITEM_VALUE = BeanUtils.convertToFieldName(Metadata::getItemValue);
|
||||
private static final String FIELD_NAME_TYPE = BeanUtils.convertToFieldName(Metadata::getType);
|
||||
private static final String FIELD_NAME_PARENT_ID = BeanUtils.convertToFieldName(Metadata::getParentId);
|
||||
|
||||
@Override
|
||||
public List<KeyValue> getKeyValueList(String type) {
|
||||
// 构建查询条件
|
||||
Wrapper queryMetadata = new QueryWrapper<Metadata>().lambda()
|
||||
.select(Metadata::getItemName, Metadata::getItemValue)
|
||||
.eq(Metadata::getType, type)
|
||||
.gt(Metadata::getParentId, 0);
|
||||
// 返回构建条件
|
||||
return getKeyValueList(queryMetadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T1,T2,S> void bindItemLabel(List voList, ISetter<T1,S> setFieldLabelFn,
|
||||
IGetter<T2> getFieldIdFn, String type){
|
||||
if(V.isEmpty(voList)){
|
||||
return;
|
||||
}
|
||||
bindingFieldTo(voList)
|
||||
.link(Metadata::getItemName, setFieldLabelFn)
|
||||
.joinOn(getFieldIdFn, Metadata::getItemValue)
|
||||
.andEQ(FIELD_NAME_TYPE, type)
|
||||
.andGT(FIELD_NAME_PARENT_ID, 0)
|
||||
.bind();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItemLabel(List voList, String setFieldName, String getFieldName, String type){
|
||||
if(V.isEmpty(voList)){
|
||||
return;
|
||||
}
|
||||
getFieldName = S.toLowerCaseCamel(getFieldName);
|
||||
bindingFieldTo(voList)
|
||||
.link(FIELD_NAME_ITEM_NAME, setFieldName)
|
||||
.joinOn(getFieldName, FIELD_NAME_ITEM_VALUE)
|
||||
.andEQ(FIELD_NAME_TYPE, type)
|
||||
.andGT(FIELD_NAME_PARENT_ID, 0)
|
||||
.bind();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 集合批次迭代
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class BatchIterator<E> implements Iterator<List<E>> {
|
||||
/**
|
||||
* 每批次集合数量
|
||||
*/
|
||||
private int batchSize;
|
||||
/***
|
||||
* 原始list
|
||||
*/
|
||||
private List<E> originalList;
|
||||
private int index = 0;
|
||||
private List<E> result;
|
||||
private int total = 0;
|
||||
|
||||
public BatchIterator(List<E> originalList, int batchSize) {
|
||||
if (batchSize <= 0) {
|
||||
return;
|
||||
}
|
||||
this.batchSize = batchSize;
|
||||
this.originalList = originalList;
|
||||
this.total = V.notEmpty(originalList)? originalList.size() : 0;
|
||||
result = new ArrayList<>(batchSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<E> next() {
|
||||
result.clear();
|
||||
for (int i = 0; i < batchSize && index < total; i++) {
|
||||
result.add(originalList.get(index++));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException("BatchIterator.remove未实现!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,525 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeanWrapper;
|
||||
import org.springframework.beans.PropertyAccessorFactory;
|
||||
import org.springframework.cglib.beans.BeanCopier;
|
||||
|
||||
import java.beans.BeanInfo;
|
||||
import java.beans.Introspector;
|
||||
import java.beans.PropertyDescriptor;
|
||||
import java.io.Serializable;
|
||||
import java.lang.invoke.SerializedLambda;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Bean相关处理工具类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class BeanUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(BeanUtils.class);
|
||||
|
||||
/**
|
||||
* 连接符号
|
||||
*/
|
||||
private static final String CHANGE_FLAG = "->";
|
||||
|
||||
/**
|
||||
* 忽略对比的字段
|
||||
*/
|
||||
private static final Set<String> IGNORE_FIELDS = new HashSet<String>(){{
|
||||
add("createTime");
|
||||
}};
|
||||
|
||||
/***
|
||||
* 缓存BeanCopier
|
||||
*/
|
||||
private static Map<String, BeanCopier> BEAN_COPIER_INST_MAP = new ConcurrentHashMap<>();
|
||||
/***
|
||||
* 缓存类-Lambda的映射关系
|
||||
*/
|
||||
private static Map<Class, SerializedLambda> CLASS_LAMDBA_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
/***
|
||||
* 获取实例
|
||||
* @param source
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
private static BeanCopier getBeanCopierInstance(Object source, Object target){
|
||||
//build key
|
||||
String beanCopierKey = source.getClass().toString() +"_"+ target.getClass().toString();
|
||||
BeanCopier copierInst = BEAN_COPIER_INST_MAP.get(beanCopierKey);
|
||||
if(copierInst == null){
|
||||
copierInst = BeanCopier.create(source.getClass(), target.getClass(), false);
|
||||
BEAN_COPIER_INST_MAP.put(beanCopierKey, copierInst);
|
||||
}
|
||||
return copierInst;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy属性到另一个对象
|
||||
* @param source
|
||||
* @param target
|
||||
*/
|
||||
public static Object copyProperties(Object source, Object target){
|
||||
BeanCopier copierInst = getBeanCopierInstance(source, target);
|
||||
copierInst.copy(source, target, null);
|
||||
return target;
|
||||
}
|
||||
|
||||
/***
|
||||
* 将对象转换为另外的对象实例
|
||||
* @param source
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> T convert(Object source, Class<T> clazz){
|
||||
if(source == null){
|
||||
return null;
|
||||
}
|
||||
T target = null;
|
||||
try{
|
||||
target = clazz.getConstructor().newInstance();
|
||||
copyProperties(source, target);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("对象转换异常, class="+clazz.getName());
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/***
|
||||
* 将对象转换为另外的对象实例
|
||||
* @param sourceList
|
||||
* @param clazz
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> convertList(List sourceList, Class<T> clazz){
|
||||
if(V.isEmpty(sourceList)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<T> resultList = new ArrayList<>();
|
||||
try{
|
||||
for(Object source : sourceList){
|
||||
T target = clazz.getConstructor().newInstance();
|
||||
copyProperties(source, target);
|
||||
resultList.add(target);
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("对象转换异常, class="+clazz.getName());
|
||||
}
|
||||
return resultList;
|
||||
}
|
||||
|
||||
/***
|
||||
* 附加Map中的属性值到Model
|
||||
* @param model
|
||||
* @param propMap
|
||||
*/
|
||||
public static void bindProperties(Object model, Map<String, Object> propMap){
|
||||
try{// 获取类属性
|
||||
BeanInfo beanInfo = Introspector.getBeanInfo(model.getClass());
|
||||
// 给 JavaBean 对象的属性赋值
|
||||
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
||||
for (PropertyDescriptor descriptor : propertyDescriptors) {
|
||||
String propertyName = descriptor.getName();
|
||||
if (propMap.containsKey(propertyName)){
|
||||
Object value = propMap.get(propertyName);
|
||||
Class type = descriptor.getWriteMethod().getParameterTypes()[0];
|
||||
Object[] args = new Object[1];
|
||||
String fieldType = type.getSimpleName();
|
||||
// 类型不一致,需转型
|
||||
if(!value.getClass().getTypeName().equals(fieldType)){
|
||||
if(value instanceof String){
|
||||
// String to Date
|
||||
if(fieldType.equalsIgnoreCase(Date.class.getSimpleName())){
|
||||
args[0] = D.fuzzyConvert((String)value);
|
||||
}
|
||||
// Map中的String型转换为其他型
|
||||
else if(fieldType.equalsIgnoreCase(Boolean.class.getSimpleName())){
|
||||
args[0] = V.isTrue((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Integer.class.getSimpleName()) || "int".equals(fieldType)) {
|
||||
args[0] = Integer.parseInt((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Long.class.getSimpleName())) {
|
||||
args[0] = Long.parseLong((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Double.class.getSimpleName())) {
|
||||
args[0] = Double.parseDouble((String)value);
|
||||
}
|
||||
else if (fieldType.equalsIgnoreCase(Float.class.getSimpleName())) {
|
||||
args[0] = Float.parseFloat((String)value);
|
||||
}
|
||||
else{
|
||||
args[0] = value;
|
||||
log.warn("类型不一致,暂无法自动绑定,请手动转型一致后调用!字段类型="+fieldType);
|
||||
}
|
||||
}
|
||||
else{
|
||||
args[0] = value;
|
||||
log.warn("类型不一致,且Map中的value非String类型,暂无法自动绑定,请手动转型一致后调用!value="+value);
|
||||
}
|
||||
}
|
||||
else{
|
||||
args[0] = value;
|
||||
}
|
||||
descriptor.getWriteMethod().invoke(model, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("复制Map属性到Model异常: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取对象的属性值
|
||||
* @param obj
|
||||
* @param field
|
||||
* @return
|
||||
*/
|
||||
public static Object getProperty(Object obj, String field){
|
||||
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
|
||||
return wrapper.getPropertyValue(field);
|
||||
}
|
||||
|
||||
/***
|
||||
* 设置属性值
|
||||
* @param obj
|
||||
* @param field
|
||||
* @param value
|
||||
*/
|
||||
public static void setProperty(Object obj, String field, Object value) {
|
||||
BeanWrapper wrapper = PropertyAccessorFactory.forBeanPropertyAccess(obj);
|
||||
wrapper.setPropertyValue(field, value);
|
||||
}
|
||||
|
||||
/***
|
||||
* Key-Object对象Map
|
||||
* @param allLists
|
||||
* @return
|
||||
*/
|
||||
public static <T> Map<Object, T> convert2KeyObjectMap(List<T> allLists, String... fields){
|
||||
if(allLists == null || allLists.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
Map<Object, T> allListMap = new LinkedHashMap<>(allLists.size());
|
||||
// 转换为map
|
||||
try{
|
||||
for(T model : allLists){
|
||||
Object key = null;
|
||||
if(V.isEmpty(fields)){
|
||||
//未指定字段,以id为key
|
||||
key = getProperty(model, Cons.FieldName.parentId.name());;
|
||||
}
|
||||
// 指定了一个字段,以该字段为key,类型同该字段
|
||||
else if(fields.length == 1){
|
||||
key = getProperty(model, fields[0]);
|
||||
}
|
||||
else{ // 指定了多个字段,以字段S.join的结果为key,类型为String
|
||||
List list = new ArrayList();
|
||||
for(String fld : fields){
|
||||
list.add(getProperty(model, fld));
|
||||
}
|
||||
key = S.join(list);
|
||||
}
|
||||
if(key != null){
|
||||
allListMap.put(key, model);
|
||||
}
|
||||
else{
|
||||
log.warn(model.getClass().getName() + " 的属性 "+fields[0]+" 值存在 null,BeanUtils.convert2KeyModelMap转换结果需要确认!");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception e){
|
||||
log.warn("转换key-model异常", e);
|
||||
}
|
||||
return allListMap;
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建上下级关联的树形结构的model
|
||||
* @param allModels
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T extends BaseEntity> List<T> buildTree(List<T> allModels){
|
||||
if(V.isEmpty(allModels)){
|
||||
return null;
|
||||
}
|
||||
// 提取所有的top level对象
|
||||
List<T> topLevelModels = new ArrayList();
|
||||
for(T model : allModels){
|
||||
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
|
||||
if(parentId == null || V.fuzzyEqual(parentId, 0)){
|
||||
topLevelModels.add(model);
|
||||
}
|
||||
}
|
||||
if(V.isEmpty(topLevelModels)){
|
||||
return topLevelModels;
|
||||
}
|
||||
// 提取向下一层的对象
|
||||
buildDeeperLevelTree(topLevelModels, allModels);
|
||||
// 返回第一层级节点(二级及以上子级通过children属性获取)
|
||||
return topLevelModels;
|
||||
}
|
||||
|
||||
/***
|
||||
* 构建下一层级树形结构
|
||||
* @param parentModels
|
||||
* @param allModels
|
||||
* @param <T>
|
||||
*/
|
||||
private static <T extends BaseEntity> void buildDeeperLevelTree(List<T> parentModels, List<T> allModels){
|
||||
List<T> deeperLevelModels = new ArrayList();
|
||||
Map<Object, T> parentLevelModelMap = convert2KeyObjectMap(parentModels);
|
||||
for(T model : allModels){
|
||||
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
|
||||
if(parentLevelModelMap.keySet().contains(parentId) && !parentId.equals(model.getId())){
|
||||
deeperLevelModels.add(model);
|
||||
}
|
||||
}
|
||||
if(V.isEmpty(deeperLevelModels)){
|
||||
return;
|
||||
}
|
||||
for(T model : deeperLevelModels){
|
||||
Object parentId = getProperty(model, Cons.FieldName.parentId.name());
|
||||
T parentModel = parentLevelModelMap.get(parentId);
|
||||
if(parentModel!=null){
|
||||
List children = (List) getProperty(parentModel, Cons.FieldName.children.name());
|
||||
if(children == null){
|
||||
children = new ArrayList();
|
||||
setProperty(parentModel, Cons.FieldName.children.name(), children);
|
||||
}
|
||||
children.add(model);
|
||||
}
|
||||
}
|
||||
// 递归进入下一层级
|
||||
buildDeeperLevelTree(deeperLevelModels, allModels);
|
||||
}
|
||||
|
||||
/***
|
||||
* 提取两个model的差异值
|
||||
* @param oldModel
|
||||
* @param newModel
|
||||
* @return
|
||||
*/
|
||||
public static String extractDiff(BaseEntity oldModel, BaseEntity newModel){
|
||||
return extractDiff(oldModel, newModel, null);
|
||||
}
|
||||
|
||||
/***
|
||||
* 提取两个model的差异值,只对比指定字段
|
||||
* @param oldModel
|
||||
* @param newModel
|
||||
* @return
|
||||
*/
|
||||
public static String extractDiff(BaseEntity oldModel, BaseEntity newModel, Set<String> fields){
|
||||
if(newModel == null || oldModel == null){
|
||||
log.warn("调用错误,Model不能为空!");
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> oldMap = oldModel.toMap();
|
||||
Map<String, Object> newMap = newModel.toMap();
|
||||
Map<String, Object> result = new HashMap<>(oldMap.size()+newMap.size());
|
||||
for(Map.Entry<String, Object> entry : oldMap.entrySet()){
|
||||
if(IGNORE_FIELDS.contains(entry.getKey())){
|
||||
continue;
|
||||
}
|
||||
String oldValue = entry.getValue()!=null ? String.valueOf(entry.getValue()) : "";
|
||||
Object newValueObj = newMap.get(entry.getKey());
|
||||
String newValue = newValueObj!=null? String.valueOf(newValueObj) : "";
|
||||
// 设置变更的值
|
||||
boolean checkThisField = fields == null || fields.contains(entry.getKey());
|
||||
if(checkThisField && !oldValue.equals(newValue)){
|
||||
result.put(entry.getKey(), S.join(oldValue, CHANGE_FLAG, newValue));
|
||||
}
|
||||
// 从新的map中移除该key
|
||||
if(newValueObj!=null){
|
||||
newMap.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
if(!newMap.isEmpty()){
|
||||
for(Map.Entry<String, Object> entry : newMap.entrySet()){
|
||||
if(IGNORE_FIELDS.contains(entry.getKey())){
|
||||
continue;
|
||||
}
|
||||
Object newValueObj = entry.getValue();
|
||||
String newValue = newValueObj!=null? String.valueOf(newValueObj) : "";
|
||||
// 设置变更的值
|
||||
if(fields==null || fields.contains(entry.getKey())){
|
||||
result.put(entry.getKey(), S.join("", CHANGE_FLAG, newValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
oldMap = null;
|
||||
newMap = null;
|
||||
// 转换结果为String
|
||||
return JSON.toJSONString(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从list对象列表中提取指定属性值到新的List
|
||||
* @param objectList 对象list
|
||||
* @param getterFn get方法
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <E,T> List collectToList(List<E> objectList, IGetter<T> getterFn){
|
||||
if(V.isEmpty(objectList)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
String getterPropName = convertToFieldName(getterFn);
|
||||
return collectToList(objectList, getterPropName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从list对象列表中提取Id主键值到新的List
|
||||
* @param objectList 对象list
|
||||
* @param <E>
|
||||
* @return
|
||||
*/
|
||||
public static <E> List collectIdToList(List<E> objectList){
|
||||
if(V.isEmpty(objectList)){
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return collectToList(objectList, Cons.FieldName.id.name());
|
||||
}
|
||||
|
||||
/***
|
||||
* 从list对象列表中提取指定属性值到新的List
|
||||
* @param objectList
|
||||
* @param getterPropName
|
||||
* @param <E>
|
||||
* @return
|
||||
*/
|
||||
public static <E> List collectToList(List<E> objectList, String getterPropName){
|
||||
List fieldValueList = new ArrayList();
|
||||
try{
|
||||
for(E object : objectList){
|
||||
Object fieldValue = getProperty(object, getterPropName);
|
||||
if(!fieldValueList.contains(fieldValue)){
|
||||
fieldValueList.add(fieldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("提取属性值异常, getterPropName="+getterPropName, e);
|
||||
}
|
||||
return fieldValueList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 绑定map中的属性值到list
|
||||
* @param setFieldFn
|
||||
* @param getFieldFun
|
||||
* @param fromList
|
||||
* @param valueMatchMap
|
||||
* @param <T1>
|
||||
*/
|
||||
public static <T1,T2,R,E> void bindPropValueOfList(ISetter<T1,R> setFieldFn, List<E> fromList, IGetter<T2> getFieldFun, Map valueMatchMap){
|
||||
if(V.isEmpty(fromList)){
|
||||
return;
|
||||
}
|
||||
// function转换为字段名
|
||||
String setterFieldName = convertToFieldName(setFieldFn), getterFieldName = convertToFieldName(getFieldFun);
|
||||
bindPropValueOfList(setterFieldName, fromList, getterFieldName, valueMatchMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 从对象集合提取某个属性值到list中
|
||||
* @param setterFieldName
|
||||
* @param fromList
|
||||
* @param getterFieldName
|
||||
* @param valueMatchMap
|
||||
* @param <E>
|
||||
*/
|
||||
public static <E> void bindPropValueOfList(String setterFieldName, List<E> fromList, String getterFieldName, Map valueMatchMap){
|
||||
if(V.isEmpty(fromList)){
|
||||
return;
|
||||
}
|
||||
try{
|
||||
for(E object : fromList){
|
||||
// 获取到当前的属性值
|
||||
Object fieldValue = getProperty(object, getterFieldName);
|
||||
// 获取到当前的value
|
||||
Object value = valueMatchMap.get(fieldValue);
|
||||
// 赋值
|
||||
setProperty(object, setterFieldName, value);
|
||||
}
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("设置属性值异常, setterFieldName="+setterFieldName, e);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换方法引用为属性名
|
||||
* @param fn
|
||||
* @return
|
||||
*/
|
||||
public static <T> String convertToFieldName(IGetter<T> fn) {
|
||||
SerializedLambda lambda = getSerializedLambda(fn);
|
||||
String methodName = lambda.getImplMethodName();
|
||||
String prefix = null;
|
||||
if(methodName.startsWith("get")){
|
||||
prefix = "get";
|
||||
}
|
||||
else if(methodName.startsWith("is")){
|
||||
prefix = "is";
|
||||
}
|
||||
if(prefix == null){
|
||||
log.warn("无效的getter方法: "+methodName);
|
||||
}
|
||||
return S.uncapFirst(S.substringAfter(methodName, prefix));
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换方法引用为属性名
|
||||
* @param fn
|
||||
* @return
|
||||
*/
|
||||
public static <T,R> String convertToFieldName(ISetter<T,R> fn) {
|
||||
SerializedLambda lambda = getSerializedLambda(fn);
|
||||
String methodName = lambda.getImplMethodName();
|
||||
if(!methodName.startsWith("set")){
|
||||
log.warn("无效的setter方法: "+methodName);
|
||||
}
|
||||
return S.uncapFirst(S.substringAfter(methodName, "set"));
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取类对应的Lambda
|
||||
* @param fn
|
||||
* @return
|
||||
*/
|
||||
private static SerializedLambda getSerializedLambda(Serializable fn){
|
||||
SerializedLambda lambda = CLASS_LAMDBA_CACHE.get(fn.getClass());
|
||||
if(lambda == null){
|
||||
try{
|
||||
Method method = fn.getClass().getDeclaredMethod("writeReplace");
|
||||
method.setAccessible(Boolean.TRUE);
|
||||
lambda = (SerializedLambda) method.invoke(fn);
|
||||
CLASS_LAMDBA_CACHE.put(fn.getClass(), lambda);
|
||||
}
|
||||
catch (Exception e){
|
||||
log.error("获取SerializedLambda异常, class="+fn.getClass().getSimpleName(), e);
|
||||
}
|
||||
}
|
||||
return lambda;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Spring上下文帮助类
|
||||
* @author Mazhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
@Component
|
||||
@Lazy(false)
|
||||
public class ContextHelper implements ApplicationContextAware {
|
||||
private static final Logger log = LoggerFactory.getLogger(ContextHelper.class);
|
||||
|
||||
/***
|
||||
* ApplicationContext上下文
|
||||
*/
|
||||
private static ApplicationContext APPLICATION_CONTEXT = null;
|
||||
|
||||
/**
|
||||
* Entity-对应的Mapper缓存
|
||||
*/
|
||||
private static Map<String, BaseService> entityToMapperCacheMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
if(APPLICATION_CONTEXT == null){
|
||||
APPLICATION_CONTEXT = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取ApplicationContext上下文
|
||||
*/
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
return APPLICATION_CONTEXT;
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据beanId获取Bean实例
|
||||
* @param beanId
|
||||
* @return
|
||||
*/
|
||||
public static Object getBean(String beanId){
|
||||
return getApplicationContext().getBean(beanId);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取指定类型的单个Bean实例
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public static Object getBean(Class type){
|
||||
return getApplicationContext().getBean(type);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取指定类型的全部实例
|
||||
* @param type
|
||||
* @param <T>
|
||||
* @return
|
||||
*/
|
||||
public static <T> List<T> getBeans(Class<T> type){
|
||||
// 获取所有的定时任务实现类
|
||||
Map<String, T> map = getApplicationContext().getBeansOfType(type);
|
||||
if(V.isEmpty(map)){
|
||||
return null;
|
||||
}
|
||||
List<T> beanList = new ArrayList<>();
|
||||
beanList.addAll(map.values());
|
||||
return beanList;
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据注解获取beans
|
||||
* @param annotationType
|
||||
* @return
|
||||
*/
|
||||
public static List<Object> getBeansByAnnotation(Class<? extends Annotation> annotationType){
|
||||
Map<String, Object> map = getApplicationContext().getBeansWithAnnotation(annotationType);
|
||||
if(V.isEmpty(map)){
|
||||
return null;
|
||||
}
|
||||
List<Object> beanList = new ArrayList<>();
|
||||
beanList.addAll(map.values());
|
||||
return beanList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Entity获取对应的Service
|
||||
* @param entity
|
||||
* @return
|
||||
*/
|
||||
public static BaseService getServiceByEntity(Class entity){
|
||||
if(entityToMapperCacheMap.isEmpty()){
|
||||
Map<String, BaseService> serviceMap = getApplicationContext().getBeansOfType(BaseService.class);
|
||||
if(V.notEmpty(serviceMap)){
|
||||
for(Map.Entry<String, BaseService> entry : serviceMap.entrySet()){
|
||||
String entityClassName = getEntityClassByServiceImpl(entry.getValue().getClass());
|
||||
if(V.notEmpty(entityClassName)){
|
||||
entityToMapperCacheMap.put(entityClassName, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return entityToMapperCacheMap.get(entity.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Service实现类的bean解析出Entity类名
|
||||
* @param currentClass
|
||||
* @return
|
||||
*/
|
||||
private static String getEntityClassByServiceImpl(Class currentClass){
|
||||
ResolvableType superType = ResolvableType.forClass(currentClass).getSuperType();
|
||||
ResolvableType[] genericsTypes = superType.getSuperType().getGenerics();
|
||||
if(V.notEmpty(genericsTypes) && genericsTypes.length >= 2){
|
||||
log.debug("Entity-Service: {} -> {}", genericsTypes[1].toString(), currentClass.getName());
|
||||
return genericsTypes[1].toString();
|
||||
}
|
||||
else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,323 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 提供常用的日期操作的工具类
|
||||
* @author MaZhicheng
|
||||
* @version 2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class D extends DateUtils{
|
||||
private static final Logger log = LoggerFactory.getLogger(DateUtils.class);
|
||||
|
||||
/***
|
||||
* 日期时间格式
|
||||
*/
|
||||
public static final String FORMAT_DATE_y2M = "yyMM";
|
||||
public static final String FORMAT_DATE_y2Md = "yyMMdd";
|
||||
public static final String FORMAT_DATE_y4 = "yyyy";
|
||||
public static final String FORMAT_DATE_y4Md = "yyyyMMdd";
|
||||
public static final String FORMAT_DATE_Y4MD = "yyyy-MM-dd";
|
||||
public static final String FORMAT_TIMESTAMP = "yyMMddhhmmss";
|
||||
public static final String FORMAT_TIME_HHmm = "HH:mm";
|
||||
public static final String FORMAT_TIME_HHmmss = "HH:mm:ss";
|
||||
public static final String FORMAT_DATETIME_Y4MDHM = "yyyy-MM-dd HH:mm";
|
||||
public static final String FORMAT_DATETIME_Y4MDHMS = "yyyy-MM-dd HH:mm:ss";
|
||||
/***
|
||||
* 星期
|
||||
*/
|
||||
protected static final String[] WEEK = new String[]{"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
|
||||
|
||||
/***
|
||||
* 当前的日期时间
|
||||
* @return format指定格式的日期时间
|
||||
*/
|
||||
public static String now(String format){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(format);
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前日期时间串
|
||||
* @return yyMMddhhmmss
|
||||
*/
|
||||
public static String toTimestamp(Date date){
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_TIMESTAMP);
|
||||
return sdf.format(date.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取月份
|
||||
* @return
|
||||
*/
|
||||
public static String getMonth(){
|
||||
return now(FORMAT_DATE_y2M);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取今天的日期
|
||||
* @return yyyyMMdd
|
||||
*/
|
||||
public static String today(){
|
||||
return now(FORMAT_DATE_y4Md);
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换字符串为日期date
|
||||
* @param datetime
|
||||
* @param fmt
|
||||
* @return
|
||||
*/
|
||||
public static Date convert2FormatDate(String datetime, String fmt){
|
||||
if (StringUtils.isBlank(datetime)){
|
||||
return null;
|
||||
}
|
||||
SimpleDateFormat format = new SimpleDateFormat(fmt);
|
||||
try {
|
||||
Date date = format.parse(datetime);
|
||||
return date;
|
||||
}
|
||||
catch (ParseException e) {
|
||||
log.warn("日期格式转换异常");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换date为格式化字符串
|
||||
* @param date
|
||||
* @param fmt
|
||||
* @return
|
||||
*/
|
||||
public static String convert2FormatString(Date date, String fmt) {
|
||||
if (date == null) {
|
||||
return null;
|
||||
} else {
|
||||
SimpleDateFormat format = new SimpleDateFormat(fmt);
|
||||
return format.format(date);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取格式化的日期
|
||||
* @param date 基准日期
|
||||
* @param daysOffset 偏移量
|
||||
* @return yyyy-MM-dd
|
||||
*/
|
||||
public static String getDate(Date date, int... daysOffset){
|
||||
if(date == null){
|
||||
date = new Date();
|
||||
}
|
||||
if(daysOffset != null && daysOffset.length > 0){
|
||||
date = addDays(date, daysOffset[0]);
|
||||
}
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE_Y4MD);
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取格式化的日期时间
|
||||
* @param date
|
||||
* @return yyyy-MM-dd HH:mm
|
||||
*/
|
||||
public static String getDateTime(Date date, int... daysOffset){
|
||||
if(date == null){
|
||||
date = new Date();
|
||||
}
|
||||
if(daysOffset != null && daysOffset.length > 0){
|
||||
date = addDays(date, daysOffset[0]);
|
||||
}
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATETIME_Y4MDHM);
|
||||
return sdf.format(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是工作时间段,用于后台程序等
|
||||
* @return
|
||||
*/
|
||||
public static boolean isWorkingTime(){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
int hour = cal.get(Calendar.HOUR_OF_DAY);
|
||||
return (hour >= 8 && hour < 20);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取上午/下午
|
||||
* @return
|
||||
*/
|
||||
public static String getAmPm() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
int hours = c.get(Calendar.HOUR_OF_DAY);
|
||||
if (hours <= 9){
|
||||
return "早上";
|
||||
}
|
||||
else if (9 < hours && hours <= 12){
|
||||
return "上午";
|
||||
}
|
||||
else if (12 < hours && hours <= 13){
|
||||
return "中午";
|
||||
}
|
||||
else if (13 < hours && hours <= 18){
|
||||
return "下午";
|
||||
}
|
||||
else{
|
||||
return "晚上";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前的年月YYMM,用于生成文件夹名称
|
||||
* @return
|
||||
*/
|
||||
public static String getYearMonth(){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE_y2M);
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前的年月YYMM,用于生成文件夹
|
||||
* @return
|
||||
*/
|
||||
public static String getYearMonthDay(){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(FORMAT_DATE_y2Md);
|
||||
return sdf.format(cal.getTime());
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前的年月YYMM,用于生成文件夹
|
||||
* @return
|
||||
*/
|
||||
public static int getDay(){
|
||||
Calendar cal = Calendar.getInstance();
|
||||
return cal.get(Calendar.DAY_OF_MONTH);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取日期对应的星期
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static String getWeek(Date date){
|
||||
return WEEK[Calendar.getInstance().get(Calendar.DAY_OF_WEEK)];
|
||||
}
|
||||
|
||||
/**
|
||||
* 毫秒数转date
|
||||
* @param timeMillis
|
||||
* @return
|
||||
*/
|
||||
public static Date timeMillis2Date(Long timeMillis){
|
||||
return new Date(timeMillis);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串时间戳转日期
|
||||
* @param value
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Date datetimeString2Date(String value){
|
||||
return convert2DateTime(value, FORMAT_DATETIME_Y4MDHMS);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串时间戳转日期
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Date convert2Date(String date){
|
||||
return convert2FormatDate(date, FORMAT_DATE_Y4MD);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串时间戳转日期
|
||||
* @param dateTime
|
||||
* @return
|
||||
* @throws ParseException
|
||||
*/
|
||||
public static Date convert2DateTime(String dateTime, String... dateFormat){
|
||||
String f = FORMAT_DATETIME_Y4MDHM;
|
||||
if(dateFormat != null && dateFormat.length > 0){
|
||||
f = dateFormat[0];
|
||||
}
|
||||
return convert2FormatDate(dateTime, f);
|
||||
}
|
||||
|
||||
/***
|
||||
* 模糊转换日期
|
||||
* @param dateString
|
||||
* @return
|
||||
*/
|
||||
public static Date fuzzyConvert(String dateString){
|
||||
if(V.isEmpty(dateString)){
|
||||
return null;
|
||||
}
|
||||
// 清洗
|
||||
if(dateString.contains("-")){
|
||||
}
|
||||
else if(dateString.contains("月")){
|
||||
dateString = dateString.replaceAll("年", "-").replaceAll("月", "-").replaceAll("日", "").replaceAll("号", "");
|
||||
}
|
||||
else{
|
||||
dateString = dateString.replaceAll("\\/", "-").replaceAll("\\.", "-");
|
||||
}
|
||||
String[] parts = dateString.split(" ");
|
||||
String[] ymd = parts[0].split("-");
|
||||
if(ymd.length >= 3){
|
||||
if(ymd[0].length() == 2){
|
||||
ymd[0] = String.valueOf(Calendar.getInstance().get(Calendar.YEAR)).substring(0, 2) + ymd[0];
|
||||
}
|
||||
if(ymd[1].length() == 1){
|
||||
ymd[1] = "0" + ymd[1];
|
||||
}
|
||||
if(ymd[2].length() == 1){
|
||||
ymd[2] = "0" + ymd[2];
|
||||
}
|
||||
}
|
||||
parts[0] = S.join(ymd, "-");
|
||||
if(parts.length == 1){
|
||||
return D.convert2FormatDate(parts[0], D.FORMAT_DATE_Y4MD);
|
||||
}
|
||||
// 18:20:30:103
|
||||
String[] hmsArray = new String[3];
|
||||
String[] hms = parts[1].split(":");
|
||||
if(hms[0].length() == 1){
|
||||
hms[0] = "0" + hms[0];
|
||||
}
|
||||
hmsArray[0] = hms[0];
|
||||
if(hms.length >= 2){
|
||||
if(hms[1].length() == 1){
|
||||
hms[1] = "0" + hms[1];
|
||||
}
|
||||
hmsArray[1] = hms[1];
|
||||
}
|
||||
else{
|
||||
hmsArray[1] = "00";
|
||||
}
|
||||
if(hms.length >= 3){
|
||||
if(hms[2].length() == 1){
|
||||
hms[2] = "0" + hms[2];
|
||||
}
|
||||
hmsArray[2] = hms[2];
|
||||
}
|
||||
else{
|
||||
hmsArray[2] = "00";
|
||||
}
|
||||
parts[1] = S.join(hmsArray, ":");
|
||||
return D.convert2FormatDate(S.join(parts, " "), D.FORMAT_DATETIME_Y4MDHMS);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Spring表单自动绑定到Java属性时的日期格式转换
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class DateConverter implements Converter<String, Date> {
|
||||
private static final Logger log = LoggerFactory.getLogger(DateConverter.class);
|
||||
|
||||
@Override
|
||||
public Date convert(String dateString) {
|
||||
return D.fuzzyConvert(dateString);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 加解密工具类 (提供AES加解密,MD5多次哈希...)
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class Encryptor {
|
||||
private static final Logger log = LoggerFactory.getLogger(Encryptor.class);
|
||||
|
||||
private static final String KEY_ALGORITHM = "AES";
|
||||
private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5PADDING";
|
||||
private static final String KEY_DEFAULT = V.notEmpty(BaseConfig.getProperty("diboot.encryptor.seed"))? BaseConfig.getProperty("diboot.encryptor.seed") : "Dibo2017M";
|
||||
private static final String KEY_FILL = "abcdefghijklmnop";
|
||||
// 加密Cipher缓存
|
||||
private static Map<String, Cipher> encryptorMap = new ConcurrentHashMap<>();
|
||||
// 解密Cipher缓存
|
||||
private static Map<String, Cipher> decryptorMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* 加密字符串(可指定加密密钥)
|
||||
* @param input 待加密文本
|
||||
* @param key 密钥(可选)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String encrypt(String input, String... key){
|
||||
String seedKey = V.notEmpty(key)? key[0] : KEY_DEFAULT;
|
||||
try{
|
||||
Cipher cipher = getEncryptor(seedKey);
|
||||
byte[] enBytes = cipher.doFinal(input.getBytes());
|
||||
return Base64.getEncoder().encodeToString(enBytes);
|
||||
}
|
||||
catch(Exception e){
|
||||
log.error("加密出错:"+input, e);
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密字符串
|
||||
* @param input 待解密文本
|
||||
* @param key 加密key(可选)
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static String decrypt(String input, String... key){
|
||||
if(V.isEmpty(input)){
|
||||
return input;
|
||||
}
|
||||
String seedKey = V.notEmpty(key)? key[0] : KEY_DEFAULT;
|
||||
try{
|
||||
Cipher cipher = getDecryptor(seedKey);
|
||||
byte[] deBytes = Base64.getDecoder().decode(input.getBytes());
|
||||
return new String(cipher.doFinal(deBytes));
|
||||
}
|
||||
catch(Exception e){
|
||||
log.error("解密出错:"+input, e);
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取指定key的加密器
|
||||
* @param key 加密密钥
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Cipher getEncryptor(String key) throws Exception{
|
||||
byte[] keyBytes = getKey(key);
|
||||
Cipher encryptor = encryptorMap.get(new String(keyBytes));
|
||||
if(encryptor == null){
|
||||
SecretKeySpec skeyspec = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
|
||||
encryptor = Cipher.getInstance(CIPHER_ALGORITHM);
|
||||
encryptor.init(Cipher.ENCRYPT_MODE, skeyspec);
|
||||
// 放入缓存
|
||||
encryptorMap.put(key, encryptor);
|
||||
}
|
||||
return encryptor;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取指定key的解密器
|
||||
* @param key 解密密钥
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private static Cipher getDecryptor(String key) throws Exception{
|
||||
byte[] keyBytes = getKey(key);
|
||||
Cipher decryptor = encryptorMap.get(new String(keyBytes));
|
||||
if(decryptor == null){
|
||||
SecretKeySpec skeyspec = new SecretKeySpec(keyBytes, KEY_ALGORITHM);
|
||||
decryptor = Cipher.getInstance(CIPHER_ALGORITHM);
|
||||
decryptor.init(Cipher.DECRYPT_MODE, skeyspec);
|
||||
// 放入缓存
|
||||
decryptorMap.put(key, decryptor);
|
||||
}
|
||||
return decryptor;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取key,如非16位则调整为16位
|
||||
* @param seed
|
||||
* @return
|
||||
*/
|
||||
private static byte[] getKey(String seed){
|
||||
if(V.isEmpty(seed)){
|
||||
seed = KEY_DEFAULT;
|
||||
}
|
||||
if(seed.length() < 16){
|
||||
seed = seed + S.cut(KEY_FILL, 16-seed.length());
|
||||
}
|
||||
else if(seed.length() > 16){
|
||||
seed = S.cut(KEY_FILL, 16);
|
||||
}
|
||||
return seed.getBytes();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* getter方法接口定义
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/15
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface IGetter<T> extends Serializable {
|
||||
Object apply(T source);
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* setter方法接口定义
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/17
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ISetter<T, U> extends Serializable {
|
||||
void accept(T t, U u);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.serializer.SerializeConfig;
|
||||
import com.alibaba.fastjson.serializer.SimpleDateFormatSerializer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/***
|
||||
* JSON操作辅助类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class JSON extends JSONObject{
|
||||
private static final Logger log = LoggerFactory.getLogger(JSON.class);
|
||||
|
||||
private static SerializeConfig serializeConfig = new SerializeConfig();
|
||||
static {
|
||||
serializeConfig.put(Date.class, new SimpleDateFormatSerializer(D.FORMAT_DATETIME_Y4MDHM));
|
||||
}
|
||||
|
||||
public static String stringify(Object object){
|
||||
return toJSONString(object, serializeConfig);
|
||||
}
|
||||
|
||||
/***
|
||||
* 将JSON字符串转换为java对象
|
||||
* @param jsonStr
|
||||
* @return
|
||||
*/
|
||||
public static Map toMap(String jsonStr){
|
||||
return parseObject(jsonStr);
|
||||
}
|
||||
|
||||
/***
|
||||
* 将JSON字符串转换为java对象
|
||||
* @param jsonStr
|
||||
* @return
|
||||
*/
|
||||
public static LinkedHashMap toLinkedHashMap(String jsonStr){
|
||||
if(V.isEmpty(jsonStr)){
|
||||
return null;
|
||||
}
|
||||
return toJavaObject(jsonStr, LinkedHashMap.class);
|
||||
}
|
||||
|
||||
/***
|
||||
* 将JSON字符串转换为java对象
|
||||
* @param jsonStr
|
||||
* @param clazz
|
||||
* @return
|
||||
*/
|
||||
public static <T> T toJavaObject(String jsonStr, Class<T> clazz){
|
||||
return JSONObject.parseObject(jsonStr, clazz);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.config.PropertiesFactoryBean;
|
||||
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 配置文件工具类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class PropertiesUtils {
|
||||
private static final Logger log = LoggerFactory.getLogger(PropertiesUtils.class);
|
||||
|
||||
/***
|
||||
* 缓存多个资源文件
|
||||
*/
|
||||
private static Map<String, Properties> allPropertiesMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* 默认资源文件名称
|
||||
*/
|
||||
private static final String DEFAULT_PROPERTIES_NAME = "application.properties";
|
||||
|
||||
/***
|
||||
* Properties配置工厂类
|
||||
*/
|
||||
private static PropertiesFactoryBean pfb = new PropertiesFactoryBean();
|
||||
|
||||
/***
|
||||
* 获取指定的配置文件
|
||||
* @return
|
||||
*/
|
||||
private static Properties getProperties(String... propertiesFileNameArgs){
|
||||
// 获取文件名
|
||||
String propFileName = getPropertiesFileName(propertiesFileNameArgs);
|
||||
// 从缓存读取
|
||||
Properties props = allPropertiesMap.get(propFileName);
|
||||
if(props == null){
|
||||
if(propFileName.endsWith(".properties")){
|
||||
pfb.setLocation(new ClassPathResource(propFileName));
|
||||
try{
|
||||
pfb.afterPropertiesSet();
|
||||
props = pfb.getObject();
|
||||
}
|
||||
catch (Exception e){
|
||||
log.warn("无法找到配置文件: " + propFileName, e);
|
||||
}
|
||||
}
|
||||
else if(propFileName.endsWith(".yaml")){
|
||||
props = yamlToProperties(propFileName);
|
||||
}
|
||||
if(props != null){
|
||||
allPropertiesMap.put(propFileName, props);
|
||||
}
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
/***
|
||||
* 读取配置项的值
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static String get(String key, String... propertiesFileName){
|
||||
// 获取文件名
|
||||
String propFileName = getPropertiesFileName(propertiesFileName);
|
||||
// 获取配置值
|
||||
String value = getConfigValueFromPropFile(key, propFileName);
|
||||
if(value == null && DEFAULT_PROPERTIES_NAME.equals(propFileName)){
|
||||
// 如果是默认配置,读取不到再尝试从当前profile配置中读取
|
||||
String profile = getConfigValueFromPropFile("spring.profiles.active", DEFAULT_PROPERTIES_NAME);
|
||||
if(V.notEmpty(profile)){
|
||||
value = getConfigValueFromPropFile(key, S.substringBeforeLast(DEFAULT_PROPERTIES_NAME, ".") + "-"+profile+".properties");
|
||||
}
|
||||
}
|
||||
if(value == null){
|
||||
log.trace("配置文件 {} 中未找到配置项: {}", propertiesFileName, key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/***
|
||||
* 读取int型的配置项
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
public static Integer getInteger(String key, String... propertiesFileName){
|
||||
// 获取文件名
|
||||
String propFileName = getPropertiesFileName(propertiesFileName);
|
||||
// 获取配置值
|
||||
String value = get(key, propFileName);
|
||||
if(V.notEmpty(value)){
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
log.trace("配置文件 {} 中未找到配置项: {}", propertiesFileName, key);
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 读取boolean值的配置项
|
||||
*/
|
||||
public static boolean getBoolean(String key, String... propertiesFileName) {
|
||||
// 获取文件名
|
||||
String propFileName = getPropertiesFileName(propertiesFileName);
|
||||
// 获取配置值
|
||||
String value = get(key, propFileName);
|
||||
if(V.notEmpty(value)){
|
||||
return V.isTrue(value);
|
||||
}
|
||||
log.trace("配置文件 "+(V.notEmpty(propertiesFileName)? propertiesFileName[0] : "")+" 中未找到配置项: "+key + ", 启用默认值 false.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取配置文件名称
|
||||
* @param propertiesFileName
|
||||
* @return
|
||||
*/
|
||||
private static String getPropertiesFileName(String... propertiesFileName){
|
||||
// 获取文件名
|
||||
if(propertiesFileName != null && propertiesFileName.length > 0){
|
||||
return propertiesFileName[0];
|
||||
}
|
||||
else{
|
||||
return DEFAULT_PROPERTIES_NAME;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 从配置文件中读取配置值
|
||||
* @param key
|
||||
* @param propertiesFileName
|
||||
* @return
|
||||
*/
|
||||
private static String getConfigValueFromPropFile(String key, String propertiesFileName){
|
||||
// 获取配置值
|
||||
Properties properties = getProperties(propertiesFileName);
|
||||
if(properties != null){
|
||||
if(properties.containsKey(key)){
|
||||
String value = properties.getProperty(key);
|
||||
// 任何password相关的参数需解密
|
||||
boolean isSensitiveConfig = key.contains(".password") || key.contains(".secret");
|
||||
if(value != null && isSensitiveConfig){
|
||||
value = Encryptor.decrypt(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取yaml并转换为Properties
|
||||
* @param yamlSource
|
||||
* @return
|
||||
*/
|
||||
private static Properties yamlToProperties(String yamlSource) {
|
||||
try {
|
||||
YamlPropertiesFactoryBean yaml = new YamlPropertiesFactoryBean();
|
||||
yaml.setResources(new ClassPathResource(yamlSource));
|
||||
return yaml.getObject();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Cannot read yaml "+yamlSource, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.config.Cons;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
|
||||
/***
|
||||
* String 操作类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class S extends StringUtils{
|
||||
/***
|
||||
* 默认分隔符 ,
|
||||
*/
|
||||
public static final String SEPARATOR = ",";
|
||||
|
||||
/***
|
||||
* 裁剪字符串,显示前部分+...
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static String cut(String input){
|
||||
return cut(input, BaseConfig.getCutLength());
|
||||
}
|
||||
|
||||
/***
|
||||
* 裁剪字符串,显示前部分+...
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static String cut(String input, int cutLength){
|
||||
return substring(input, 0, cutLength);
|
||||
}
|
||||
|
||||
/***
|
||||
* 将list拼接成string,默认分隔符:,
|
||||
* @param stringList
|
||||
* @return
|
||||
*/
|
||||
public static String join(List<String> stringList){
|
||||
return StringUtils.join(stringList, SEPARATOR);
|
||||
}
|
||||
|
||||
/***
|
||||
* 将list拼接成string,默认分隔符:,
|
||||
* @param stringArray
|
||||
* @return
|
||||
*/
|
||||
public static String join(String[] stringArray){
|
||||
return StringUtils.join(stringArray, SEPARATOR);
|
||||
}
|
||||
|
||||
/***
|
||||
* 按,拆分字符串
|
||||
* @param joinedStr
|
||||
* @return
|
||||
*/
|
||||
public static String[] split(String joinedStr){
|
||||
if(joinedStr == null){
|
||||
return null;
|
||||
}
|
||||
return joinedStr.split(SEPARATOR);
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为String数组(避免转型异常)
|
||||
* @param stringList
|
||||
* @return
|
||||
*/
|
||||
public static String[] toStringArray(List<String> stringList){
|
||||
String[] array = new String[stringList.size()];
|
||||
for(int i=0; i<stringList.size(); i++){
|
||||
array[i] = stringList.get(i);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换成蛇形命名(用于Java属性转换为数据库列名)
|
||||
* @param camelCaseStrArray
|
||||
* @return
|
||||
*/
|
||||
public static String[] toSnakeCase(String[] camelCaseStrArray){
|
||||
if(camelCaseStrArray == null){
|
||||
return null;
|
||||
}
|
||||
String[] snakeCaseArray = new String[camelCaseStrArray.length];
|
||||
for(int i=0; i<camelCaseStrArray.length; i++){
|
||||
snakeCaseArray[i] = toSnakeCase(camelCaseStrArray[i]);
|
||||
}
|
||||
return snakeCaseArray;
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换成蛇形命名(用于Java属性转换为数据库列名)
|
||||
* @param camelCaseStrArray
|
||||
* @return
|
||||
*/
|
||||
public static List<String> toSnakeCase(List<String> camelCaseStrArray){
|
||||
if(camelCaseStrArray == null){
|
||||
return null;
|
||||
}
|
||||
List<String> snakeCaseList = new ArrayList<>(camelCaseStrArray.size());
|
||||
for(String camelCaseStr : camelCaseStrArray){
|
||||
snakeCaseList.add(toSnakeCase(camelCaseStr));
|
||||
}
|
||||
return snakeCaseList;
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换成蛇形命名(用于Java属性转换为数据库列名)
|
||||
* @param camelCaseStr
|
||||
* @return
|
||||
*/
|
||||
public static String toSnakeCase(String camelCaseStr){
|
||||
if(V.isEmpty(camelCaseStr)){
|
||||
return null;
|
||||
}
|
||||
char[] chars = camelCaseStr.toCharArray();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c : chars){
|
||||
if(Character.isUpperCase(c)){
|
||||
if(sb.length() > 0){
|
||||
sb.append(Cons.SEPARATOR_UNDERSCORE);
|
||||
}
|
||||
sb.append(Character.toLowerCase(c));
|
||||
}
|
||||
else{
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换成首字母小写的驼峰命名(用于数据库列名转换为Java属性)
|
||||
* @param snakeCaseStr
|
||||
* @return
|
||||
*/
|
||||
public static String toLowerCaseCamel(String snakeCaseStr){
|
||||
if(V.isEmpty(snakeCaseStr)){
|
||||
return null;
|
||||
}
|
||||
// 不包含_,直接return
|
||||
if(!snakeCaseStr.contains(Cons.SEPARATOR_UNDERSCORE)){
|
||||
return snakeCaseStr;
|
||||
}
|
||||
char[] chars = snakeCaseStr.toCharArray();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
boolean upperCase = false;
|
||||
for (char c : chars){
|
||||
if(Cons.SEPARATOR_UNDERSCORE.equals(Character.toString(c))){
|
||||
upperCase = true;
|
||||
continue;
|
||||
}
|
||||
if(upperCase){
|
||||
sb.append(Character.toUpperCase(c));
|
||||
upperCase = false;
|
||||
}
|
||||
else{
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为Long类型(判空,避免NPE)
|
||||
* @param strValue
|
||||
* @return
|
||||
*/
|
||||
public static Long toLong(String strValue){
|
||||
return toLong(strValue, null);
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为Long类型(判空,避免NPE)
|
||||
* @param strValue 字符类型值
|
||||
* @param defaultLong 默认值
|
||||
* @return
|
||||
*/
|
||||
public static Long toLong(String strValue, Long defaultLong){
|
||||
if(V.isEmpty(strValue)){
|
||||
return defaultLong;
|
||||
}
|
||||
return Long.parseLong(strValue);
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为Integer类型(判空,避免NPE)
|
||||
* @param strValue
|
||||
* @return
|
||||
*/
|
||||
public static Integer toInt(String strValue){
|
||||
return toInt(strValue, null);
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为Integer类型(判空,避免NPE)
|
||||
* @param strValue
|
||||
* @param defaultInt 默认值
|
||||
* @return
|
||||
*/
|
||||
public static Integer toInt(String strValue, Integer defaultInt){
|
||||
if(V.isEmpty(strValue)){
|
||||
return defaultInt;
|
||||
}
|
||||
return Integer.parseInt(strValue);
|
||||
}
|
||||
|
||||
/***
|
||||
* 字符串转换为boolean
|
||||
* @param strValue
|
||||
* @return
|
||||
*/
|
||||
public static boolean toBoolean(String strValue){
|
||||
return toBoolean(strValue, false);
|
||||
}
|
||||
|
||||
/***
|
||||
* 字符串转换为boolean
|
||||
* @param strValue
|
||||
* @param defaultBoolean
|
||||
* @return
|
||||
*/
|
||||
public static boolean toBoolean(String strValue, boolean defaultBoolean){
|
||||
if(V.notEmpty(strValue)){
|
||||
return V.isTrue(strValue);
|
||||
}
|
||||
return defaultBoolean;
|
||||
}
|
||||
|
||||
/***
|
||||
* 将多个空格替换为一个
|
||||
* @param input
|
||||
* @return
|
||||
*/
|
||||
public static String removeDuplicateBlank(String input){
|
||||
if(V.isEmpty(input)){
|
||||
return input;
|
||||
}
|
||||
return input.trim().replaceAll(" +", " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得随机串
|
||||
* @return
|
||||
*/
|
||||
public static String newUuid() {
|
||||
return UUID.randomUUID().toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
/***
|
||||
* 生成指定位数的数字/验证码
|
||||
*/
|
||||
private static final String NUMBER_SET = "12345678901";
|
||||
private static Random random = new Random();
|
||||
public static String newRandomNum(int length){
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(NUMBER_SET.charAt(random.nextInt(9)));
|
||||
for(int i=1; i<length; i++){
|
||||
sb.append(NUMBER_SET.charAt(random.nextInt(10)));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/***
|
||||
* 将首字母转为小写
|
||||
* @return
|
||||
*/
|
||||
public static String uncapFirst(String input){
|
||||
if(input != null){
|
||||
return String.valueOf(input.charAt(0)).toLowerCase() + input.substring(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 将首字母转为大写
|
||||
* @return
|
||||
*/
|
||||
public static String capFirst(String input){
|
||||
if(input != null){
|
||||
return String.valueOf(input.charAt(0)).toUpperCase() + input.substring(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 批量替换关键字
|
||||
* @param text
|
||||
* @param searchList
|
||||
* @param replacementList
|
||||
* @return
|
||||
*/
|
||||
public static String replaceEach(String text, List<String> searchList, List<String> replacementList){
|
||||
if(V.isEmpty(searchList) || V.isEmpty(replacementList)){
|
||||
return text;
|
||||
}
|
||||
String[] searchArray = searchList.toArray(new String[searchList.size()]);
|
||||
String[] replacementArray = replacementList.toArray(new String[replacementList.size()]);
|
||||
return replaceEach(text, searchArray, replacementArray);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,377 @@
|
|||
package com.diboot.core.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.*;
|
||||
|
||||
/***
|
||||
* Validator校验类
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*
|
||||
*/
|
||||
public class V {
|
||||
private static final Logger log = LoggerFactory.getLogger(V.class);
|
||||
|
||||
/***
|
||||
* 对象是否为空
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public static boolean isEmpty(Object obj){
|
||||
return obj == null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 字符串是否为空
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static boolean isEmpty(String value){
|
||||
return S.isBlank(value);
|
||||
}
|
||||
|
||||
/***
|
||||
* 字符串数组是否不为空
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public static boolean isEmpty(String[] values){
|
||||
return values == null || values.length == 0;
|
||||
}
|
||||
|
||||
/***
|
||||
* 集合为空
|
||||
* @param list
|
||||
* @return
|
||||
*/
|
||||
public static <T> boolean isEmpty(Collection<T> list) {
|
||||
return list == null || list.isEmpty();
|
||||
}
|
||||
|
||||
/***
|
||||
* Map为空
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public static boolean isEmpty(Map obj){
|
||||
return obj == null || obj.isEmpty();
|
||||
}
|
||||
|
||||
/***
|
||||
* 对象是否为空
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEmpty(Object obj){
|
||||
return obj != null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 字符串是否不为空
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEmpty(String value){
|
||||
return S.isNotBlank(value);
|
||||
}
|
||||
|
||||
/***
|
||||
* 字符串数组是否不为空
|
||||
* @param values
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEmpty(String[] values){
|
||||
return values != null && values.length > 0;
|
||||
}
|
||||
|
||||
/***
|
||||
* 集合不为空
|
||||
* @param list
|
||||
* @return
|
||||
*/
|
||||
public static <T> boolean notEmpty(Collection<T> list) {
|
||||
return list != null && !list.isEmpty();
|
||||
}
|
||||
|
||||
/***
|
||||
* 对象不为空且不为0
|
||||
* @param longObj
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEmptyOrZero(Long longObj){
|
||||
return longObj != null && longObj.longValue() != 0;
|
||||
}
|
||||
|
||||
/***
|
||||
* 对象不为空且不为0
|
||||
* @param intObj
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEmptyOrZero(Integer intObj){
|
||||
return intObj != null && intObj.intValue() != 0;
|
||||
}
|
||||
|
||||
/***
|
||||
* Map为空
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEmpty(Map obj){
|
||||
return obj != null && !obj.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为数字(允许小数点)
|
||||
* @param str
|
||||
* @return true Or false
|
||||
*/
|
||||
public static boolean isNumeric(String str){
|
||||
return S.isNumeric(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为正确的邮件格式
|
||||
* @param str
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isEmail(String str){
|
||||
if(isEmpty(str)) {
|
||||
return false;
|
||||
}
|
||||
return str.matches("^[\\w-]+(\\.[\\w-]+)*@[\\w-]+(\\.[\\w-]+)+$");
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断字符串是否为电话号码
|
||||
* @param str
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isPhone(String str){
|
||||
if(isEmpty(str)){
|
||||
return false;
|
||||
}
|
||||
boolean valid = str.matches("^1\\d{10}$");
|
||||
if(!valid){
|
||||
valid = str.matches("^0\\d{2,3}-?\\d{7,8}$");
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为整型数字
|
||||
* @param str
|
||||
* @return
|
||||
*/
|
||||
public static boolean isNumber(String str) {
|
||||
try{
|
||||
S.isNumeric(str);
|
||||
Integer.parseInt(str);
|
||||
return true;
|
||||
}
|
||||
catch(Exception ex){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否boolean值范围
|
||||
*/
|
||||
private static final Set<String> TRUE_SET = new HashSet(){{
|
||||
add("true"); add("是"); add("y"); add("yes"); add("1");
|
||||
}};
|
||||
private static final Set<String> FALSE_SET = new HashSet(){{
|
||||
add("false"); add("否"); add("n"); add("no"); add("0");
|
||||
}};
|
||||
|
||||
/***
|
||||
* 是否为boolean类型
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static boolean isValidBoolean(String value){
|
||||
if(value == null){
|
||||
return false;
|
||||
}
|
||||
value = S.trim(value).toLowerCase();
|
||||
return TRUE_SET.contains(value) || FALSE_SET.contains(value);
|
||||
}
|
||||
|
||||
/***
|
||||
* 转换为boolean类型, 并判定是否为true
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
public static boolean isTrue(String value){
|
||||
if(value == null){
|
||||
return false;
|
||||
}
|
||||
value = S.trim(value).toLowerCase();
|
||||
return TRUE_SET.contains(value);
|
||||
}
|
||||
|
||||
/***
|
||||
* 根据指定规则校验字符串的值是否合法
|
||||
* @param value
|
||||
* @param validation
|
||||
* @return
|
||||
*/
|
||||
public static String validate(String value, String validation){
|
||||
if(isEmpty(validation)){
|
||||
return null;
|
||||
}
|
||||
List<String> errorMsgList = new ArrayList<>();
|
||||
String[] rules = validation.split(",");
|
||||
for(String rule : rules){
|
||||
if ("NotNull".equalsIgnoreCase(rule)){
|
||||
if (isEmpty(value)) {
|
||||
errorMsgList.add("不能为空");
|
||||
}
|
||||
}
|
||||
else if ("Number".equalsIgnoreCase(rule)){
|
||||
if (!isNumber(value)) {
|
||||
errorMsgList.add("非数字格式");
|
||||
}
|
||||
}
|
||||
else if ("Boolean".equalsIgnoreCase(rule)){
|
||||
if (!isValidBoolean(value)) {
|
||||
errorMsgList.add("非Boolean格式");
|
||||
}
|
||||
}
|
||||
else if ("Date".equalsIgnoreCase(rule)){
|
||||
if (D.fuzzyConvert(value) == null) {
|
||||
errorMsgList.add("非日期格式");
|
||||
}
|
||||
}
|
||||
else if (rule.toLowerCase().startsWith("length")) {
|
||||
String range = rule.substring(rule.indexOf("(") + 1, rule.lastIndexOf(")"));
|
||||
if (range.contains("-")) {
|
||||
String[] arr = range.split("-");
|
||||
if (notEmpty(arr[0])) {
|
||||
if ((value.length() < Integer.parseInt(arr[0]))) {
|
||||
errorMsgList.add("长度少于最小限制数: " + arr[0]);
|
||||
}
|
||||
}
|
||||
if (notEmpty(arr[1])) {
|
||||
if (value.length() > Integer.parseInt(arr[1])) {
|
||||
errorMsgList.add("长度超出最大限制数: " + arr[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!(value.length() == Integer.parseInt(range))) {
|
||||
errorMsgList.add("长度限制: " + range + "位");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ("Email".equalsIgnoreCase(rule)) {
|
||||
if (!isEmail(value)) {
|
||||
errorMsgList.add("非Email格式");
|
||||
}
|
||||
}
|
||||
else if ("Phone".equalsIgnoreCase(rule)) {
|
||||
if (!isPhone(value)) {
|
||||
errorMsgList.add("非电话号码格式");
|
||||
}
|
||||
}
|
||||
else{
|
||||
//TODO 无法识别的格式
|
||||
}
|
||||
}
|
||||
// 返回校验不通过的结果
|
||||
if(errorMsgList.isEmpty()){
|
||||
return null;
|
||||
}
|
||||
else{
|
||||
return S.join(errorMsgList);
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 判定两个对象是否不同类型或不同值
|
||||
* @param source
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static boolean notEqual(Object source, Object target){
|
||||
return !equal(source, target);
|
||||
}
|
||||
|
||||
/***
|
||||
* 判定两个对象是否类型相同值相等
|
||||
* @param source
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static boolean equal(Object source, Object target){
|
||||
// 都为空
|
||||
if(source == null && target == null){
|
||||
return true;
|
||||
}// 一个为空一个非空
|
||||
else if(source == null || target == null){
|
||||
return false;
|
||||
}
|
||||
else if((source instanceof String && target instanceof String)
|
||||
|| (source instanceof Long && target instanceof Long)
|
||||
|| (source instanceof Integer && target instanceof Integer)
|
||||
|| (source instanceof Float && target instanceof Float)
|
||||
|| (source instanceof Double && target instanceof Double)
|
||||
){
|
||||
return (source).equals(target);
|
||||
}
|
||||
else if(source instanceof List && target instanceof List){
|
||||
List sourceList = (List)source, targetList = (List)target;
|
||||
// size不等
|
||||
if(sourceList.size() != targetList.size()){
|
||||
return false;
|
||||
}
|
||||
for(Object obj : sourceList){
|
||||
if(!targetList.contains(obj)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 其他类型不一致
|
||||
else if(!source.getClass().getName().equals(target.getClass().getName())){
|
||||
return false;
|
||||
}
|
||||
else{
|
||||
log.warn("暂未实现类型 "+ source.getClass().getSimpleName() + "-"+ target.getClass().getSimpleName() + " 的比对!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 模糊对比是否相等(类型不同的转成String对比)
|
||||
* @param source
|
||||
* @param target
|
||||
* @return
|
||||
*/
|
||||
public static boolean fuzzyEqual(Object source, Object target){
|
||||
if(equal(source, target)){
|
||||
return true;
|
||||
}
|
||||
// Boolean-String类型
|
||||
if(source instanceof Boolean && target instanceof String){
|
||||
return (boolean) source == V.isTrue((String)target);
|
||||
}
|
||||
if(target instanceof Boolean && source instanceof String){
|
||||
return (boolean) target == V.isTrue((String)source);
|
||||
}
|
||||
// Date-String类型
|
||||
else if((source instanceof Timestamp || source instanceof Date) && target instanceof String){
|
||||
return D.getDateTime((Date)source).equals(target) || D.getDate((Date)source).equals(target);
|
||||
}
|
||||
else if((target instanceof Timestamp || target instanceof Date) && source instanceof String){
|
||||
return D.getDateTime((Date)target).equals(source) || D.getDate((Date)target).equals(source);
|
||||
}
|
||||
else{
|
||||
return String.valueOf(source).equals(String.valueOf(target));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
package com.diboot.core.vo;
|
||||
|
||||
import com.diboot.core.util.V;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* JSON返回结果
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class JsonResult implements Serializable {
|
||||
private static final long serialVersionUID = 1001L;
|
||||
|
||||
/***
|
||||
* 状态码
|
||||
*/
|
||||
private int code;
|
||||
/***
|
||||
* 消息内容
|
||||
*/
|
||||
private String msg;
|
||||
/***
|
||||
* 返回结果数据
|
||||
*/
|
||||
private Object data;
|
||||
|
||||
/**
|
||||
* 默认成功,无返回数据
|
||||
*/
|
||||
public JsonResult(){
|
||||
this.code = Status.OK.code();
|
||||
this.msg = Status.OK.label();
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认成功,有返回数据(及附加提示信息)
|
||||
*/
|
||||
public JsonResult(Object data, String... additionalMsg){
|
||||
this.code = Status.OK.code();
|
||||
this.msg = Status.OK.label();
|
||||
this.data = data;
|
||||
if(V.notEmpty(additionalMsg)){
|
||||
this.msg += ": " + additionalMsg[0];
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 非成功,指定状态(及附加提示信息)
|
||||
* @param status
|
||||
* @param additionalMsg
|
||||
*/
|
||||
public JsonResult(Status status, String... additionalMsg){
|
||||
this.code = status.code();
|
||||
this.msg = status.label();
|
||||
if(V.notEmpty(additionalMsg)){
|
||||
this.msg += ": " + additionalMsg[0];
|
||||
}
|
||||
this.data = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 非成功,指定状态、返回数据(及附加提示信息)
|
||||
*/
|
||||
public JsonResult(Status status, Object data, String... additionalMsg){
|
||||
this.code = status.code();
|
||||
this.msg = status.label();
|
||||
if(V.notEmpty(additionalMsg)){
|
||||
this.msg += ": " + additionalMsg[0];
|
||||
}
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/***
|
||||
* 自定义JsonResult
|
||||
* @param code
|
||||
* @param label
|
||||
* @param data
|
||||
*/
|
||||
public JsonResult(int code, String label, Object data){
|
||||
this.code = code;
|
||||
this.msg = label;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/***
|
||||
* 绑定分页信息
|
||||
* @param pagination
|
||||
*/
|
||||
public JsonResult bindPagination(Pagination pagination){
|
||||
return new PagingJsonResult(this, pagination);
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
public Object getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.diboot.core.vo;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* KeyValue键值对形式的VO
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/4
|
||||
*/
|
||||
public class KeyValue implements Serializable {
|
||||
private static final long serialVersionUID = -2358161241655186720L;
|
||||
|
||||
public KeyValue(){}
|
||||
|
||||
public KeyValue(String key, Object value){
|
||||
this.k = key;
|
||||
this.v = value;
|
||||
}
|
||||
|
||||
/***
|
||||
* key: 显示值
|
||||
*/
|
||||
private String k;
|
||||
|
||||
/***
|
||||
* value: 存储值
|
||||
*/
|
||||
private Object v;
|
||||
|
||||
public String getK() {
|
||||
return k;
|
||||
}
|
||||
|
||||
public void setK(String k) {
|
||||
this.k = k;
|
||||
}
|
||||
|
||||
public Object getV() {
|
||||
return v;
|
||||
}
|
||||
|
||||
public void setV(Object v) {
|
||||
this.v = v;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
package com.diboot.core.vo;
|
||||
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
import com.diboot.core.config.Cons;
|
||||
import com.diboot.core.util.S;
|
||||
import com.diboot.core.util.V;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 分页
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class Pagination implements Serializable {
|
||||
private static final Logger log = LoggerFactory.getLogger(Pagination.class);
|
||||
|
||||
private static final long serialVersionUID = -4083929594112114522L;
|
||||
|
||||
/***
|
||||
* 当前页
|
||||
*/
|
||||
private int _pageIndex = 1;
|
||||
/***
|
||||
* 默认每页数量10
|
||||
*/
|
||||
private int _pageSize = BaseConfig.getPageSize();
|
||||
/***
|
||||
* count总数
|
||||
*/
|
||||
private long _totalCount = 0;
|
||||
/***
|
||||
* 排序-升序排列的字段
|
||||
*/
|
||||
private List<String> ascList = null;
|
||||
/***
|
||||
* 降序排列的字段(默认以ID降序排列,当指定了其他排列方式时以用户指定为准)
|
||||
*/
|
||||
private List<String> descList = new ArrayList<>(Arrays.asList(Cons.FieldName.id.name()));
|
||||
|
||||
public Pagination(){
|
||||
}
|
||||
|
||||
/***
|
||||
* 指定当前页数
|
||||
*/
|
||||
public Pagination(int pageIndex){
|
||||
set_pageIndex(pageIndex);
|
||||
}
|
||||
|
||||
public int get_pageIndex() {
|
||||
return _pageIndex;
|
||||
}
|
||||
|
||||
public void set_pageIndex(int _pageIndex) {
|
||||
this._pageIndex = _pageIndex;
|
||||
}
|
||||
|
||||
public int get_pageSize() {
|
||||
return _pageSize;
|
||||
}
|
||||
|
||||
public void set_pageSize(int _pageSize) {
|
||||
if(_pageSize > 1000){
|
||||
log.warn("分页pageSize过大,将被调整为默认限值,请检查调用是否合理!pageSize="+_pageSize);
|
||||
_pageSize = 1000;
|
||||
}
|
||||
this._pageSize = _pageSize;
|
||||
}
|
||||
|
||||
public long get_totalCount() {
|
||||
return _totalCount;
|
||||
}
|
||||
|
||||
public void set_totalCount(long _totalCount) {
|
||||
this._totalCount = _totalCount;
|
||||
}
|
||||
|
||||
public void set_orderBy(String orderBy){
|
||||
if(V.notEmpty(orderBy)){
|
||||
// 先清空默认排序规则
|
||||
clearDefaultOrder();
|
||||
// 指定新的排序规则
|
||||
String[] orderByFields = S.split(orderBy);
|
||||
for(String field : orderByFields){
|
||||
// orderBy=name:DESC,age:ASC,birthdate
|
||||
if(field.contains(":")){
|
||||
String[] fieldAndOrder = S.split(field, ":");
|
||||
if("DESC".equalsIgnoreCase(fieldAndOrder[1])){
|
||||
if(descList == null){
|
||||
descList = new ArrayList<>();
|
||||
}
|
||||
descList.add(fieldAndOrder[0]);
|
||||
}
|
||||
else{
|
||||
if(ascList == null){
|
||||
ascList = new ArrayList<>();
|
||||
}
|
||||
ascList.add(fieldAndOrder[0]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(ascList == null){
|
||||
ascList = new ArrayList<>();
|
||||
}
|
||||
ascList.add(field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 清除默认排序
|
||||
*/
|
||||
public void clearDefaultOrder(){
|
||||
ascList = null;
|
||||
descList = null;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取总的页数
|
||||
* @return
|
||||
*/
|
||||
public int get_totalPage() {
|
||||
if(_totalCount <= 0){
|
||||
return 0;
|
||||
}
|
||||
return (int)Math.ceil((float)_totalCount/_pageSize);
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取数据库字段的列排序,用于service层调用
|
||||
* @return
|
||||
*/
|
||||
public List<String> getAscList() {
|
||||
return ascList;
|
||||
}
|
||||
|
||||
/***
|
||||
* 获取数据库字段的列排序,,用于service层调用
|
||||
* @return
|
||||
*/
|
||||
public List<String> getDescList() {
|
||||
return descList;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.diboot.core.vo;
|
||||
|
||||
/**
|
||||
* JSON返回结果
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public class PagingJsonResult extends JsonResult{
|
||||
private static final long serialVersionUID = 1001L;
|
||||
|
||||
/***
|
||||
* 分页相关信息
|
||||
*/
|
||||
private Pagination page;
|
||||
|
||||
/**
|
||||
* 默认成功,无返回数据
|
||||
*/
|
||||
public PagingJsonResult(JsonResult jsonResult, Pagination pagination){
|
||||
super(jsonResult.getCode(), jsonResult.getMsg(), jsonResult.getData());
|
||||
this.page = pagination;
|
||||
}
|
||||
|
||||
public Pagination getPage() {
|
||||
return page;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package com.diboot.core.vo;
|
||||
|
||||
/**
|
||||
* 状态码定义
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/01/01
|
||||
*/
|
||||
public enum Status {
|
||||
/***
|
||||
* 请求处理成功
|
||||
*/
|
||||
OK(0, "操作成功"),
|
||||
|
||||
/***
|
||||
* 部分成功(一般用于批量处理场景,只处理筛选后的合法数据)
|
||||
*/
|
||||
WARN_PARTIAL_SUCCESS(1001, "部分成功"),
|
||||
|
||||
/***
|
||||
* 有潜在的性能问题
|
||||
*/
|
||||
WARN_PERFORMANCE_ISSUE(1002, "潜在的性能问题"),
|
||||
|
||||
/***
|
||||
* 传入参数不对
|
||||
*/
|
||||
FAIL_INVALID_PARAM(4000, "请求参数不匹配"),
|
||||
|
||||
/***
|
||||
* Token无效或已过期
|
||||
*/
|
||||
FAIL_INVALID_TOKEN(4001, "Token无效或已过期"),
|
||||
|
||||
/***
|
||||
* 没有权限执行该操作
|
||||
*/
|
||||
FAIL_NO_PERMISSION(4003, "无权执行该操作"),
|
||||
|
||||
/***
|
||||
* 请求资源不存在
|
||||
*/
|
||||
FAIL_NOT_FOUND(4004, "请求资源不存在"),
|
||||
|
||||
/***
|
||||
* 数据校验不通过
|
||||
*/
|
||||
FAIL_VALIDATION(4005, "数据校验不通过"),
|
||||
|
||||
/***
|
||||
* 操作执行失败
|
||||
*/
|
||||
FAIL_OPERATION(4006, "操作执行失败"),
|
||||
|
||||
/***
|
||||
* 系统异常
|
||||
*/
|
||||
FAIL_EXCEPTION(5000, "系统异常");
|
||||
|
||||
private int code;
|
||||
private String label;
|
||||
Status(int code, String label){
|
||||
this.code = code;
|
||||
this.label = label;
|
||||
}
|
||||
public int code(){
|
||||
return this.code;
|
||||
}
|
||||
public String label(){
|
||||
return this.label;
|
||||
}
|
||||
public static int getCode(String value){
|
||||
for(Status eu : Status.values()){
|
||||
if(eu.name().equals(value)){
|
||||
return eu.code();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
public static String getLabel(String value){
|
||||
for(Status eu : Status.values()){
|
||||
if(eu.name().equals(value)){
|
||||
return eu.label();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
SET FOREIGN_KEY_CHECKS=0;
|
||||
-- 元数据表
|
||||
-- DROP TABLE IF EXISTS `metadata`;
|
||||
CREATE TABLE `metadata` (
|
||||
`id` int unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
|
||||
`parent_id` int unsigned NOT NULL COMMENT '父ID',
|
||||
`type` varchar(50) NOT NULL COMMENT '元数据类型',
|
||||
`item_name` varchar(100) NOT NULL COMMENT '元数据项显示名',
|
||||
`item_value` varchar(100) DEFAULT NULL COMMENT '元数据项存储值',
|
||||
`comment` varchar(100) DEFAULT NULL COMMENT '备注',
|
||||
`extdata` varchar(200) DEFAULT NULL COMMENT '扩展属性',
|
||||
`sort_id` smallint NOT NULL DEFAULT '99' COMMENT '排序号',
|
||||
`system` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否是系统预置',
|
||||
`editable` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否可编辑',
|
||||
`active` tinyint(1) NOT NULL DEFAULT '1' COMMENT '是否有效',
|
||||
`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_metadata` (`type`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
|
|
@ -1,13 +1,4 @@
|
|||
plugins {
|
||||
id 'java'
|
||||
}
|
||||
|
||||
sourceCompatibility = 1.8
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(":diboot-core")
|
||||
testCompile group: 'junit', name: 'junit', version: '4.12'
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.diboot.example;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
|
||||
/**
|
||||
* @author Administrator
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class Application extends SpringBootServletInitializer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(Application.class, args);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.diboot.example.config;
|
||||
|
||||
import com.diboot.core.config.BaseConfig;
|
||||
|
||||
/**
|
||||
* 应用配置
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
public class AppConfig extends BaseConfig {
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.diboot.example.config;
|
||||
|
||||
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
|
||||
import com.baomidou.mybatisplus.extension.injector.LogicSqlInjector;
|
||||
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Mybatis-Plus配置
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
@Configuration
|
||||
@MapperScan(basePackages={"com.diboot.*.mapper*"})
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
/**
|
||||
* Mybatis-plus分页插件
|
||||
*/
|
||||
@Bean
|
||||
public PaginationInterceptor paginationInterceptor() {
|
||||
PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
|
||||
return paginationInterceptor;
|
||||
}
|
||||
|
||||
/***
|
||||
* 逻辑删除注入
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public ISqlInjector sqlInjector() {
|
||||
return new LogicSqlInjector();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.diboot.example.config;
|
||||
|
||||
import com.alibaba.fastjson.serializer.SerializerFeature;
|
||||
import com.alibaba.fastjson.support.config.FastJsonConfig;
|
||||
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
|
||||
import com.diboot.core.util.D;
|
||||
import com.diboot.core.util.DateConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/***
|
||||
* Spring配置文件
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/19
|
||||
*/
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@EnableTransactionManagement(proxyTargetClass=true)
|
||||
@ComponentScan(basePackages={"com.diboot"})
|
||||
public class SpringMvcConfig implements WebMvcConfigurer{
|
||||
private static final Logger log = LoggerFactory.getLogger(SpringMvcConfig.class);
|
||||
|
||||
/**
|
||||
* JSON转换组件替换为fastJson
|
||||
*/
|
||||
@Bean
|
||||
public HttpMessageConverters fastJsonHttpMessageConverters() {
|
||||
FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
|
||||
//处理中文乱码问题
|
||||
List<MediaType> fastMediaTypes = new ArrayList<>();
|
||||
fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8);
|
||||
converter.setSupportedMediaTypes(fastMediaTypes);
|
||||
// 配置转换格式
|
||||
FastJsonConfig fastJsonConfig = new FastJsonConfig();
|
||||
// 设置fastjson的序列化参数:禁用循环依赖检测,数据兼容浏览器端(避免JS端Long精度丢失问题)
|
||||
fastJsonConfig.setSerializerFeatures(SerializerFeature.DisableCircularReferenceDetect,
|
||||
SerializerFeature.BrowserCompatible);
|
||||
fastJsonConfig.setDateFormat(D.FORMAT_DATETIME_Y4MDHM);
|
||||
converter.setFastJsonConfig(fastJsonConfig);
|
||||
|
||||
HttpMessageConverter<?> httpMsgConverter = converter;
|
||||
return new HttpMessageConverters(httpMsgConverter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addFormatters(FormatterRegistry registry) {
|
||||
registry.addConverter(new DateConverter());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.example.entity.Department;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.service.DepartmentService;
|
||||
import com.diboot.example.vo.DepartmentVO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Organization相关Controller
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/department")
|
||||
public class DepartmentController extends BaseCrudRestController {
|
||||
|
||||
@Autowired
|
||||
private DepartmentService departmentService;
|
||||
|
||||
/***
|
||||
* 默认的分页实现
|
||||
* <p>
|
||||
* url参数示例: /list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResult getDefaultVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Department> queryWrapper = buildQuery(request);
|
||||
return super.getEntityListWithPaging(request, queryWrapper, DepartmentVO.class);
|
||||
}
|
||||
|
||||
/***
|
||||
* 默认的分页实现
|
||||
* <p>
|
||||
* url参数示例: /listVo?page.size=20&page.index=1&page.orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/listVo")
|
||||
public JsonResult getCustomVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Department> queryWrapper = buildQuery(request);
|
||||
// 查询当前页的数据
|
||||
List entityList = departmentService.getEntityList(queryWrapper);
|
||||
List voList = departmentService.getViewObjectList(entityList, DepartmentVO.class);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, voList);
|
||||
}
|
||||
|
||||
@GetMapping("/kv")
|
||||
public JsonResult getKVPairList(HttpServletRequest request){
|
||||
Wrapper wrapper = new QueryWrapper<Department>().lambda()
|
||||
.select(Department::getName, Department::getId);
|
||||
List<KeyValue> list = departmentService.getKeyValueList(wrapper);
|
||||
return new JsonResult(list);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public JsonResult createEntity(@ModelAttribute DepartmentVO viewObject, BindingResult result, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
// 转换
|
||||
Department entity = BeanUtils.convert(viewObject, Department.class);
|
||||
// 创建
|
||||
return super.createEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 查询Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
DepartmentVO vo = departmentService.getViewObject(id, DepartmentVO.class);
|
||||
return new JsonResult(vo);
|
||||
}
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Organization entity, BindingResult result,
|
||||
HttpServletRequest request, ModelMap modelMap) throws Exception{
|
||||
return super.updateEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 删除用户
|
||||
* @param id 用户ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return departmentService;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.util.JSON;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.example.entity.Department;
|
||||
import com.diboot.example.entity.Employee;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.service.EmployeeService;
|
||||
import com.diboot.example.vo.DepartmentVO;
|
||||
import com.diboot.example.vo.EmployeeVO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Organization相关Controller
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/employee")
|
||||
public class EmployeeController extends BaseCrudRestController {
|
||||
|
||||
@Autowired
|
||||
private EmployeeService employeeService;
|
||||
|
||||
@GetMapping("/test")
|
||||
public JsonResult test(HttpServletRequest request) throws Exception{
|
||||
// List<Long> userIdList = new ArrayList<>();
|
||||
// userIdList.add(1001L);
|
||||
// userIdList.add(1003L);
|
||||
// String sql = "SELECT user_id, role_id FROM user_role WHERE user_id IN (?)";
|
||||
// List<Map<String, Object>> list = SqlExecutor.executeQuery(sql, userIdList);
|
||||
|
||||
|
||||
List<Long> userIdList = new ArrayList<>();
|
||||
userIdList.add(1L);
|
||||
QueryWrapper<Employee> queryWrapper = new QueryWrapper<Employee>();
|
||||
|
||||
//IN条件一定不能为空,否则就会删除整张表数据
|
||||
queryWrapper.in("id", userIdList);
|
||||
System.out.println(JSON.stringify(queryWrapper));
|
||||
employeeService.deleteEntities(queryWrapper)
|
||||
;
|
||||
userIdList.clear();
|
||||
queryWrapper = new QueryWrapper<Employee>();
|
||||
queryWrapper.in("id", userIdList);
|
||||
employeeService.deleteEntities(queryWrapper);
|
||||
|
||||
return new JsonResult();
|
||||
}
|
||||
|
||||
/***
|
||||
* 默认的分页实现
|
||||
* <p>
|
||||
* url参数示例: /list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResult getDefaultVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Department> queryWrapper = buildQuery(request);
|
||||
return super.getEntityListWithPaging(request, queryWrapper, DepartmentVO.class);
|
||||
}
|
||||
|
||||
/***
|
||||
* 默认的分页实现
|
||||
* <p>
|
||||
* url参数示例: /listVo?page.size=20&page.index=1&page.orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/listVo")
|
||||
public JsonResult getCustomVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Employee> queryWrapper = buildQuery(request);
|
||||
// 查询当前页的数据
|
||||
List entityList = employeeService.getEntityList(queryWrapper);
|
||||
List voList = employeeService.getViewObjectList(entityList, EmployeeVO.class);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, voList);
|
||||
}
|
||||
|
||||
@GetMapping("/kv")
|
||||
public JsonResult getKVPairList(HttpServletRequest request){
|
||||
Wrapper wrapper = new QueryWrapper<Employee>().lambda()
|
||||
.select(Employee::getRealname, Employee::getId);
|
||||
List<KeyValue> list = employeeService.getKeyValueList(wrapper);
|
||||
return new JsonResult(list);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public JsonResult createEntity(@ModelAttribute EmployeeVO viewObject, BindingResult result, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
// 转换
|
||||
Employee entity = BeanUtils.convert(viewObject, Employee.class);
|
||||
// 创建
|
||||
return super.createEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 查询Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
EmployeeVO vo = employeeService.getViewObject(id, EmployeeVO.class);
|
||||
return new JsonResult(vo);
|
||||
}
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Organization entity, BindingResult result,
|
||||
HttpServletRequest request, ModelMap modelMap) throws Exception{
|
||||
return super.updateEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 删除用户
|
||||
* @param id 用户ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return employeeService;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package com.diboot.example.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.Wrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.controller.BaseCrudRestController;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.core.util.BeanUtils;
|
||||
import com.diboot.core.vo.JsonResult;
|
||||
import com.diboot.core.vo.KeyValue;
|
||||
import com.diboot.core.vo.Status;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.service.OrganizationService;
|
||||
import com.diboot.example.vo.OrganizationVO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Organization相关Controller
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/organization")
|
||||
public class OrganizationController extends BaseCrudRestController {
|
||||
|
||||
@Autowired
|
||||
private OrganizationService organizationService;
|
||||
|
||||
/***
|
||||
* 默认的分页实现
|
||||
* <p>
|
||||
* url参数示例: /list?_pageSize=20&_pageIndex=1&_orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResult getDefaultVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Organization> queryWrapper = buildQuery(request);
|
||||
return super.getEntityListWithPaging(request, queryWrapper, OrganizationVO.class);
|
||||
}
|
||||
|
||||
/***
|
||||
* 默认的分页实现
|
||||
* <p>
|
||||
* url参数示例: /listVo?page.size=20&page.index=1&page.orderBy=itemValue&type=GENDAR
|
||||
* </p>
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/listVo")
|
||||
public JsonResult getCustomVOList(HttpServletRequest request) throws Exception{
|
||||
QueryWrapper<Organization> queryWrapper = buildQuery(request);
|
||||
// 查询当前页的数据
|
||||
List entityList = organizationService.getEntityList(queryWrapper);
|
||||
List voList = organizationService.getViewObjectList(entityList, OrganizationVO.class);
|
||||
// 返回结果
|
||||
return new JsonResult(Status.OK, voList);
|
||||
}
|
||||
|
||||
@GetMapping("/kv")
|
||||
public JsonResult getKVPairList(HttpServletRequest request){
|
||||
Wrapper wrapper = new QueryWrapper<Organization>().lambda()
|
||||
.select(Organization::getName, Organization::getId);
|
||||
List<KeyValue> list = organizationService.getKeyValueList(wrapper);
|
||||
return new JsonResult(list);
|
||||
}
|
||||
|
||||
/***
|
||||
* 创建Entity
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PostMapping("/")
|
||||
public JsonResult createEntity(@ModelAttribute OrganizationVO viewObject, BindingResult result, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
// 转换
|
||||
Organization entity = BeanUtils.convert(viewObject, Organization.class);
|
||||
// 创建
|
||||
return super.createEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 查询Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
public JsonResult getModel(@PathVariable("id")Long id, HttpServletRequest request, ModelMap modelMap)
|
||||
throws Exception{
|
||||
OrganizationVO vo = organizationService.getViewObject(id, OrganizationVO.class);
|
||||
return new JsonResult(vo);
|
||||
}
|
||||
|
||||
/***
|
||||
* 更新Entity
|
||||
* @param id ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@PutMapping("/{id}")
|
||||
public JsonResult updateModel(@PathVariable("id")Long id, @ModelAttribute Organization entity, BindingResult result,
|
||||
HttpServletRequest request, ModelMap modelMap) throws Exception{
|
||||
return super.updateEntity(entity, result, modelMap);
|
||||
}
|
||||
|
||||
/***
|
||||
* 删除用户
|
||||
* @param id 用户ID
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResult deleteModel(@PathVariable("id")Long id, HttpServletRequest request) throws Exception{
|
||||
return super.deleteEntity(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseService getService() {
|
||||
return organizationService;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.diboot.example.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseExtEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 定时任务
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2018/12/27
|
||||
*/
|
||||
@Data
|
||||
public class Department extends BaseExtEntity {
|
||||
private static final long serialVersionUID = -4849732665419794547L;
|
||||
|
||||
@TableField
|
||||
private Long parentId;
|
||||
|
||||
@TableField
|
||||
private Long orgId;
|
||||
|
||||
@TableField
|
||||
private String name;
|
||||
|
||||
@TableField
|
||||
private String code;
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.diboot.example.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 员工Entity
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
@Data
|
||||
public class Employee extends BaseEntity {
|
||||
private static final long serialVersionUID = 8980226078305249367L;
|
||||
|
||||
@TableField
|
||||
private Long departmentId;
|
||||
|
||||
@TableField
|
||||
private String realname;
|
||||
|
||||
@TableField
|
||||
private Date birthdate;
|
||||
|
||||
@TableField
|
||||
private String gender;
|
||||
|
||||
@TableField
|
||||
private String status;
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.diboot.example.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 单位Entity
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
@Data
|
||||
public class Organization extends BaseEntity {
|
||||
private static final long serialVersionUID = -5889309041570465909L;
|
||||
|
||||
@TableField
|
||||
private Long parentId;
|
||||
|
||||
@TableField
|
||||
private String name;
|
||||
|
||||
@TableField
|
||||
private String telphone;
|
||||
|
||||
@TableField
|
||||
private String address;
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.diboot.example.entity;
|
||||
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
public class Role extends BaseEntity {
|
||||
private static final long serialVersionUID = 3701095453152116088L;
|
||||
|
||||
private String name;
|
||||
|
||||
private String code;
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.diboot.example.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.diboot.core.entity.BaseEntity;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
@Data
|
||||
public class User extends BaseEntity {
|
||||
private static final long serialVersionUID = 3050761344045195972L;
|
||||
|
||||
@TableField
|
||||
private String username;
|
||||
|
||||
@TableField
|
||||
private String gender;
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.example.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.example.entity.Department;
|
||||
|
||||
/**
|
||||
* 部门Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface DepartmentMapper extends BaseCrudMapper<Department> {
|
||||
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.example.mapper.DepartmentMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.example.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.example.entity.Employee;
|
||||
|
||||
/**
|
||||
* 员工Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface EmployeeMapper extends BaseCrudMapper<Employee> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.example.mapper.EmployeeMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.example.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.example.entity.Organization;
|
||||
|
||||
/**
|
||||
* 单位Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface OrganizationMapper extends BaseCrudMapper<Organization> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "./mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.diboot.example.mapper.OrganizationMapper">
|
||||
|
||||
</mapper>
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.example.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.example.entity.Role;
|
||||
|
||||
/**
|
||||
* 员工Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface RoleMapper extends BaseCrudMapper<Role> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.diboot.example.mapper;
|
||||
|
||||
import com.diboot.core.mapper.BaseCrudMapper;
|
||||
import com.diboot.example.entity.User;
|
||||
|
||||
/**
|
||||
* 员工Mapper
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/22
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
public interface UserMapper extends BaseCrudMapper<User> {
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,291 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
|
||||
Copyright 2009-2013 the original author or authors.
|
||||
|
||||
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 joinOn 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.
|
||||
|
||||
-->
|
||||
|
||||
<!ELEMENT mapper (cache-ref | cache | resultMap* | parameterMap* | sql* | insert* | update* | delete* | select* )+>
|
||||
<!ATTLIST mapper
|
||||
xmlns:fo CDATA #IMPLIED
|
||||
namespace CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT cache-ref EMPTY>
|
||||
<!ATTLIST cache-ref
|
||||
namespace CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT cache (property*)>
|
||||
<!ATTLIST cache
|
||||
type CDATA #IMPLIED
|
||||
eviction CDATA #IMPLIED
|
||||
flushInterval CDATA #IMPLIED
|
||||
size CDATA #IMPLIED
|
||||
readOnly CDATA #IMPLIED
|
||||
blocking CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT parameterMap (parameter+)?>
|
||||
<!ATTLIST parameterMap
|
||||
id CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT parameter EMPTY>
|
||||
<!ATTLIST parameter
|
||||
property CDATA #REQUIRED
|
||||
javaType CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
mode (IN | OUT | INOUT) #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
scale CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT resultMap (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST resultMap
|
||||
id CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
extends CDATA #IMPLIED
|
||||
autoMapping (true|false) #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT constructor (idArg*,arg*)>
|
||||
|
||||
<!ELEMENT id EMPTY>
|
||||
<!ATTLIST id
|
||||
property CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT result EMPTY>
|
||||
<!ATTLIST result
|
||||
property CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT idArg EMPTY>
|
||||
<!ATTLIST idArg
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT arg EMPTY>
|
||||
<!ATTLIST arg
|
||||
javaType CDATA #IMPLIED
|
||||
column CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT collection (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST collection
|
||||
property CDATA #REQUIRED
|
||||
column CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
ofType CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
notNullColumn CDATA #IMPLIED
|
||||
columnPrefix CDATA #IMPLIED
|
||||
resultSet CDATA #IMPLIED
|
||||
foreignColumn CDATA #IMPLIED
|
||||
autoMapping (true|false) #IMPLIED
|
||||
fetchType (lazy|eager) #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT association (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST association
|
||||
property CDATA #REQUIRED
|
||||
column CDATA #IMPLIED
|
||||
javaType CDATA #IMPLIED
|
||||
jdbcType CDATA #IMPLIED
|
||||
select CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
notNullColumn CDATA #IMPLIED
|
||||
columnPrefix CDATA #IMPLIED
|
||||
resultSet CDATA #IMPLIED
|
||||
foreignColumn CDATA #IMPLIED
|
||||
autoMapping (true|false) #IMPLIED
|
||||
fetchType (lazy|eager) #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT discriminator (case+)>
|
||||
<!ATTLIST discriminator
|
||||
column CDATA #IMPLIED
|
||||
javaType CDATA #REQUIRED
|
||||
jdbcType CDATA #IMPLIED
|
||||
typeHandler CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT case (constructor?,id*,result*,association*,collection*, discriminator?)>
|
||||
<!ATTLIST case
|
||||
value CDATA #REQUIRED
|
||||
resultMap CDATA #IMPLIED
|
||||
resultType CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT property EMPTY>
|
||||
<!ATTLIST property
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT typeAlias EMPTY>
|
||||
<!ATTLIST typeAlias
|
||||
alias CDATA #REQUIRED
|
||||
type CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT select (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST select
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
resultMap CDATA #IMPLIED
|
||||
resultType CDATA #IMPLIED
|
||||
resultSetType (FORWARD_ONLY | SCROLL_INSENSITIVE | SCROLL_SENSITIVE) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
fetchSize CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
useCache (true|false) #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
resultOrdered (true|false) #IMPLIED
|
||||
resultSets CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT insert (#PCDATA | selectKey | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST insert
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
keyProperty CDATA #IMPLIED
|
||||
useGeneratedKeys (true|false) #IMPLIED
|
||||
keyColumn CDATA #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT selectKey (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST selectKey
|
||||
resultType CDATA #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
keyProperty CDATA #IMPLIED
|
||||
keyColumn CDATA #IMPLIED
|
||||
order (BEFORE|AFTER) #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT update (#PCDATA | selectKey | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST update
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
keyProperty CDATA #IMPLIED
|
||||
useGeneratedKeys (true|false) #IMPLIED
|
||||
keyColumn CDATA #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT delete (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST delete
|
||||
id CDATA #REQUIRED
|
||||
parameterMap CDATA #IMPLIED
|
||||
parameterType CDATA #IMPLIED
|
||||
timeout CDATA #IMPLIED
|
||||
flushCache (true|false) #IMPLIED
|
||||
statementType (STATEMENT|PREPARED|CALLABLE) #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
lang CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!-- Dynamic -->
|
||||
|
||||
<!ELEMENT include (property+)?>
|
||||
<!ATTLIST include
|
||||
refid CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT bind EMPTY>
|
||||
<!ATTLIST bind
|
||||
name CDATA #REQUIRED
|
||||
value CDATA #REQUIRED
|
||||
>
|
||||
|
||||
<!ELEMENT sql (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST sql
|
||||
id CDATA #REQUIRED
|
||||
lang CDATA #IMPLIED
|
||||
databaseId CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT trim (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST trim
|
||||
prefix CDATA #IMPLIED
|
||||
prefixOverrides CDATA #IMPLIED
|
||||
suffix CDATA #IMPLIED
|
||||
suffixOverrides CDATA #IMPLIED
|
||||
>
|
||||
<!ELEMENT where (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ELEMENT set (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
|
||||
<!ELEMENT foreach (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST foreach
|
||||
collection CDATA #REQUIRED
|
||||
item CDATA #IMPLIED
|
||||
index CDATA #IMPLIED
|
||||
open CDATA #IMPLIED
|
||||
close CDATA #IMPLIED
|
||||
separator CDATA #IMPLIED
|
||||
>
|
||||
|
||||
<!ELEMENT choose (when* , otherwise?)>
|
||||
<!ELEMENT when (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST when
|
||||
test CDATA #REQUIRED
|
||||
>
|
||||
<!ELEMENT otherwise (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
|
||||
<!ELEMENT if (#PCDATA | include | trim | where | set | foreach | choose | if | bind)*>
|
||||
<!ATTLIST if
|
||||
test CDATA #REQUIRED
|
||||
>
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.example.entity.Department;
|
||||
|
||||
/**
|
||||
* 部门相关Service
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
public interface DepartmentService extends BaseService<Department> {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.example.entity.Employee;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
public interface EmployeeService extends BaseService<Employee> {
|
||||
|
||||
List<Map<String, Object>> testCustomQueryWrapper(QueryWrapper wrapper);
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.example.entity.Organization;
|
||||
|
||||
/**
|
||||
* 单位相关Service
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
public interface OrganizationService extends BaseService<Organization> {
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.example.entity.Role;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
public interface RoleService extends BaseService<Role> {
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.diboot.example.service;
|
||||
|
||||
import com.diboot.core.service.BaseService;
|
||||
import com.diboot.example.entity.User;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
public interface UserService extends BaseService<User> {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.example.entity.Department;
|
||||
import com.diboot.example.mapper.DepartmentMapper;
|
||||
import com.diboot.example.service.DepartmentService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 部门相关Service实现
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class DepartmentServiceImpl extends BaseServiceImpl<DepartmentMapper, Department> implements DepartmentService {
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.example.entity.Employee;
|
||||
import com.diboot.example.mapper.EmployeeMapper;
|
||||
import com.diboot.example.service.EmployeeService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class EmployeeServiceImpl extends BaseServiceImpl<EmployeeMapper, Employee> implements EmployeeService {
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> testCustomQueryWrapper(QueryWrapper wrapper){
|
||||
return getBaseMapper().selectMaps(wrapper);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.mapper.OrganizationMapper;
|
||||
import com.diboot.example.service.OrganizationService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 单位相关Service实现
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OrganizationServiceImpl extends BaseServiceImpl<OrganizationMapper, Organization> implements OrganizationService {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.example.entity.Role;
|
||||
import com.diboot.example.mapper.RoleMapper;
|
||||
import com.diboot.example.service.RoleService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, Role> implements RoleService {
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package com.diboot.example.service.impl;
|
||||
|
||||
import com.diboot.core.service.impl.BaseServiceImpl;
|
||||
import com.diboot.example.entity.User;
|
||||
import com.diboot.example.mapper.UserMapper;
|
||||
import com.diboot.example.service.UserService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 员工相关Service
|
||||
* @author Mazhicheng
|
||||
* @version 2018/12/23
|
||||
* Copyright © www.dibo.ltd
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class UserServiceImpl extends BaseServiceImpl<UserMapper, User> implements UserService {
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.diboot.example.vo;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.core.binding.annotation.BindField;
|
||||
import com.diboot.example.entity.Department;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
@Data
|
||||
public class DepartmentVO extends Department {
|
||||
private static final long serialVersionUID = -362116388664907913L;
|
||||
|
||||
@BindField(entity = Organization.class, field = "name", condition = "org_id=id")
|
||||
private String orgName;
|
||||
|
||||
@BindField(entity = Department.class, field = "name", condition = "parent_id=id")
|
||||
private String parentName;
|
||||
|
||||
@BindEntityList(entity = Department.class, condition = "id=parent_id")
|
||||
private List<Department> children;
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.diboot.example.vo;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntity;
|
||||
import com.diboot.core.binding.annotation.BindField;
|
||||
import com.diboot.core.binding.annotation.BindMetadata;
|
||||
import com.diboot.example.entity.Department;
|
||||
import com.diboot.example.entity.Employee;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
@Data
|
||||
public class EmployeeVO extends Employee {
|
||||
private static final long serialVersionUID = 2956966168209358800L;
|
||||
|
||||
@BindEntity(entity = Department.class, condition="department_id=id")
|
||||
private Department department;
|
||||
|
||||
@BindMetadata(type="GENDER", field="gender")
|
||||
private String genderLabel;
|
||||
|
||||
@BindField(entity=Department.class, field="name", condition="this.department_id=id AND code IS NOT NULL")
|
||||
private String deptName;
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.diboot.example.vo;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.core.binding.annotation.BindField;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/5
|
||||
*/
|
||||
@Data
|
||||
public class OrganizationVO extends Organization {
|
||||
private static final long serialVersionUID = 9056449207962546696L;
|
||||
|
||||
@BindField(entity = Organization.class, field = "name", condition = "this.parentId=id")
|
||||
private String parentName;
|
||||
|
||||
@BindEntityList(entity = Organization.class, condition = "this.id=parentId")
|
||||
private List<Organization> children;
|
||||
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.diboot.example.vo;
|
||||
|
||||
import com.diboot.core.binding.annotation.BindEntityList;
|
||||
import com.diboot.core.binding.annotation.BindField;
|
||||
import com.diboot.core.binding.annotation.BindMetadata;
|
||||
import com.diboot.example.entity.Organization;
|
||||
import com.diboot.example.entity.Role;
|
||||
import com.diboot.example.entity.User;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Mazhicheng
|
||||
* @version v2.0
|
||||
* @date 2019/1/30
|
||||
*/
|
||||
@Data
|
||||
public class UserVO extends User {
|
||||
private static final long serialVersionUID = 3526115343377985725L;
|
||||
|
||||
@BindMetadata(type="GENDER", field = "gender")
|
||||
private String genderLabel;
|
||||
|
||||
// 支持级联字段关联
|
||||
@BindField(entity = Organization.class, field="name", condition="this.departmentId=Department.id AND Department.orgId=id")
|
||||
private String orgName;
|
||||
|
||||
// 支持多-多Entity实体关联
|
||||
@BindEntityList(entity = Role.class, condition="this.id=user_role.user_id AND user_role.role_id=id")
|
||||
private List<Role> roleList;
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
server.port=8080
|
||||
server.servlet.context-path=/example
|
||||
#10秒超时
|
||||
spring.server.connectionTimeout=10000
|
||||
spring.server.protocol=org.apache.coyote.http11.Http11Nio2Protocol
|
||||
spring.server.redirectPort=443
|
||||
spring.server.compression=on
|
||||
|
||||
# spring config
|
||||
spring.devtools.restart.enabled=true
|
||||
|
||||
#datasource config
|
||||
spring.datasource.url=jdbc:mysql://localhost:3306/diboot_example?characterEncoding=utf8
|
||||
spring.datasource.username=diboot
|
||||
spring.datasource.password=123456
|
||||
spring.datasource.hikari.maximum-pool-size=5
|
||||
spring.datasource.hikari.data-source-properties.useInformationSchema=true
|
||||
spring.datasource.hikari.data-source-properties.nullCatalogMeansCurrent=true
|
||||
# 数据库驱动
|
||||
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
|
||||
|
||||
#字符集utf-8
|
||||
spring.http.encoding.charset=UTF-8
|
||||
spring.http.encoding.enabled=true
|
||||
spring.http.encoding.force=true
|
||||
|
||||
# mybatis配置
|
||||
#mybatis.configuration.cache-enabled=false
|
||||
#mybatis.configuration.lazy-loading-enabled=true
|
||||
#mybatis.configuration.map-underscore-to-camel-case=true
|
||||
#mybatis.configuration.multiple-result-sets-enabled=false
|
||||
#mybatis.configuration.use-generated-keys=true
|
||||
#mybatis.configuration.auto-mapping-behavior=full
|
||||
#mybatis.configuration.default-statement-timeout=60
|
||||
#mybatis.configuration.log-impl=org.apache.ibatis.logging.log4j2.Log4j2Impl
|
||||
|
||||
# logging config
|
||||
logging.pattern.console=%clr{%d{MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${PID}}{faint} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%xwEx
|
||||
logging.level.root=info
|
||||
logging.level.org.apache=info
|
||||
logging.level.org.hibernate.validator=info
|
||||
logging.level.org.springframework=info
|
||||
logging.level.com.zaxxer.hikari=info
|
||||
logging.level.com.diboot=debug
|
||||
logging.level.org.mybatis=debug
|
|
@ -0,0 +1,5 @@
|
|||
__ _ __ __
|
||||
____/ / (_) / /_ ____ ____ / /_
|
||||
/ __ / / / / __ \ / __ \ / __ \ / __/
|
||||
/ /_/ / / / / /_/ / / /_/ / / /_/ / / /_
|
||||
\__,_/ /_/ /_.___/ \____/ \____/ \__/
|
Loading…
Reference in New Issue