优化枚举字典

This commit is contained in:
zhou-hao
2018-04-12 22:59:05 +08:00
parent 8d872213d0
commit ba9597a812
15 changed files with 213 additions and 36 deletions

View File

@@ -0,0 +1,104 @@
package org.hswebframework.web.dao.mybatis;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.hswebframework.web.dict.EnumDict;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.util.ClassUtils;
import java.io.IOException;
import java.sql.*;
import static org.springframework.util.StringUtils.tokenizeToStringArray;
@Slf4j
public class EnumDictHandlerRegister {
static TypeHandlerRegistry typeHandlerRegistry;
private static MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory();
private static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
public static void register(String packages) {
register(tokenizeToStringArray(packages,
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
public static void register(String[] packages) {
if (typeHandlerRegistry == null) {
log.error("请在spring容器初始化后再调用此方法!");
return;
}
for (String basePackage : packages) {
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
ClassUtils.convertClassNameToResourcePath(basePackage) + "/**/*.class";
try {
Resource[] resources = resourcePatternResolver.getResources(packageSearchPath);
for (Resource resource : resources) {
try {
MetadataReader reader = metadataReaderFactory.getMetadataReader(resource);
Class enumType = Class.forName(reader.getClassMetadata().getClassName());
if (enumType.isEnum() && EnumDict.class.isAssignableFrom(enumType)) {
log.debug("register typeHandler for enum dict:{}", enumType);
typeHandlerRegistry.register(enumType, new EnumDictHandler(enumType));
}
} catch (Exception ignore) {
}
}
} catch (IOException e) {
log.warn("register enum dict error", e);
}
}
}
@Getter
@Setter
@AllArgsConstructor
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.BIT,
JdbcType.BOOLEAN, JdbcType.NUMERIC,
JdbcType.TINYINT, JdbcType.INTEGER,
JdbcType.BIGINT, JdbcType.DECIMAL,
JdbcType.CHAR})
static class EnumDictHandler<T extends Enum & EnumDict> implements TypeHandler<T> {
private Class<T> type;
@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
ps.setObject(i, parameter.getValue());
}
@Override
public T getResult(ResultSet rs, String columnName) throws SQLException {
Object val = rs.getObject(columnName);
return EnumDict.findByValue(getType(), val).orElse(null);
}
@Override
public T getResult(ResultSet rs, int columnIndex) throws SQLException {
Object val = rs.getObject(columnIndex);
return EnumDict.findByValue(getType(), val).orElse(null);
}
@Override
public T getResult(CallableStatement cs, int columnIndex) throws SQLException {
Object val = cs.getObject(columnIndex);
return EnumDict.findByValue(getType(), val).orElse(null);
}
}
}

View File

@@ -74,7 +74,6 @@ public class MyBatisAutoConfiguration {
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
MybatisProperties mybatisProperties = this.mybatisProperties();
if (null != entityFactory) {
factory.setObjectFactory(new MybatisEntityFactory(entityFactory));
}
@@ -109,7 +108,11 @@ public class MyBatisAutoConfiguration {
}
factory.setTypeHandlersPackage(typeHandlers);
factory.setMapperLocations(mybatisProperties.resolveMapperLocations());
SqlSessionFactory sqlSessionFactory = factory.getObject();
EnumDictHandlerRegister.typeHandlerRegistry = sqlSessionFactory.getConfiguration().getTypeHandlerRegistry();
EnumDictHandlerRegister.register("org.hswebframework.web;" + mybatisProperties.getTypeHandlersPackage());
ResultMapsUtils.setSqlSession(sqlSessionFactory);
try {
Class.forName("javax.persistence.Table");
@@ -117,6 +120,9 @@ public class MyBatisAutoConfiguration {
} catch (@SuppressWarnings("all") Exception ignore) {
}
EasyOrmSqlBuilder.getInstance().entityFactory = entityFactory;
sqlSessionFactory.getConfiguration().getTypeAliasRegistry();
return sqlSessionFactory;
}

View File

@@ -7,6 +7,8 @@ import org.hswebframework.ezorm.rdb.meta.RDBColumnMetaData;
import org.hswebframework.ezorm.rdb.meta.RDBTableMetaData;
import org.hswebframework.ezorm.rdb.meta.converter.DateTimeConverter;
import org.hswebframework.ezorm.rdb.meta.converter.NumberValueConverter;
import org.hswebframework.utils.ClassUtils;
import org.hswebframework.web.dict.EnumDict;
import org.springframework.core.annotation.AnnotationUtils;
import javax.persistence.Column;
@@ -59,6 +61,8 @@ public class JpaAnnotationParser {
jdbcTypeMapping.put(java.sql.Date.class, JDBCType.TIMESTAMP);
jdbcTypeMapping.put(java.sql.Timestamp.class, JDBCType.TIMESTAMP);
jdbcTypeMapping.put(Object.class, JDBCType.VARCHAR);
jdbcTypeConvert.add((type, property) -> {
Enumerated enumerated = getAnnotation(type, property, Enumerated.class);
return enumerated != null ? JDBCType.VARCHAR : null;
@@ -67,6 +71,14 @@ public class JpaAnnotationParser {
Lob enumerated = getAnnotation(type, property, Lob.class);
return enumerated != null ? JDBCType.CLOB : null;
});
jdbcTypeConvert.add((type, property) -> {
if (type.isEnum() && EnumDict.class.isAssignableFrom(type)) {
Class genType = ClassUtils.getGenericType(type);
return jdbcTypeMapping.getOrDefault(genType, JDBCType.OTHER);
}
return null;
});
}
public static RDBTableMetaData parseMetaDataFromEntity(Class entityClass) {
@@ -92,7 +104,9 @@ public class JpaAnnotationParser {
columnMetaData.setPrecision(column.precision());
columnMetaData.setJavaType(descriptor.getPropertyType());
JDBCType type = jdbcTypeMapping.get(descriptor.getPropertyType());
Class propertyType = descriptor.getPropertyType();
JDBCType type = jdbcTypeMapping.get(propertyType);
if (type == null) {
type = jdbcTypeConvert.stream()
.map(func -> func.apply(entityClass, descriptor))

View File

@@ -20,6 +20,6 @@ public class JpaAnnotationParserTest {
RDBTableMetaData metaData = JpaAnnotationParser.parseMetaDataFromEntity(TestEntity.class);
Assert.assertNotNull(metaData);
Assert.assertEquals(metaData.getColumns().size(), 4);
Assert.assertEquals(metaData.getColumns().size(), 5);
}
}

View File

@@ -1,6 +1,7 @@
package org.hswebframework.web.dao.mybatis.builder.jpa;
import lombok.Data;
import org.hswebframework.web.dict.defaults.TrueOrFalse;
import javax.persistence.Column;
import javax.persistence.Table;
@@ -22,4 +23,7 @@ public class TestEntity extends AbstractEntity {
@Column(name = "role_id")
private String roleId;
@Column(name = "enabled")
private TrueOrFalse enabled;
}

View File

@@ -1,12 +1,11 @@
package org.hswebframework.web.commons.entity;
/**
* TODO 完成注释
*
* @author zhouhao
* @see DataStatusEnum
*/
public interface DataStatus {
Byte STATUS_ENABLED = 1;
Byte STATUS_ENABLED = 1;
Byte STATUS_DISABLED = 0;
Byte STATUS_LOCKED = -1;
Byte STATUS_LOCKED = -1;
}

View File

@@ -0,0 +1,18 @@
package org.hswebframework.web.commons.entity;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hswebframework.web.dict.EnumDict;
@AllArgsConstructor
@Getter
public enum DataStatusEnum implements EnumDict<Byte> {
ENABLED((byte) 1, "正常"),
DISABLED((byte) 0, "禁用"),
LOCK((byte) -1, "锁定"),
DELETED((byte) -10, "删除");
private Byte value;
private String text;
}

View File

@@ -26,6 +26,20 @@ public interface EnumDict<V> {
*/
String getText();
/**
* 对比是否和value相等,对比地址,值,value转为string忽略大小写对比,text忽略大小写对比
*
* @param v value
* @return 是否相等
*/
default boolean eq(Object v) {
return getValue() == v
|| getValue().equals(v)
|| String.valueOf(getValue()).equalsIgnoreCase(String.valueOf(v))
|| getText().equalsIgnoreCase(String.valueOf(v));
}
/**
* 枚举选项的描述,对一个选项进行详细的描述有时候是必要的.默认值为{@link this#getText()}
*
@@ -77,7 +91,7 @@ public interface EnumDict<V> {
*
* @see this#find(Class, Predicate)
*/
static <T extends Enum & EnumDict> Optional<T> find(Class<T> type, Object valueOrTextOrAlias) {
return Optional.ofNullable(findByValue(type, valueOrTextOrAlias).orElseGet(() -> findByText(type, String.valueOf(valueOrTextOrAlias)).orElse(null)));
static <T extends Enum & EnumDict> Optional<T> find(Class<T> type, Object target) {
return find(type, v->v.eq(target));
}
}

View File

@@ -0,0 +1,19 @@
package org.hswebframework.web.dict.defaults;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.hswebframework.web.dict.EnumDict;
@Getter
@AllArgsConstructor
public enum TrueOrFalse implements EnumDict<Byte> {
TRUE((byte) 1, ""),
FALSE((byte) 0, "");
private Byte value;
private String text;
}

View File

@@ -22,7 +22,7 @@ import java.io.Serializable;
import java.util.List;
/**
* TODO 完成注释
* 验证结果
*
* @author zhouhao
*/

View File

@@ -24,6 +24,7 @@ import org.hswebframework.web.BusinessException;
import java.util.List;
public class ValidationException extends BusinessException {
private static final long serialVersionUID = 7807607467371210082L;
private ValidateResults results;
public ValidationException(String message) {

View File

@@ -1,7 +1,9 @@
package org.hswebframework.web.bean;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;
import java.lang.reflect.InvocationTargetException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@@ -13,7 +15,7 @@ import java.util.Map;
public class FastBeanCopierTest {
@Test
public void test() {
public void test() throws InvocationTargetException, IllegalAccessException {
Source source = new Source();
source.setAge(100);
source.setName("测试");
@@ -31,8 +33,8 @@ public class FastBeanCopierTest {
Target target = new Target();
FastBeanCopier.copy(source, target);
long t = System.currentTimeMillis();
// Copier copier = FastBeanCopier.getCopier(source, target, true);
for (int i = 10_0000; i > 0; i--) {
FastBeanCopier.copy(source, target);
}

View File

@@ -29,7 +29,6 @@ public class DictDefineTest {
Assert.assertEquals(UserCode.SIMPLE, EnumDict.findByText(UserCode.class, UserCode.SIMPLE.getText()).orElse(null));
Assert.assertEquals(UserCode.SIMPLE, EnumDict.find(UserCode.class, UserCode.SIMPLE.getText()).orElse(null));
}
@Test

View File

@@ -7,7 +7,6 @@ import org.hswebframework.web.service.TreeService;
import java.util.List;
/**
* TODO 完成注释
*
* @author zhouhao
*/

View File

@@ -8,7 +8,6 @@ import org.hswebframework.web.commons.entity.DataStatus;
import org.hswebframework.web.dao.schedule.ScheduleJobDao;
import org.hswebframework.web.entity.schedule.ScheduleJobEntity;
import org.hswebframework.web.id.IDGenerator;
import org.hswebframework.web.service.EnableCacheGenericEntityService;
import org.hswebframework.web.service.GenericEntityService;
import org.hswebframework.web.service.schedule.ScheduleJobService;
import org.hswebframework.web.service.schedule.ScheduleTriggerBuilder;
@@ -16,7 +15,6 @@ import org.quartz.*;
import org.quartz.spi.MutableTrigger;
import org.quartz.spi.OperableTrigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
@@ -83,18 +81,18 @@ public class SimpleScheduleJobService extends GenericEntityService<ScheduleJobEn
protected void startJob(ScheduleJobEntity jobEntity) {
try {
if(scheduler.checkExists(createJobKey(jobEntity))) {
return;
}
JobDetail jobDetail = JobBuilder
.newJob(DynamicJob.class)
.withIdentity(createJobKey(jobEntity))
.setJobData(createJobDataMap(jobEntity.getParameters()))
.usingJobData(DynamicJobFactory.JOB_ID_KEY, jobEntity.getId())
.withDescription(jobEntity.getName() + (jobEntity.getRemark() == null ? "" : jobEntity.getRemark()))
.build();
MutableTrigger trigger = scheduleTriggerBuilder.buildTrigger(jobEntity.getQuartzConfig());
trigger.setKey(createTriggerKey(jobEntity));
if (scheduler.checkExists(createJobKey(jobEntity))) {
return;
}
JobDetail jobDetail = JobBuilder
.newJob(DynamicJob.class)
.withIdentity(createJobKey(jobEntity))
.setJobData(createJobDataMap(jobEntity.getParameters()))
.usingJobData(DynamicJobFactory.JOB_ID_KEY, jobEntity.getId())
.withDescription(jobEntity.getName() + (jobEntity.getRemark() == null ? "" : jobEntity.getRemark()))
.build();
MutableTrigger trigger = scheduleTriggerBuilder.buildTrigger(jobEntity.getQuartzConfig());
trigger.setKey(createTriggerKey(jobEntity));
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
@@ -129,11 +127,11 @@ public class SimpleScheduleJobService extends GenericEntityService<ScheduleJobEn
@Override
public void enable(String id) {
Objects.requireNonNull(id);
int size= createUpdate().set(ScheduleJobEntity.status, DataStatus.STATUS_ENABLED)
int size = createUpdate().set(ScheduleJobEntity.status, DataStatus.STATUS_ENABLED)
.where(ScheduleJobEntity.id, id).exec();
if(size>0) {
startJob(selectByPk(id));
}
if (size > 0) {
startJob(selectByPk(id));
}
}
private void deleteJob(ScheduleJobEntity jobEntity) {
@@ -150,10 +148,10 @@ public class SimpleScheduleJobService extends GenericEntityService<ScheduleJobEn
@Override
public void disable(String id) {
Objects.requireNonNull(id);
int size = createUpdate().set(ScheduleJobEntity.status, DataStatus.STATUS_DISABLED)
int size = createUpdate().set(ScheduleJobEntity.status, DataStatus.STATUS_DISABLED)
.where(ScheduleJobEntity.id, id).exec();
if(size>0) {
deleteJob(selectByPk(id));
}
if (size > 0) {
deleteJob(selectByPk(id));
}
}
}