Merge pull request #1 from dibo-software/develop

Develop
This commit is contained in:
Mazc 2019-05-11 18:01:02 +08:00 committed by GitHub
commit de589e230a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
93 changed files with 7747 additions and 38 deletions

View File

@ -1,6 +1,6 @@
buildscript {
ext {
springBootVersion = '2.1.2.RELEASE'
springBootVersion = '2.1.4.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.16"
mybatisStarterVersion = "2.0.1"
mybatisPlusVersion = "3.1.1"
fastjsonVersion = "1.2.58"
lombokVersion = "1.18.8"
}
dependencies {
compileOnly("org.projectlombok:lombok:$lombokVersion")
@ -51,7 +51,7 @@ subprojects {
// 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")
}

View File

@ -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'
}

View File

@ -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();
}

View File

@ -0,0 +1,137 @@
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.util.Collection;
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列表
String annoObjectForeignKeyField = S.toLowerCaseCamel(annoObjectForeignKey);
List annoObjectForeignKeyList = BeanUtils.collectToList(annoObjectList, annoObjectForeignKeyField);
if(V.isEmpty(annoObjectForeignKeyList)){
return;
}
// 解析中间表查询关联
if(middleTable != null){
String sql = middleTable.toSQL(annoObjectForeignKeyList);
// 执行查询并合并结果
String keyName = middleTable.getEqualsToRefEntityPkColumn(), valueName = middleTable.getEqualsToAnnoObjectFKColumn();
Map<Object, Object> middleTableResultMap = SqlExecutor.executeQueryAndMergeResult(sql, annoObjectForeignKeyList, keyName, valueName);
if(V.notEmpty(middleTableResultMap)){
Collection middleTableColumnValueList = middleTableResultMap.keySet();
// 构建查询条件
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), middleTableColumnValueList);
// 查询entity列表
List<T> list = referencedService.getEntityList(queryWrapper);
// 绑定结果
bindingResult(S.toLowerCaseCamel(referencedEntityPrimaryKey), list, middleTableResultMap);
}
}
else{
// 构建查询条件
queryWrapper.in(S.toSnakeCase(referencedEntityPrimaryKey), annoObjectForeignKeyList);
// 查询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, Object> middleTableResultMap) {
Map<String, T> valueEntityMap = new HashMap<>(list.size());
for(T entity : list){
Object pkValue = BeanUtils.getProperty(entity, doPkPropName);
Object annoObjFK = middleTableResultMap.get(pkValue);
if(annoObjFK != null){
valueEntityMap.put(String.valueOf(annoObjFK), entity);
}
else{
log.warn("转换结果异常,中间关联条件数据不一致");
}
}
// 绑定
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityMap);
}
/***
* 绑定结果
* @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(String.valueOf(pkValue), entity);
}
// 绑定
BeanUtils.bindPropValueOfList(annoObjectField, annoObjectList, annoObjectForeignKey, valueEntityMap);
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,380 @@
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;
}
// 解析中间表关联
String tableName = extractMiddleTableName(expressionList);
if(tableName != null){
parseMiddleTable(binder, expressionList, tableName);
}
else{
parseDirectRelation(binder, expressionList);
}
}
/**
* 解析直接关联
* @param binder
* @param expressionList
* @param <T>
*/
private static <T> void parseDirectRelation(BaseBinder<T> binder, List<Expression> expressionList) {
// 解析直接关联
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 <T> void parseMiddleTable(BaseBinder<T> binder, List<Expression> expressionList, String tableName) {
// 单一条件不是中间表条件
if(expressionList.size() <= 1){
return;
}
// 提取到表
MiddleTable middleTable = new MiddleTable(tableName);
// 中间表两边边连接字段
String middleTableEqualsToAnnoObjectFKColumn = null, middleTableEqualsToRefEntityPkColumn = null;
// VO与Entity的关联字段
String annoObjectForeignKey = null, referencedEntityPrimaryKey = 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();
String rightColumn = express.getRightExpression().toString();
// 如果右侧为中间表字段: this.departmentId=Department.id
if(rightColumn.startsWith(tableName+".")){
// 绑定左手边连接列
String leftHandColumn = getColumnName(leftColumn);
// this. 开头的vo对象字段
if(isVoColumn(leftColumn)){
// 识别到vo对象的属性 departmentId
annoObjectForeignKey = leftHandColumn;
// 对应中间表的关联字段
middleTableEqualsToAnnoObjectFKColumn = getColumnName(rightColumn);
}
else{
// 注解关联的entity主键
referencedEntityPrimaryKey = leftHandColumn;
middleTableEqualsToRefEntityPkColumn = getColumnName(rightColumn);
}
binder.joinOn(annoObjectForeignKey, referencedEntityPrimaryKey);
middleTable.connect(middleTableEqualsToAnnoObjectFKColumn, middleTableEqualsToRefEntityPkColumn);
}
// 如果左侧为中间表字段: Department.orgId=id (entity=Organization)
if(leftColumn.startsWith(tableName+".")){
// 绑定右手边连接列
String rightHandColumn = getColumnName(rightColumn);
if(isVoColumn(rightColumn)){
// 识别到vo对象的属性 departmentId
annoObjectForeignKey = rightHandColumn;
// 对应中间表的关联字段
middleTableEqualsToAnnoObjectFKColumn = S.substringAfter(leftColumn, ".");
}
else{
referencedEntityPrimaryKey = rightHandColumn;
middleTableEqualsToRefEntityPkColumn = getColumnName(leftColumn);
}
binder.joinOn(annoObjectForeignKey, referencedEntityPrimaryKey);
middleTable.connect(middleTableEqualsToAnnoObjectFKColumn, middleTableEqualsToRefEntityPkColumn);
}
}
}
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());
}
}
}
binder.withMiddleTable(middleTable);
}
/**
* 提取中间表表对象名
* @param expressionList
* @return
*/
private static String extractMiddleTableName(List<Expression> expressionList){
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 = 1;
for(Map.Entry<String, Integer> entry : tableNameCountMap.entrySet()){
if(entry.getValue() > count){
count = entry.getValue();
tableName = entry.getKey();
}
}
return tableName;
}
/**
* 统计表名出现的次数
* @param tableNameCountMap
* @param columnStr
*/
private static void countTableName(Map<String, Integer> tableNameCountMap, String columnStr) {
if(columnStr.contains(".")){
// 如果是中间表(非this,self标识的当前表)
if(!isVoColumn(columnStr)){
String tempTableName = S.substringBefore(columnStr, ".");
Integer count = tableNameCountMap.get(tempTableName);
if(count == null){
count = 0;
}
count++;
tableNameCountMap.put(tempTableName, count);
}
}
}
/**
* 注解列
* @return
*/
private static String getColumnName(String annoColumn){
if(annoColumn.contains(".")){
annoColumn = S.substringAfter(annoColumn, ".");
}
return annoColumn;
}
/**
* 是否为VO自身属性以this开头的
* @param expression
* @return
*/
private static boolean isVoColumn(String expression){
String tempTableName = S.substringBefore(expression, ".");
// 如果是中间表(非this,self标识的当前表)
return "this".equals(tempTableName) || "self".equals(tempTableName);
}
}

View File

@ -0,0 +1,299 @@
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(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) {
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,102 @@
package com.diboot.core.binding.parser;
import com.diboot.core.config.Cons;
import com.diboot.core.util.S;
import com.diboot.core.util.V;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* 中间表
* @author Mazhicheng<br>
* @version 1.0<br>
* @date 2019/04/01 <br>
*/
public class MiddleTable {
/**
* 中间表
*/
private String table;
/**
* 与注解VO的外键关联的连接字段
*/
private String equalsToAnnoObjectFKColumn;
/**
* 与被引用Entity属性主键的连接字段
*/
private String equalsToRefEntityPkColumn;
/**
* 附加条件
*/
private List<String> additionalConditions;
public MiddleTable(String table){
this.table = table;
}
/**
* 连接左手连接VO的外键右手连接Entity属性的主键
* @param equalsToAnnoObjectFKColumn
* @param equalsToRefEntityPkColumn
* @return
*/
public MiddleTable connect(String equalsToAnnoObjectFKColumn, String equalsToRefEntityPkColumn) {
this.equalsToAnnoObjectFKColumn = equalsToAnnoObjectFKColumn;
this.equalsToRefEntityPkColumn = equalsToRefEntityPkColumn;
return this;
}
/**
* 添加中间表查询所需的附加条件
* @param additionalCondition
*/
public MiddleTable addAdditionalCondition(String additionalCondition) {
if(this.additionalConditions == null){
this.additionalConditions = new ArrayList<>();
}
this.additionalConditions.add(additionalCondition);
return this;
}
public String getEqualsToAnnoObjectFKColumn() {
return equalsToAnnoObjectFKColumn;
}
public String getEqualsToRefEntityPkColumn() {
return equalsToRefEntityPkColumn;
}
/**
* 转换查询SQL
* @param annoObjectForeignKeyList 注解外键值的列表用于拼接SQL查询
* @return
*/
public String toSQL(List annoObjectForeignKeyList){
if(V.isEmpty(annoObjectForeignKeyList)){
return null;
}
Object object = annoObjectForeignKeyList.get(0);
// 不需要加引号的类型
boolean noQuotes = object instanceof Integer
|| object instanceof Long
|| object instanceof Double
|| object instanceof Float
|| object instanceof BigDecimal;
// 构建SQL
StringBuilder sb = new StringBuilder();
sb.append("SELECT ").append(this.equalsToAnnoObjectFKColumn).append(Cons.SEPARATOR_COMMA)
.append(this.equalsToRefEntityPkColumn).append(" FROM ").append(this.table)
.append(" WHERE ").append(this.equalsToAnnoObjectFKColumn).append(" IN (");
String params = S.repeat("?", ",", annoObjectForeignKeyList.size());
sb.append(params).append(")");
if(this.additionalConditions != null){
for(String condition : this.additionalConditions){
sb.append(" AND ").append(condition);
}
}
return sb.toString();
}
}

View File

@ -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;
}
}

View File

@ -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
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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());
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -0,0 +1,11 @@
package com.diboot.core.plugin;
/**
* 插件管理器
* @author Mazhicheng
* @version v2.0
* @date 2018/10/23
*/
public interface PluginManager {
}

View File

@ -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);
/***
* 创建或更新entityentity.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);
}

View File

@ -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);
}

View File

@ -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+", 请检查!");
}
}

View File

@ -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();
}
}

View File

@ -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未实现!");
}
}

View File

@ -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]+" 值存在 nullBeanUtils.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(String.valueOf(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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,96 @@
package com.diboot.core.util;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 原生SQL执行类
* @author Mazhicheng
* @version v2.0
* @date 2019/1/31
*/
public class SqlExecutor {
private static final Logger log = LoggerFactory.getLogger(SqlExecutor.class);
/***
* 执行Select语句
* @param sql
* @return
*/
public static List<Map<String,Object>> executeQuery(String sql, List params) throws Exception{
if(V.isEmpty(sql)){
return null;
}
// 获取SqlSessionFactory实例
SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) ContextHelper.getBean(SqlSessionFactory.class);
if(sqlSessionFactory == null){
log.warn("无法获取SqlSessionFactory实例SQL将不被执行。");
return null;
}
// 替换单个?参数为多个用于拼接IN参数
if(sql.contains("?") && V.notEmpty(params)){
sql = S.replace(sql, "?", S.repeat("?", ",", params.size()));
}
log.debug("执行查询SQL: "+sql);
try(SqlSession session = sqlSessionFactory.openSession(); Connection conn = session.getConnection(); PreparedStatement stmt = conn.prepareStatement(sql)){
if(V.notEmpty(params)){
for(int i=0; i<params.size(); i++){
stmt.setObject(i+1, params.get(i));
}
}
ResultSet rs = stmt.executeQuery();
ResultSetMetaData meta = rs.getMetaData();
List<Map<String,Object>> mapList = new ArrayList<>();
if(meta.getColumnCount() > 0){
// 添加数据行
while(rs.next()){
Map<String,Object> dataRow = new HashMap<>();
for(int i=1; i<=meta.getColumnCount(); i++){
dataRow.put(meta.getColumnLabel(i), rs.getObject(i));
}
mapList.add(dataRow);
}
rs.close();
}
log.debug("查询结果: "+JSON.stringify(mapList));
return mapList;
}
catch(Exception e){
log.error("执行Sql查询异常", e);
throw e;
}
}
/**
* 执行查询和合并结果
* @param sql
* @param params
* @return
*/
public static Map<Object, Object> executeQueryAndMergeResult(String sql, List params, String keyName, String valueName){
List<Map<String,Object>> resultSetMapList = null;
try {
resultSetMapList = executeQuery(sql, params);
}
catch (Exception e) {
log.warn("执行查询异常", e);
}
// 合并list为map
Map<Object, Object> resultMap = new HashMap<>();
if(V.notEmpty(resultSetMapList)){
for(Map<String, Object> row : resultSetMapList){
resultMap.put(row.get(keyName), row.get(valueName));
}
}
return resultMap;
}
}

View File

@ -0,0 +1,368 @@
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 notEquals(Object source, Object target){
return !equals(source, target);
}
/***
* 判定两个对象是否类型相同值相等
* @param source
* @param target
* @return
*/
public static <T> boolean equals(T source, T target){
if(source == null && target == null){
return true;
}
else if(source == null || target == null){
return false;
}
// 不为空调用equals比较
else if(source instanceof Comparable){
return (source).equals(target);
}
else if(source instanceof Collection){
Collection sourceList = (Collection)source, targetList = (Collection)target;
// size不等
if(sourceList.size() != targetList.size()){
return false;
}
for(Object obj : sourceList){
if(!targetList.contains(obj)){
return false;
}
}
return true;
}
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(equals(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));
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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'
}

View File

@ -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);
}
}

View File

@ -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 {
}

View File

@ -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();
}
}

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,67 @@
package com.diboot.example.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.diboot.core.controller.BaseCrudRestController;
import com.diboot.core.service.BaseService;
import com.diboot.core.vo.JsonResult;
import com.diboot.core.vo.Status;
import com.diboot.example.entity.User;
import com.diboot.example.service.UserService;
import com.diboot.example.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* User相关Controller
* @author Mazhicheng
* @version 2019/05/11
* Copyright © www.dibo.ltd
*/
@RestController
@RequestMapping("/user")
public class UserController extends BaseCrudRestController {
@Autowired
private UserService userService;
/***
* 默认的分页实现
* <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<User> queryWrapper = buildQuery(request);
return super.getEntityListWithPaging(request, queryWrapper, UserVO.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<User> queryWrapper = buildQuery(request);
// 查询当前页的数据
List entityList = userService.getEntityList(queryWrapper);
List voList = userService.getViewObjectList(entityList, UserVO.class);
// 返回结果
return new JsonResult(Status.OK, voList);
}
@Override
protected BaseService getService() {
return userService;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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> {
}

View File

@ -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>

View File

@ -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> {
}

View File

@ -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>

View File

@ -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> {
}

View File

@ -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>

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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
>

View File

@ -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> {
}

View File

@ -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);
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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> {
}

View File

@ -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 {
}

View File

@ -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);
}
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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 {
}

View File

@ -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;
}

View File

@ -0,0 +1,32 @@
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 com.diboot.example.entity.Organization;
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;
// 通过中间表关联
@BindEntity(entity = Organization.class, condition = "this.department_id=department.id AND department.org_id=id AND department.deleted=0") // AND deleted=0
private Organization organization;
}

View File

@ -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;
}

View File

@ -0,0 +1,34 @@
package com.diboot.example.vo;
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.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;
}

View File

@ -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&serverTimezone=GMT%2B8
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

View File

@ -0,0 +1,5 @@
__ _ __ __
____/ / (_) / /_ ____ ____ / /_
/ __ / / / / __ \ / __ \ / __ \ / __/
/ /_/ / / / / /_/ / / /_/ / / /_/ / / /_
\__,_/ /_/ /_.___/ \____/ \____/ \__/

View File

@ -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&serverTimezone=GMT%2B8
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