init
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# zilean-mybatis
|
||||
|
||||
简化单表重复的CRUD操作,有了它,无需手动建表,简单查询无需重复书写XML。封装隔离后,可轻松嵌入到任何系统里,目前仅针对MySQL有效
|
||||
|
||||
### 特别说明
|
||||
```txt
|
||||
封装隔离后,可轻松嵌入到任何系统里,目前仅针对MySQL有效
|
||||
```
|
||||
|
||||
### 引用Jar
|
||||
```txt
|
||||
Lombok ---------------- 简化get/set/toString等方法, https://www.projectlombok.org/
|
||||
Spring Data JPA ------- Java持久层API
|
||||
MySQL Driver ---------- MySQL数据库驱动
|
||||
MyBatis Framework ----- Mybatis框架
|
||||
HuTool ---------------- 贼好用的Java工具类库
|
||||
Druid ----------------- 阿里数据库连接池组件
|
||||
Fastjson -------------- 阿里Json工具类
|
||||
```
|
||||
|
||||
### 主要功能
|
||||
```txt
|
||||
简化单表crud操作, 基础方法无需书写xml也无需引用mybatis的crud注解
|
||||
运用JPA实现自动建表, 你再也不用烦恼, 表字段究竟怎么取名才好
|
||||
```
|
||||
|
||||
### 注意
|
||||
```txt
|
||||
1、BaseEntity子类必须有javax.persistence.Entity, javax.persistence.Table两个注解
|
||||
2、BaseEntity子类中的@Table必须含有name属性, 并指定表名, 不然会导致建表失败, 并且BaseMapper也取不到表名
|
||||
3、BaseDao子接口必须有org.springframework.stereotype.Repository注解
|
||||
4、根据阿里巴巴Java编码规范, BaseEntity子类中不能出现不属于数据库表的字段, 如需关联查询, 请新建BaseVo的子类
|
||||
5、建议简单的crud使用BaseDao中的方法, 复杂的关联查询使用xml
|
||||
6、如果不需要, 或者不怎么会用Lombok的话, 只需要从pom中移除Lombok依赖, 在对应Lombok注解处加上get/set方法即可
|
||||
```
|
||||
@@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<!-- maven可以继承父项目中的参数,所以可以删除子模块中相同定义 -->
|
||||
<artifactId>zilean-mybatis</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>zilean-mybatis</name>
|
||||
<description>简易MyBatis模块</description>
|
||||
|
||||
<parent>
|
||||
<groupId>cn.odboy</groupId>
|
||||
<artifactId>zilean</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<!-- lookup parent from repository -->
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<dependencies>
|
||||
<!-- maven可以继承父项目中的依赖,所以可以删除子模块中相同定义 -->
|
||||
<!--lombok 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>${lombok.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- HuTool工具箱-->
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>${hutool.version}</version>
|
||||
</dependency>
|
||||
<!--jpa 依赖-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<!--Spring-Mybatis-->
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
<version>2.1.0</version>
|
||||
</dependency>
|
||||
<!-- JSON解析 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>${fastjson.version}</version>
|
||||
</dependency>
|
||||
<!-- zilean-common 依赖 -->
|
||||
<dependency>
|
||||
<groupId>cn.odboy</groupId>
|
||||
<artifactId>zilean-common</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<!-- 如果其他包需要依赖这个模块那么就不要加这个 -->
|
||||
<!--<build>-->
|
||||
<!--<plugins>-->
|
||||
<!--<plugin>-->
|
||||
<!--<groupId>org.springframework.boot</groupId>-->
|
||||
<!--<artifactId>spring-boot-maven-plugin</artifactId>-->
|
||||
<!--</plugin>-->
|
||||
<!--</plugins>-->
|
||||
<!--</build>-->
|
||||
</project>
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
package cn.odboy.zilean.mybatis.cache;
|
||||
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.WeakCache;
|
||||
import cn.hutool.core.date.DateUnit;
|
||||
import cn.odboy.zilean.mybatis.constant.SqlConsts;
|
||||
import org.apache.ibatis.cache.Cache;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
/**
|
||||
* @author 田俊
|
||||
* @version 1.0.0
|
||||
* @name: DefaultMyBatisCache <br>
|
||||
* @description: TODO 自定义的Mybatis缓存 <br>
|
||||
* @date: 2019/04/2019/4/6 <br>
|
||||
* @since JDK 1.8
|
||||
*/
|
||||
public final class DefaultMyBatisCache implements Cache {
|
||||
private static final Logger log = LoggerFactory.getLogger(DefaultMyBatisCache.class);
|
||||
|
||||
private String id;
|
||||
private ReadWriteLock lock = new ReentrantReadWriteLock();
|
||||
/**
|
||||
* 过期时间:30分钟
|
||||
*/
|
||||
private WeakCache<Object, Object> cache =
|
||||
CacheUtil.newWeakCache(DateUnit.MINUTE.getMillis() * 30);
|
||||
|
||||
public DefaultMyBatisCache() {
|
||||
log.debug("Mybatis自定义缓存初始化");
|
||||
}
|
||||
|
||||
/**
|
||||
* 必须有该构造函数
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
public DefaultMyBatisCache(String id) {
|
||||
log.debug("Mybatis自定义缓存通过ID初始化");
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存编号
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@Override
|
||||
public String getId() {
|
||||
log.debug("得到ID:" + id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存对象的大小
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
@Override
|
||||
public int getSize() {
|
||||
log.debug("获取缓存大小!");
|
||||
return cache.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存key值缓存对象
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
@Override
|
||||
public void putObject(Object key, Object value) {
|
||||
log.debug("往缓存中添加元素:key=" + key + ",value=" + value);
|
||||
cache.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过KEY获取缓存对象
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Object getObject(Object key) {
|
||||
if (key != null && (SqlConsts.PH_SQL_FIND.contains(String.valueOf(key)))) {
|
||||
// 二级缓存不更新问题
|
||||
cache.remove(key);
|
||||
}
|
||||
log.debug("通过kEY获取值:" + key);
|
||||
log.debug("OVER");
|
||||
log.debug("=======================================================");
|
||||
log.debug("值为:" + cache.get(key));
|
||||
log.debug("=====================OVER==============================");
|
||||
return cache.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过key删除缓存对象
|
||||
*
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Object removeObject(Object key) {
|
||||
log.debug("移除缓存对象:" + key);
|
||||
cache.remove(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空缓存
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
log.debug("清除缓存!");
|
||||
cache.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存的读写锁
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public ReadWriteLock getReadWriteLock() {
|
||||
log.debug("获取锁对象!!!");
|
||||
return lock;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package cn.odboy.zilean.mybatis.constant;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO SQL常量
|
||||
* @time: 2019/8/8 10:41
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
public class SqlConsts {
|
||||
/**
|
||||
* 对象属性:主键名称
|
||||
*/
|
||||
public static final String PRIMARY_KEY_NAME = "id";
|
||||
/**
|
||||
* 方法名称:获取主键, 具体查看BaseEntity中的属性名称
|
||||
*/
|
||||
public static final String GET_ID = "getId";
|
||||
/**
|
||||
* 方法名称:设置更新时间, 具体查看BaseEntity中的属性名称
|
||||
*/
|
||||
public static final String SET_UPDATE_TIME = "setUpdateTime";
|
||||
/**
|
||||
* 错误提示:当Entity类没有标注注解@Table(javax.persistence.Table)时, EntityMapper继承了BaseMapper后报错
|
||||
*/
|
||||
public static final String TX_TABLE_NONE =
|
||||
"POJO类中没有@Table注解, 不能使用BaseMapper接口, 如需使用BaseMapper接口, 请加上注解javax.persistence.Table";
|
||||
/**
|
||||
* 错误提示:当分页对象 Page 为null时的提示
|
||||
*/
|
||||
public static final String TX_PAGE_NULL = "分页对象Page不能为空";
|
||||
/**
|
||||
* SQL条件表达式:有效数据
|
||||
*/
|
||||
public static final String EX_SQL_EFFECTIVE_DATA = "delete_flag=0";
|
||||
/**
|
||||
* SQL条件表达式:无效数据
|
||||
*/
|
||||
public static final String EX_SQL_UNEFFECTIVE_DATA = "delete_flag=1";
|
||||
/**
|
||||
* SQL条件表达式:通用统计
|
||||
*/
|
||||
public static final String EX_SQL_CUSTOM_COUNT = "count(0)";
|
||||
/**
|
||||
* SQL条件表达式:分页
|
||||
*/
|
||||
public static final String PR_SQL_PAGE = " LIMIT {}, {}";
|
||||
/**
|
||||
* SQL参数字段:创建时间、主键
|
||||
*/
|
||||
public static final String PR_SQL_ORDER_ID = "create_time desc";
|
||||
/**
|
||||
* SQL查找方法名称头
|
||||
*/
|
||||
public static final String PH_SQL_FIND = "find";
|
||||
/**
|
||||
* GET
|
||||
*/
|
||||
public static final String PH_SQL_GET = "get";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
package cn.odboy.zilean.mybatis.core;
|
||||
|
||||
import cn.odboy.zilean.mybatis.entity.BaseEntity;
|
||||
import cn.odboy.zilean.mybatis.page.Page;
|
||||
import org.apache.ibatis.annotations.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO 通用Dao接口
|
||||
* <p>MyBatis提供了2个注解标记:@Select(只能处理字符串常量) 和 @SelectProvider(可以使用一个SQL提供程序来生成相应的SQL语句)
|
||||
* <p>这几个注解声明在Mapper对应的interface的方法上的,注解用于生成查询用的sql语句
|
||||
* 如果对应的Mapper中已使用@Param来注解参数,则在对应的Prodiver的方法中无需写参数
|
||||
* <p>注解中的参数: type参数指定的Class类,必须要能够通过无参的构造函数来初始化
|
||||
* method参数指定的方法,必须是public的,返回值必须为String,可以为static
|
||||
* <p>重点:在Mapper接口和@SelectProvide方法类中,不要使用重载,也就是说,不要使用方法名相同参数不同的方法
|
||||
* @time: 2019/8/8 10:41
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
public interface BaseDao<T extends BaseEntity> {
|
||||
/**
|
||||
* 选择性插入(非空属性值), 并返回受影响的行数
|
||||
* <p>
|
||||
* 插入后,可获取到id的值
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @return 受影响的行数
|
||||
*/
|
||||
@InsertProvider(type = SqlBuilder.class, method = "insertSelective")
|
||||
@Options(useGeneratedKeys = true, keyProperty = "id")
|
||||
int insertSelective(T entity);
|
||||
|
||||
/**
|
||||
* 通过ID删除, 并返回受影响的行数
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 受影响的行数
|
||||
*/
|
||||
@UpdateProvider(type = SqlBuilder.class, method = "deleteById")
|
||||
int deleteById(Long id);
|
||||
|
||||
/**
|
||||
* 通过ID更新, 并返回受影响的行数
|
||||
*
|
||||
* @param entity 实体对象
|
||||
* @return 受影响的行数
|
||||
*/
|
||||
@UpdateProvider(type = SqlBuilder.class, method = "updateSelectiveById")
|
||||
int updateSelectiveById(T entity);
|
||||
|
||||
/**
|
||||
* 根据ID查询, 并返回单个实体对象
|
||||
* 注解ResultMap的意思是从sql的执行结果集中取数据,拼装成Enitity的实体类
|
||||
* 当mapper中传入的参数是使用@param
|
||||
* 注解修饰,在xxxProvider类中必须使用Map对象接收参数
|
||||
*
|
||||
* @param id 主键ID
|
||||
* @return 实体对象
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "selectOneById")
|
||||
T selectOneById(Long id);
|
||||
|
||||
/**
|
||||
* 通过类属性和值查询,并返回实体对象集合
|
||||
*
|
||||
* @param nav 类属性名称和值的容器
|
||||
* @return 实体对象集合
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "selectByNav")
|
||||
List<T> selectByNav(@Param("nav") EntityPropNav nav);
|
||||
|
||||
/**
|
||||
* 通过类属性和值模糊查询,并返回实体对象集合
|
||||
*
|
||||
* @param nav 类属性名称和值的容器
|
||||
* @return 实体对象集合
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "selectByLikeNav")
|
||||
List<T> selectByLikeNav(@Param("nav") EntityPropNav nav);
|
||||
|
||||
/**
|
||||
* 分页获取对象, 并返回实体对象集合
|
||||
*
|
||||
* @param entity 查询对象
|
||||
* @param page 分页对象
|
||||
* @return 实体对象集合
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "selectByPage")
|
||||
List<T> selectByPage(@Param("entity") T entity, @Param("page") Page page);
|
||||
|
||||
/**
|
||||
* 不分页, 查询所有(存在全表查询风险,不建议大表与超大表使用)
|
||||
*
|
||||
* @param entity 查询对象entity
|
||||
* @return 实体对象集合
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "selectAll")
|
||||
List<T> selectAll(@Param("entity") T entity);
|
||||
|
||||
/**
|
||||
* 不分页获取范围内对象, 并返回实体对象集合(这个估计会有点bug,如果查询字符串得加单引号不然mybatis会以为它是数据库字段名称)
|
||||
*
|
||||
* @param propName 对象属性名称
|
||||
* @param propValues 对象属性值集合
|
||||
* @return 实体对象集合
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "selectAllInValues")
|
||||
List<T> selectAllInValues(@Param("propName") String propName, @Param("propValues") List<Object> propValues);
|
||||
|
||||
/**
|
||||
* 条件统计数量
|
||||
*
|
||||
* @param entity 查询对象entity
|
||||
* @return 总数量
|
||||
*/
|
||||
@SelectProvider(type = SqlBuilder.class, method = "countAll")
|
||||
long countAll(@Param("entity") T entity);
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package cn.odboy.zilean.mybatis.core;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO 对象属性名称和值(容器)
|
||||
* @time: 2019/8/10 3:37
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
@Getter
|
||||
@ToString
|
||||
@Log4j2
|
||||
public class EntityPropNav implements Serializable {
|
||||
private static EntityPropNav cloneObj = new EntityPropNav();
|
||||
|
||||
/**
|
||||
* 对象属性名称
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* 对象属性值
|
||||
*/
|
||||
public Object value;
|
||||
|
||||
/**
|
||||
* 私有化构造函数,不得从外部new
|
||||
*/
|
||||
private EntityPropNav() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象克隆实例, 适合频繁new的场景
|
||||
*
|
||||
* @param name 对象属性名称
|
||||
* @param value 对象属性值
|
||||
* @return EntityPropNav
|
||||
*/
|
||||
public static EntityPropNav build(String name, Object value) {
|
||||
return ObjectUtil.cloneByStream(cloneObj).setName(name).setValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对象属性名称
|
||||
*
|
||||
* @param name 对象属性名称
|
||||
*/
|
||||
public EntityPropNav setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置对象属性值
|
||||
*
|
||||
* @param value 对象属性值
|
||||
*/
|
||||
public EntityPropNav setValue(Object value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,445 @@
|
||||
package cn.odboy.zilean.mybatis.core;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.date.DateTime;
|
||||
import cn.hutool.core.util.PageUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.odboy.zilean.common.constant.GlobalConsts;
|
||||
import cn.odboy.zilean.mybatis.constant.SqlConsts;
|
||||
import cn.odboy.zilean.mybatis.entity.BaseEntity;
|
||||
import cn.odboy.zilean.mybatis.page.Page;
|
||||
import cn.odboy.zilean.mybatis.util.BeanColumnUtils;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.extern.log4j.Log4j2;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.builder.annotation.ProviderContext;
|
||||
import org.apache.ibatis.jdbc.SQL;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
|
||||
import javax.persistence.Table;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO SQL构造器
|
||||
* @time: 2019/8/8 10:35
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
@Log4j2
|
||||
public class SqlBuilder<T extends BaseEntity> {
|
||||
/**
|
||||
* 表名
|
||||
*/
|
||||
private String tableName = null;
|
||||
/**
|
||||
* 表字段映射
|
||||
*/
|
||||
private String baseColumnList = null;
|
||||
/**
|
||||
* Bean属性名称
|
||||
*/
|
||||
private List<String> beanNames = new ArrayList<>(GlobalConsts.DEFAULT_COLLECTIONS_SIZE);
|
||||
/**
|
||||
* Bean属性名称-->数据库表名 映射关系
|
||||
*/
|
||||
private Map<String, String> beanTableMap = new HashMap<>(GlobalConsts.DEFAULT_COLLECTIONS_SIZE);
|
||||
/**
|
||||
* 数据库表名-->get方法名称
|
||||
*/
|
||||
private Map<String, String> tableGetNameMap = new HashMap<>(GlobalConsts.DEFAULT_COLLECTIONS_SIZE);
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
*
|
||||
* @param context ProviderContext
|
||||
* @throws Exception
|
||||
*/
|
||||
private void init(ProviderContext context) throws Exception {
|
||||
if (StrUtil.isBlank(tableName)) {
|
||||
if (!initTableName(context)) {
|
||||
throw new RuntimeException(SqlConsts.TX_TABLE_NONE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取并设置表名
|
||||
*
|
||||
* @param context ProviderContext
|
||||
* @return boolean
|
||||
*/
|
||||
private boolean initTableName(ProviderContext context) throws Exception {
|
||||
Class mapperType = context.getMapperType();
|
||||
// 强制转换为“参数化类型” [BaseDao<T extends BaseEntity>]
|
||||
ParameterizedType genericSuperclass = (ParameterizedType) mapperType.getGenericInterfaces()[0];
|
||||
// Class类是Type接口的实现类
|
||||
// 获取参数化类型中,实际类型的定义 [new Type[]{T.class}]
|
||||
// 获取数据的第一个元素:T.class
|
||||
// 当前运行类的参数化类型中的实际的类型, 比如BaseMapper<User>, 此处的Class为User.class
|
||||
Class clazz = (Class) genericSuperclass.getActualTypeArguments()[0];
|
||||
// 获取表名
|
||||
// 当entity类有注解时
|
||||
// @javax.persistence.Table(name=sso_user, ...), 自动建表的表名称不得以"t_"或其他前缀开头,只能是类名下换线命名
|
||||
// 没有注解, 返回null
|
||||
Table table = AnnotationUtils.getAnnotation(clazz, Table.class);
|
||||
if (table != null) {
|
||||
this.tableName = table.name();
|
||||
// 获取bean属性名称
|
||||
// 根据jpa内定策略转换为表字段名称
|
||||
Field[] fields = ReflectUtil.getFields(clazz);
|
||||
String sqlColumnName, fieldName;
|
||||
for (Field field : fields) {
|
||||
fieldName = field.getName();
|
||||
sqlColumnName = BeanColumnUtils.getDataBaseColumnName(fieldName);
|
||||
// 建立映射关系
|
||||
beanNames.add(fieldName);
|
||||
beanTableMap.put(fieldName, sqlColumnName);
|
||||
tableGetNameMap.put(sqlColumnName, SqlConsts.PH_SQL_GET + BeanColumnUtils.toUpperCaseFirstOne(fieldName));
|
||||
// 设置查询字段
|
||||
// 定义临时变量
|
||||
StringBuilder column = new StringBuilder();
|
||||
// fix bug: 20190703 由于驼峰命名的原因导致查出来的数据不能设置到实体类中
|
||||
for (Map.Entry<String, String> entry : this.beanTableMap.entrySet()) {
|
||||
// value, 即实体类对应的表字段名称
|
||||
column.append(entry.getValue()).append(" as ");
|
||||
// value, 即实体类本身的属性名称
|
||||
column.append(entry.getKey()).append(",");
|
||||
}
|
||||
// 去除末尾的逗号
|
||||
this.baseColumnList = column.substring(0, column.length() - 1);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 选择性插入
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param entity <T extends BaseEntity>
|
||||
* @return SQL
|
||||
*/
|
||||
public String insertSelective(ProviderContext context, T entity) throws Exception {
|
||||
this.init(context);
|
||||
if (entity == null) {
|
||||
throw new RuntimeException("entity不能为null");
|
||||
}
|
||||
// 非空属性数量
|
||||
int nonNullPropSize = 0;
|
||||
// 参数字段 有序合集
|
||||
List<String> columns = new ArrayList<>(GlobalConsts.DEFAULT_COLLECTIONS_SIZE);
|
||||
// 参数字段值 有序合集
|
||||
List<String> values = new ArrayList<>(GlobalConsts.DEFAULT_COLLECTIONS_SIZE);
|
||||
List<String> nonNullList = getNonNullList(entity, beanNames, tableGetNameMap, beanTableMap);
|
||||
for (String beanName : nonNullList) {
|
||||
// 此处不能用nonNullPropSize++, ++操作符是线程不安全的
|
||||
nonNullPropSize = nonNullPropSize + 1;
|
||||
// 获取属性名称
|
||||
columns.add(beanTableMap.get(beanName));
|
||||
values.add("#{" + beanName + "}");
|
||||
}
|
||||
// 判断是不是什么都没做
|
||||
if (nonNullPropSize == 0) {
|
||||
throw new RuntimeException("至少有一个字段有值!");
|
||||
}
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.INSERT_INTO(SqlBuilder.this.tableName);
|
||||
sql.INTO_COLUMNS(columns.toArray(new String[0]));
|
||||
sql.INTO_VALUES(values.toArray(new String[0]));
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("Entity -> " + JSON.toJSONString(entity));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过ID(逻辑)删除
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param id 主键值
|
||||
* @return SQL
|
||||
*/
|
||||
public String deleteById(ProviderContext context, Long id) throws Exception {
|
||||
this.init(context);
|
||||
if (id == null) {
|
||||
throw new RuntimeException("id不能为null");
|
||||
}
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.UPDATE(this.tableName);
|
||||
sql.SET(SqlConsts.EX_SQL_UNEFFECTIVE_DATA);
|
||||
sql.WHERE(SqlConsts.PRIMARY_KEY_NAME + "=#{" + SqlConsts.PRIMARY_KEY_NAME + "}");
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("ID -> " + id);
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过ID更新
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param entity <T extends BaseEntity>
|
||||
* @return SQL
|
||||
*/
|
||||
public String updateSelectiveById(ProviderContext context, T entity) throws Exception {
|
||||
this.init(context);
|
||||
log.info(JSON.toJSONString(context));
|
||||
// 如果ID为空
|
||||
if (ReflectUtil.invoke(entity, SqlConsts.GET_ID) == null) {
|
||||
throw new RuntimeException("id不能为null");
|
||||
}
|
||||
// 设置更新时间
|
||||
ReflectUtil.invoke(entity, SqlConsts.SET_UPDATE_TIME, DateTime.now());
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.UPDATE(this.tableName);
|
||||
List<String> nonNullList = getNonNullList(entity, beanNames, tableGetNameMap, beanTableMap);
|
||||
for (String beanName : nonNullList) {
|
||||
// 不更新id字段
|
||||
if (SqlConsts.PRIMARY_KEY_NAME.equalsIgnoreCase(beanName)) {
|
||||
continue;
|
||||
}
|
||||
// 配置映射关系
|
||||
sql.SET(this.beanTableMap.get(beanName) + "=#{" + beanName + "}");
|
||||
}
|
||||
sql.WHERE(SqlConsts.PRIMARY_KEY_NAME + "=#{" + SqlConsts.PRIMARY_KEY_NAME + "}");
|
||||
sql.AND();
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("Entity -> " + JSON.toJSONString(entity));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过ID查询
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param id 主键
|
||||
* @return SQL
|
||||
*/
|
||||
public String selectOneById(ProviderContext context, Long id) throws Exception {
|
||||
this.init(context);
|
||||
if (id == null) {
|
||||
throw new RuntimeException("id不能为null");
|
||||
}
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(this.baseColumnList);
|
||||
sql.FROM(this.tableName);
|
||||
sql.WHERE(SqlConsts.PRIMARY_KEY_NAME + "=" + id);
|
||||
sql.AND();
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("ID -> " + id);
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过类属性和值查询,并返回实体对象集合
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param nav 类属性名称和值的容器
|
||||
* @return SQL
|
||||
*/
|
||||
public String selectByNav(ProviderContext context, @Param("nav") EntityPropNav nav) throws Exception {
|
||||
this.init(context);
|
||||
if (nav == null) {
|
||||
throw new RuntimeException("nav不能为null");
|
||||
}
|
||||
if (nav.getName() == null) {
|
||||
throw new RuntimeException("nav.name不能为null");
|
||||
}
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(this.baseColumnList);
|
||||
sql.FROM(this.tableName);
|
||||
sql.WHERE(beanTableMap.get(String.valueOf(nav.name)) + "=#{nav.value}");
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
sql.ORDER_BY(SqlConsts.PR_SQL_ORDER_ID);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("Nav -> " + JSON.toJSONString(nav));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过类属性和值模糊查询,并返回实体对象集合
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param nav 类属性名称和值的容器
|
||||
* @return SQL
|
||||
*/
|
||||
public String selectByLikeNav(ProviderContext context, @Param("nav") EntityPropNav nav) throws Exception {
|
||||
this.init(context);
|
||||
if (nav == null) {
|
||||
throw new RuntimeException("nav不能为null");
|
||||
}
|
||||
if (nav.getName() == null) {
|
||||
throw new RuntimeException("nav.name不能为null");
|
||||
}
|
||||
if (nav.getValue() == null) {
|
||||
throw new RuntimeException("nav.value不能为null");
|
||||
}
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(this.baseColumnList);
|
||||
sql.FROM(this.tableName);
|
||||
sql.WHERE(beanTableMap.get(String.valueOf(nav.name)) + " like CONCAT('%',#{nav.value},'%')");
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
sql.ORDER_BY(SqlConsts.PR_SQL_ORDER_ID);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("Nav -> " + JSON.toJSONString(nav));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页获取对象, 并返回实体对象集合
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param entity 查询对象
|
||||
* @param page 分页对象
|
||||
* @return SQL
|
||||
*/
|
||||
public String selectByPage(ProviderContext context, @Param("entity") T entity, @Param("page") Page page)
|
||||
throws Exception {
|
||||
this.init(context);
|
||||
if (page == null) {
|
||||
throw new RuntimeException(SqlConsts.TX_PAGE_NULL);
|
||||
}
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(this.baseColumnList);
|
||||
sql.FROM(this.tableName);
|
||||
List<String> nonNullList = getNonNullList(entity, beanNames, tableGetNameMap, beanTableMap);
|
||||
for (String beanName : nonNullList) {
|
||||
sql.WHERE(this.beanTableMap.get(beanName) + "=#{entity." + beanName + "}");
|
||||
}
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
int[] startEndIndex = PageUtil.transToStartEnd(page.getPage(), page.getPageSize());
|
||||
sql.ORDER_BY(SqlConsts.PR_SQL_ORDER_ID + StrUtil.format(SqlConsts.PR_SQL_PAGE, startEndIndex[0], startEndIndex[1]));
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("entity -> " + JSON.toJSONString(entity));
|
||||
log.info("Page -> " + JSON.toJSONString(page));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 不分页, 查询所有(存在全表查询风险,不建议大表与超大表使用)
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param entity 非空, 查询对象entity
|
||||
* @return SQL
|
||||
*/
|
||||
public String selectAll(ProviderContext context, @Param("entity") T entity) throws Exception {
|
||||
this.init(context);
|
||||
// 组装SQL
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(this.baseColumnList);
|
||||
sql.FROM(this.tableName);
|
||||
List<String> nonNullList = getNonNullList(entity, beanNames, tableGetNameMap, beanTableMap);
|
||||
for (String beanName : nonNullList) {
|
||||
sql.WHERE(this.beanTableMap.get(beanName) + "=#{entity." + beanName + "}");
|
||||
}
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
sql.ORDER_BY(SqlConsts.PR_SQL_ORDER_ID);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("entity -> " + JSON.toJSONString(entity));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 不分页获取范围内对象, 并返回实体对象集合(这个估计会有点bug,如果查询字符串得加单引号不然mybatis会以为它是数据库字段名称)
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param propName 对象属性名称
|
||||
* @param propValues 对象属性值集合
|
||||
* @return SQL
|
||||
*/
|
||||
public String selectAllInValues(ProviderContext context, @Param("propName") String propName,
|
||||
@Param("propValues") List<Object> propValues) throws Exception {
|
||||
this.init(context);
|
||||
if (propName == null) {
|
||||
throw new RuntimeException("propName不能为null");
|
||||
}
|
||||
if (CollectionUtil.isEmpty(propValues)) {
|
||||
throw new RuntimeException("propValues不能为null、或存在为null的对象");
|
||||
}
|
||||
// 组合ID
|
||||
StringBuilder idsArrays = new StringBuilder();
|
||||
for (Object propValue : propValues) {
|
||||
idsArrays.append(propValue);
|
||||
idsArrays.append(",");
|
||||
}
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(this.baseColumnList);
|
||||
sql.FROM(this.tableName);
|
||||
sql.WHERE(beanTableMap.get(propName) + " in (" + idsArrays.substring(0, idsArrays.length() - 1) + ")");
|
||||
sql.AND();
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("propName -> " + propName);
|
||||
log.info("propValues -> " + JSON.toJSONString(propValues));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 条件统计数量
|
||||
*
|
||||
* @param context 上下文
|
||||
* @param entity 非空, 查询对象entity
|
||||
* @return SQL
|
||||
*/
|
||||
public String countAll(ProviderContext context, @Param("entity") T entity) throws Exception {
|
||||
this.init(context);
|
||||
SQL sql = new SQL();
|
||||
sql.SELECT(SqlConsts.EX_SQL_CUSTOM_COUNT);
|
||||
sql.FROM(this.tableName);
|
||||
List<String> nonNullList = getNonNullList(entity, beanNames, tableGetNameMap, beanTableMap);
|
||||
for (String beanName : nonNullList) {
|
||||
sql.WHERE(this.beanTableMap.get(beanName) + "=#{entity." + beanName + "}");
|
||||
}
|
||||
sql.WHERE(SqlConsts.EX_SQL_EFFECTIVE_DATA);
|
||||
log.info("SQL -> " + sql.toString());
|
||||
log.info("entity -> " + JSON.toJSONString(entity));
|
||||
return sql.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取非空属性合集
|
||||
*
|
||||
* @param assetObj 被校验对象
|
||||
* @param assetObjProps 被校验对象所有属性名称
|
||||
* @param tableGetNameMap 表列名与对象GET属性方法名称的映射关系
|
||||
* @param beanTableMap 对象属性名称与表列名的映射关系
|
||||
* @return List<String>
|
||||
*/
|
||||
private List<String> getNonNullList(Object assetObj, List<String> assetObjProps, Map<String, String> tableGetNameMap,
|
||||
Map<String, String> beanTableMap) {
|
||||
List<String> result = new ArrayList<>(GlobalConsts.DEFAULT_COLLECTIONS_SIZE);
|
||||
//assetObj不为空,即有查询条件的分页
|
||||
if (assetObj != null) {
|
||||
// 类属性值
|
||||
Object beanPropValue;
|
||||
// 遍历类属性
|
||||
for (String assetObjProp : assetObjProps) {
|
||||
// 1、通过beanName获取表字段名称
|
||||
// 2、通过表字段名称获取get方法名称
|
||||
// 3、通过反射获取属性值
|
||||
beanPropValue = ReflectUtil.invoke(assetObj, tableGetNameMap.get(beanTableMap.get(assetObjProp)));
|
||||
// 如果属性值不为null
|
||||
if (beanPropValue != null) {
|
||||
result.add(assetObjProp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package cn.odboy.zilean.mybatis.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO BaseEntity 与数据库表结构一一对应,通过DAO层向上传输数据源对象(即Entity)
|
||||
* @time: 2019/8/8 10:42
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
@MappedSuperclass
|
||||
public abstract class BaseEntity implements Serializable {
|
||||
/**
|
||||
* 自增主键
|
||||
*/
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@Column(columnDefinition = "BIGINT(20) UNIQUE NOT NULL COMMENT '自增主键'")
|
||||
protected Long id;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@Column(columnDefinition = "DATETIME NOT NULL COMMENT '创建时间'")
|
||||
protected Date createTime;
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@Column(columnDefinition = "DATETIME COMMENT '更新时间'")
|
||||
protected Date updateTime;
|
||||
/**
|
||||
* 软删除标识(1、已删除 0、未删除)
|
||||
*/
|
||||
@Column(columnDefinition = "TINYINT(1) NOT NULL DEFAULT 0 COMMENT '软删除标识'")
|
||||
protected Integer deleteFlag;
|
||||
/**
|
||||
* 备注信息
|
||||
*/
|
||||
@Column(columnDefinition = "VARCHAR(100) NOT NULL DEFAULT '' COMMENT '备注信息'")
|
||||
protected String remark;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package cn.odboy.zilean.mybatis.page;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO 页面索引、数据数量
|
||||
* @time: 2019/8/8 10:43
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class Page implements Serializable {
|
||||
private Integer page = 1;
|
||||
private Integer pageSize = 10;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package cn.odboy.zilean.mybatis.page;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO 分页对象
|
||||
* @time: 2019/8/8 10:43
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class Pagination<T> implements Serializable {
|
||||
/**
|
||||
* 数据集合
|
||||
*/
|
||||
private List<T> rows;
|
||||
/**
|
||||
* 数据总数
|
||||
*/
|
||||
private Long total;
|
||||
/**
|
||||
* 页面参数
|
||||
*/
|
||||
private Page page;
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
package cn.odboy.zilean.mybatis.util;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* @author: Odboy
|
||||
* @version: Jdk 1.8
|
||||
* @desc: TODO 实体类属性名与数据库字段名互转
|
||||
* @time: 2019/8/8 10:43
|
||||
* @blog: www.odboy.cn
|
||||
*/
|
||||
public final class BeanColumnUtils {
|
||||
private BeanColumnUtils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 类属性名称转SQL字段名
|
||||
*
|
||||
* @param beanPropName 类属性名称
|
||||
* @return
|
||||
*/
|
||||
public static String getDataBaseColumnName(String beanPropName) {
|
||||
if (!StringUtils.isEmpty(beanPropName)) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (char c : beanPropName.toCharArray()) {
|
||||
if (Character.isUpperCase(c)) {
|
||||
sb.append("_").append(Character.toLowerCase(c));
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
throw new NullPointerException("beanPropName不能为null");
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回有的值条件,比如有个User类,有属性name,id
|
||||
* 当只有id有值时,返回and id ={id的值}
|
||||
*
|
||||
* @return
|
||||
* @throws
|
||||
* @author ld
|
||||
* @date 2019/02/11 14:13
|
||||
*/
|
||||
public String gainConditionFromObjectByField(Object object) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
// 取出所有属性
|
||||
Field[] fields = object.getClass().getDeclaredFields();
|
||||
for (Field f : fields) {
|
||||
String fieldName = f.getName();
|
||||
// 取属性值
|
||||
Object value = getFieldValue(this, fieldName);
|
||||
if (ObjectUtil.isNotNull(value)) {
|
||||
Class<?> type = f.getType();
|
||||
if ("class java.lang.String".equals(type.toString())) {
|
||||
sb.append(" and ").append(fieldName).append("='").append(value).append("'");
|
||||
} else {
|
||||
sb.append(" and ").append(fieldName).append("=").append(value);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字段值
|
||||
*
|
||||
* @param object 对象
|
||||
* @param fieldName 类的属性名称
|
||||
* @return 字段值
|
||||
*/
|
||||
private String getFieldValue(Object object, String fieldName) {
|
||||
Object o = invokeMethod(object, fieldName);
|
||||
return ObjectUtil.isNotNull(o) ? o.toString() : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 执行某个Field的getField方法
|
||||
*
|
||||
* @param object 对象
|
||||
* @param fieldName 类的属性名称
|
||||
* @return Object
|
||||
*/
|
||||
private Object invokeMethod(Object object, String fieldName) {
|
||||
Class<?> testClass = object.getClass();
|
||||
// 首字母大写
|
||||
// fieldName -> FieldName
|
||||
String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
|
||||
try {
|
||||
return ReflectUtil.invoke(testClass, "get" + methodName);
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 首字母转大写
|
||||
*
|
||||
* @param s String
|
||||
* @return String
|
||||
*/
|
||||
public static String toUpperCaseFirstOne(String s) {
|
||||
|
||||
if (Character.isUpperCase(s.charAt(0))) {
|
||||
// 如果第一位为大写字母, 直接返回
|
||||
return s;
|
||||
} else {
|
||||
return String.valueOf(Character.toUpperCase(s.charAt(0))) + s.substring(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user