├── .gitignore ├── .settings └── .gitignore ├── src └── main │ ├── java │ └── com │ │ └── mingri │ │ └── mybatissmart │ │ ├── barracks │ │ ├── package-info.java │ │ ├── IdtacticsEnum.java │ │ ├── MybatisSmartException.java │ │ ├── Constant.java │ │ ├── SqlKwd.java │ │ ├── DialectEnum.java │ │ ├── SqlPrint.java │ │ └── Tool.java │ │ ├── dbo │ │ ├── package-info.java │ │ ├── SmartColumnInfo.java │ │ ├── SetSql.java │ │ ├── WhereNode.java │ │ ├── MapperSql.java │ │ ├── MapperSqlTool.java │ │ ├── SmartTableInfo.java │ │ └── Where.java │ │ ├── mapper │ │ ├── package-info.java │ │ ├── SmartMapper.java │ │ ├── InternalMapper.java │ │ ├── DeleteSmartMapper.java │ │ ├── InsertSmartMapper.java │ │ ├── UpdateSmartMapper.java │ │ └── SelectSmartMapper.java │ │ ├── config │ │ ├── ConfigurationCustomizer.java │ │ ├── SmartProperties.java │ │ ├── SpringBootVFS.java │ │ ├── MappingConfig.java │ │ ├── MybatisSmartAutoConfiguration.java │ │ └── MybatisSmartContext.java │ │ ├── annotation │ │ ├── SmartTable.java │ │ └── SmartColumn.java │ │ ├── ex │ │ ├── SmartKeyGenerator.java │ │ ├── SmartConfiguration.java │ │ └── MybatisProperties.java │ │ └── provider │ │ ├── SqlBuildParam.java │ │ └── MapperSqlProvider.java │ └── resources │ └── META-INF │ └── spring.factories ├── .classpath └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | /.project 3 | /bin/ 4 | -------------------------------------------------------------------------------- /.settings/.gitignore: -------------------------------------------------------------------------------- 1 | /org.eclipse.jdt.core.prefs 2 | /org.eclipse.m2e.core.prefs 3 | /org.eclipse.core.resources.prefs 4 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 兵营:这里有 常量、一些处理工具、普通类...... 3 | * @author ljl 4 | * 5 | */ 6 | package com.mingri.mybatissmart.barracks; -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 数据库相关: 3 | * 表映射类、列和字段映射类、sql类相关 4 | * @author ljl 5 | * 6 | */ 7 | package com.mingri.mybatissmart.dbo; -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/package-info.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * mapper相关,也就是对应数据库的dao层 4 | * @author ljl 5 | * 6 | */ 7 | package com.mingri.mybatissmart.mapper; -------------------------------------------------------------------------------- /src/main/resources/META-INF/spring.factories: -------------------------------------------------------------------------------- 1 | # Auto Configure 2 | org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ 3 | com.mingri.mybatissmart.config.MybatisSmartAutoConfiguration -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/SmartMapper.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.mapper; 2 | 3 | public interface SmartMapper extends InsertSmartMapper,DeleteSmartMapper,UpdateSmartMapper,SelectSmartMapper { 4 | 5 | 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/IdtacticsEnum.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | /** 4 | * id生成策略 5 | * 6 | */ 7 | public enum IdtacticsEnum { 8 | 9 | 10 | /** 11 | * 数据库自增 12 | */ 13 | SQL_INCR, 14 | 15 | 16 | /** 17 | * mybatis-smart 默认生成 18 | */ 19 | DFT, 20 | 21 | 22 | /** 23 | * 自定义 24 | */ 25 | DEFINED 26 | } -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/MybatisSmartException.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | 4 | public class MybatisSmartException extends RuntimeException { 5 | 6 | 7 | /** 8 | * 9 | */ 10 | private static final long serialVersionUID = 6866945517200513981L; 11 | 12 | public MybatisSmartException(String string) { 13 | super(string); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/Constant.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | public interface Constant { 4 | 5 | /** 6 | * Mapper 实体类参数(表映射类)名称 7 | */ 8 | static final String PARAM_KEY = "ek"; 9 | /** 10 | * Mapper参数名称: 表映射类 11 | */ 12 | static final String TABLE_KEY = "tbk"; 13 | /** 14 | * Mapper insert函数名称 15 | */ 16 | static final String INSERT_METHOD = "inserts"; 17 | 18 | /** 19 | * Mapper where参数名称 20 | */ 21 | static final String COND_KEY = "condk"; 22 | 23 | 24 | public static final String SPACE = " "; 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/config/ConfigurationCustomizer.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.config; 2 | 3 | import org.apache.ibatis.session.Configuration; 4 | 5 | /** 6 | * Callback interface that can be customized a {@link Configuration} object generated on auto-configuration. 7 | * 8 | * @author Kazuki Shimizu 9 | * @since 1.2.1 10 | */ 11 | @FunctionalInterface 12 | public interface ConfigurationCustomizer { 13 | 14 | /** 15 | * Customize the given a {@link Configuration} object. 16 | * 17 | * @param configuration 18 | * the configuration object to customize 19 | */ 20 | void customize(Configuration configuration); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/InternalMapper.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | import org.apache.ibatis.annotations.Select; 7 | 8 | /** 9 | * 内部mapper,不提供外外部使用 10 | * @author ljl 11 | * 12 | */ 13 | public interface InternalMapper { 14 | 15 | @Select("SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME=#{tableName}") 16 | List selectFields(@Param("tableName") String tableName); 17 | 18 | /** 19 | * 查询表字段的statement 20 | */ 21 | static final String SELECTFIELDS_STATEMENT = InternalMapper.class.getCanonicalName() + ".selectFields"; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/SqlKwd.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | /** 4 | * sql 关键字 5 | * @author ljl 6 | * 7 | */ 8 | public interface SqlKwd { 9 | static final String WHERE_PRE = " where "; 10 | static final String ORDER_BY = " order by "; 11 | static final String LIMIT = " limit "; 12 | static final String OFFSET = " offset "; 13 | static final String FROM = " from "; 14 | static final String INSERT_INTO = " insert into "; 15 | static final String SELECT = " select "; 16 | static final String UPDATE = " update "; 17 | static final String DELETE = " delete "; 18 | static final String SET = " set "; 19 | static final String AS = " as "; 20 | } -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/DialectEnum.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | import com.mingri.langhuan.cabinet.tool.StrTool; 4 | 5 | /** 6 | * 数据库方言枚举 7 | * @author ljl 8 | * 9 | */ 10 | public enum DialectEnum { 11 | 12 | MYSQL("mysql"), 13 | SQLSERVER("sqlserver"); 14 | public final String name; 15 | 16 | private DialectEnum(String name) { 17 | this.name=name; 18 | } 19 | 20 | public static DialectEnum ofName(String name) { 21 | if(StrTool.isEmpty(name)) { 22 | return null; 23 | } 24 | for (DialectEnum dialect : DialectEnum.values()) { 25 | if(dialect.name.equals(name)) { 26 | return dialect; 27 | } 28 | } 29 | return null; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/SmartColumnInfo.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import java.lang.reflect.Field; 4 | 5 | import com.mingri.mybatissmart.annotation.SmartColumn; 6 | 7 | public class SmartColumnInfo { 8 | 9 | private Field field; 10 | private SmartColumn smartColumn; 11 | 12 | public SmartColumnInfo(Field field, SmartColumn columnInfo) { 13 | super(); 14 | this.field = field; 15 | this.smartColumn = columnInfo; 16 | } 17 | 18 | public SmartColumnInfo() { 19 | } 20 | 21 | public Field getField() { 22 | return field; 23 | } 24 | 25 | 26 | public void setField(Field field) { 27 | this.field = field; 28 | } 29 | 30 | public SmartColumn getSmartColumn() { 31 | return smartColumn; 32 | } 33 | 34 | public void setSmartColumn(SmartColumn columnInfo) { 35 | this.smartColumn = columnInfo; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/SqlPrint.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | import org.slf4j.Logger; 4 | 5 | public class SqlPrint { 6 | 7 | private boolean isPrint = true; 8 | 9 | private static SqlPrint INSTANCE; 10 | 11 | public SqlPrint() { 12 | INSTANCE = this; 13 | } 14 | 15 | public boolean isPrint() { 16 | return isPrint; 17 | } 18 | 19 | public void setPrint(boolean isPrint) { 20 | this.isPrint = isPrint; 21 | } 22 | 23 | public static SqlPrint instance() { 24 | if (SqlPrint.INSTANCE == null) { 25 | synchronized (SqlPrint.class) { 26 | if (SqlPrint.INSTANCE == null) { 27 | SqlPrint.INSTANCE = new SqlPrint(); 28 | } 29 | } 30 | } 31 | return SqlPrint.INSTANCE; 32 | } 33 | 34 | public void print(Logger logger, String sql) { 35 | if (isPrint) { 36 | logger.info(sql); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/DeleteSmartMapper.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.mapper; 2 | 3 | import org.apache.ibatis.annotations.DeleteProvider; 4 | import org.apache.ibatis.annotations.Param; 5 | 6 | import com.mingri.mybatissmart.barracks.Constant; 7 | import com.mingri.mybatissmart.dbo.Where; 8 | import com.mingri.mybatissmart.provider.MapperSqlProvider; 9 | 10 | public interface DeleteSmartMapper{ 11 | 12 | @DeleteProvider(method = "deleteById", type = MapperSqlProvider.class) 13 | int deleteById(Object idV); 14 | 15 | @DeleteProvider(method = "delete", type = MapperSqlProvider.class) 16 | int deleteByObjAndWhere(@Param(Constant.PARAM_KEY) Object e, 17 | @Param(Constant.COND_KEY) Where filterSqlBuild); 18 | 19 | @DeleteProvider(method = "delete", type = MapperSqlProvider.class) 20 | int deleteByWhere(@Param(Constant.COND_KEY) Where filterSqlBuild); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/InsertSmartMapper.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.mapper; 2 | 3 | import org.apache.ibatis.annotations.InsertProvider; 4 | import org.apache.ibatis.annotations.Param; 5 | 6 | import com.mingri.mybatissmart.barracks.Constant; 7 | import com.mingri.mybatissmart.provider.MapperSqlProvider; 8 | 9 | /** 10 | * 11 | * @author ljl 12 | * @date 2020-11-12 Dscription: 13 | * 14 | */ 15 | public interface InsertSmartMapper { 16 | 17 | /** 18 | * 该类的函数名必须是{@code com.mingri.mybatissmart.barracks.Constant.INSERT_METHOD} 19 | * 为前缀,否则MybatisSmart配置的的id自增会失效 20 | * 21 | * @author ljl 22 | * @date 2020-11-12 23 | * @param e 要insert的对象或者集合,必须是"@SmartTable"的类或者子类 24 | * @return 25 | */ 26 | @InsertProvider(method = Constant.INSERT_METHOD, type = MapperSqlProvider.class) 27 | int inserts(@Param(Constant.PARAM_KEY) Object e); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/config/SmartProperties.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.config; 2 | 3 | import java.util.Map; 4 | 5 | import com.mingri.mybatissmart.barracks.SqlPrint; 6 | 7 | /** 8 | * 配置属性类 9 | * 10 | * @author ljl 2019年11月30日 11 | */ 12 | public class SmartProperties { 13 | 14 | 15 | /** 16 | * 表映射实体扫描包:key:包,value:sessionFactory的beanName 17 | */ 18 | private Map tablePackages; 19 | private SqlPrint sqlPrint; 20 | 21 | public Map getTablePackages() { 22 | return tablePackages; 23 | } 24 | 25 | public void setTablePackages(Map tablePackages) { 26 | this.tablePackages = tablePackages; 27 | } 28 | 29 | public SqlPrint getSqlPrint() { 30 | return sqlPrint; 31 | } 32 | 33 | public void setSqlPrint(SqlPrint sqlPrint) { 34 | this.sqlPrint = sqlPrint; 35 | } 36 | 37 | 38 | 39 | 40 | 41 | } -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/UpdateSmartMapper.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.mapper; 2 | 3 | import org.apache.ibatis.annotations.Param; 4 | import org.apache.ibatis.annotations.UpdateProvider; 5 | 6 | import com.mingri.mybatissmart.barracks.Constant; 7 | import com.mingri.mybatissmart.dbo.SetSql; 8 | import com.mingri.mybatissmart.dbo.Where; 9 | import com.mingri.mybatissmart.provider.MapperSqlProvider; 10 | 11 | public interface UpdateSmartMapper{ 12 | 13 | @UpdateProvider(method = "updateById", type = MapperSqlProvider.class) 14 | int updateById(@Param(Constant.PARAM_KEY) Object e); 15 | 16 | 17 | @UpdateProvider(method = "updateByWhere", type = MapperSqlProvider.class) 18 | int updateByWhere(@Param(Constant.PARAM_KEY) Object e, 19 | @Param(Constant.COND_KEY) Where filterSqlBuild); 20 | 21 | @UpdateProvider(method = "updateBySets", type = MapperSqlProvider.class) 22 | int updateBySets(@Param(Constant.PARAM_KEY) SetSql sets, 23 | @Param(Constant.COND_KEY) Where filterSqlBuild); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/annotation/SmartTable.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import org.springframework.core.annotation.AliasFor; 10 | 11 | import com.mingri.mybatissmart.barracks.IdtacticsEnum; 12 | 13 | /** 14 | * 数据库表信息 15 | * 16 | * @author ljl 17 | * 18 | */ 19 | @Target({ ElementType.TYPE }) 20 | @Retention(RetentionPolicy.RUNTIME) 21 | @Documented 22 | public @interface SmartTable { 23 | 24 | /** 25 | * 表名 26 | * 27 | * @return 表名 28 | */ 29 | String value() default ""; 30 | 31 | /** 32 | * 表名 33 | * 34 | * @return 表名 35 | */ 36 | @AliasFor("value") 37 | String name() default ""; 38 | 39 | /** 40 | * 41 | * 表别名 42 | * 43 | * @return 表别名 44 | */ 45 | String alias() default ""; 46 | 47 | /** 48 | * id生成策略 49 | * 50 | * @return id生成策略枚举 51 | */ 52 | IdtacticsEnum idtactics() default IdtacticsEnum.DFT; 53 | 54 | /** 55 | * id列对应的字段名称 56 | * 57 | * @return id字段 58 | */ 59 | String idFieldName() default "id"; 60 | } 61 | -------------------------------------------------------------------------------- /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/annotation/SmartColumn.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.annotation; 2 | 3 | import java.lang.annotation.Documented; 4 | import java.lang.annotation.ElementType; 5 | import java.lang.annotation.Retention; 6 | import java.lang.annotation.RetentionPolicy; 7 | import java.lang.annotation.Target; 8 | 9 | import com.mingri.langhuan.cabinet.constant.ObjTypeEnum; 10 | 11 | /** 12 | * 数据库列信息 13 | * 14 | * @author ljl 15 | * 16 | */ 17 | @Target({ ElementType.FIELD }) 18 | @Retention(RetentionPolicy.RUNTIME) 19 | @Documented 20 | public @interface SmartColumn { 21 | 22 | /** 23 | * 列名
24 | * 默认是"",则将字段名称转驼峰匹配:userName 配 user_name 或者 username 25 | * 26 | * @return 字段名称 27 | */ 28 | String value() default ""; 29 | 30 | /** 31 | * 值是 "",null 时不insert 32 | * 33 | * @return 要新增的值的类型 34 | */ 35 | ObjTypeEnum[] insertValType() default { ObjTypeEnum.OBJ }; 36 | 37 | /** 38 | * 值是 "",null 时不update 39 | * 40 | * @return 要更新的值的类型 41 | */ 42 | ObjTypeEnum[] updateValType() default { ObjTypeEnum.OBJ }; 43 | 44 | /** 45 | * 时间字段格式化,如果是日期类型,需要格式化,则配置此字段 46 | * 47 | * @return 日期格式化字符串 48 | */ 49 | String dateFormart() default ""; 50 | 51 | /** 52 | * 是否插入 53 | * 54 | * @return 布尔值 55 | */ 56 | boolean isInsert() default true; 57 | 58 | /** 59 | * 是否更新 60 | * 61 | * @return 布尔值 62 | */ 63 | boolean isUpdate() default true; 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/SetSql.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | 6 | public class SetSql { 7 | 8 | // 该字段名字不能随便修改,有#{}中使用 9 | private Map sets = new LinkedHashMap<>(); 10 | private boolean setEmpty = false; 11 | 12 | Map getSets() { 13 | return sets; 14 | } 15 | 16 | private SetSql() { 17 | } 18 | 19 | boolean isSetEmpty() { 20 | return setEmpty; 21 | } 22 | 23 | public static Builder builder() { 24 | Builder b=new Builder(); 25 | return b; 26 | } 27 | public static Builder builder(String column, Object value) { 28 | Builder b=new Builder(column,value); 29 | return b; 30 | } 31 | 32 | public static class Builder { 33 | 34 | private SetSql setSql; 35 | 36 | public Builder() { 37 | setSql = new SetSql(); 38 | } 39 | 40 | public Builder(String column, Object value) { 41 | setSql = new SetSql(); 42 | set(column, value); 43 | } 44 | /** 45 | * 当值为null,""时,是否也set 46 | * 47 | * @param isSetEmpty 当值为null,""时,是否也set 48 | * @return Builder对象 49 | */ 50 | public Builder setEmpty(boolean isSetEmpty) { 51 | setSql.setEmpty = isSetEmpty; 52 | return this; 53 | } 54 | 55 | public Builder set(String column, Object value) { 56 | setSql.sets.put(column, value); 57 | return this; 58 | } 59 | 60 | public SetSql build() { 61 | return setSql; 62 | } 63 | 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/ex/SmartKeyGenerator.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.ex; 2 | 3 | import java.sql.Statement; 4 | 5 | import org.apache.ibatis.binding.MapperMethod.ParamMap; 6 | import org.apache.ibatis.executor.Executor; 7 | import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator; 8 | import org.apache.ibatis.mapping.MappedStatement; 9 | 10 | import com.mingri.mybatissmart.barracks.Constant; 11 | import com.mingri.mybatissmart.barracks.IdtacticsEnum; 12 | import com.mingri.mybatissmart.barracks.Tool; 13 | import com.mingri.mybatissmart.config.MybatisSmartContext; 14 | import com.mingri.mybatissmart.dbo.SmartTableInfo; 15 | 16 | public class SmartKeyGenerator extends Jdbc3KeyGenerator { 17 | 18 | public static final SmartKeyGenerator INSTANCE = new SmartKeyGenerator(); 19 | 20 | @Override 21 | public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) { 22 | 23 | Class clazz = Tool.getClassByParam(parameter); 24 | if (clazz == null) { 25 | return; 26 | } 27 | SmartTableInfo smtb = MybatisSmartContext.getSmartTableInfo(clazz); 28 | if (smtb == null) { 29 | return; 30 | } 31 | if (smtb.getSmartTable().idtactics() != IdtacticsEnum.SQL_INCR) { 32 | return; 33 | } 34 | if (parameter instanceof ParamMap) { 35 | parameter = ((ParamMap) parameter).get(Constant.PARAM_KEY); 36 | } 37 | smtb.modifyKeyProperties(ms); 38 | Jdbc3KeyGenerator.INSTANCE.processAfter(executor, ms, stmt, parameter); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/mapper/SelectSmartMapper.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.mapper; 2 | 3 | import java.util.List; 4 | 5 | import org.apache.ibatis.annotations.Param; 6 | import org.apache.ibatis.annotations.SelectProvider; 7 | 8 | import com.mingri.mybatissmart.barracks.Constant; 9 | import com.mingri.mybatissmart.dbo.Where; 10 | import com.mingri.mybatissmart.provider.MapperSqlProvider; 11 | 12 | /** 13 | * 只读 14 | * @author ljl 15 | * 16 | * @param 实体类 17 | */ 18 | public interface SelectSmartMapper{ 19 | 20 | 21 | @SelectProvider(method = "select", type = MapperSqlProvider.class) 22 | List selectByObjAndWhere(@Param(Constant.PARAM_KEY) E obj, @Param(Constant.COND_KEY) Where filterSqlBuild); 23 | 24 | 25 | @SelectProvider(method = "select", type = MapperSqlProvider.class) 26 | List selectByWhere(@Param(Constant.COND_KEY) Where filterSqlBuild); 27 | 28 | 29 | @SelectProvider(method = "select", type = MapperSqlProvider.class) 30 | E selectOneByWhere(@Param(Constant.COND_KEY) Where filterSqlBuild); 31 | 32 | 33 | @SelectProvider(method = "selectById", type = MapperSqlProvider.class) 34 | E selectById(Object idV); 35 | 36 | 37 | @SelectProvider(method = "count", type = MapperSqlProvider.class) 38 | int countByObjAndWhere(@Param(Constant.PARAM_KEY) Object obj, 39 | @Param(Constant.COND_KEY) Where filterSqlBuild); 40 | 41 | 42 | @SelectProvider(method = "count", type = MapperSqlProvider.class) 43 | int countByWhere(@Param(Constant.COND_KEY) Where filterSqlBuild); 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/config/SpringBootVFS.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.config; 2 | 3 | import java.io.IOException; 4 | import java.io.UncheckedIOException; 5 | import java.net.URL; 6 | import java.util.List; 7 | import java.util.stream.Collectors; 8 | import java.util.stream.Stream; 9 | 10 | import org.apache.ibatis.io.VFS; 11 | import org.springframework.core.io.Resource; 12 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 13 | import org.springframework.core.io.support.ResourcePatternResolver; 14 | 15 | /** 16 | * @author Hans Westerbeek 17 | * @author Eddú Meléndez 18 | * @author Kazuki Shimizu 19 | */ 20 | public class SpringBootVFS extends VFS { 21 | 22 | private final ResourcePatternResolver resourceResolver; 23 | 24 | public SpringBootVFS() { 25 | this.resourceResolver = new PathMatchingResourcePatternResolver(getClass().getClassLoader()); 26 | } 27 | 28 | @Override 29 | public boolean isValid() { 30 | return true; 31 | } 32 | 33 | @Override 34 | protected List list(URL url, String path) throws IOException { 35 | String urlString = url.toString(); 36 | String baseUrlString = urlString.endsWith("/") ? urlString : urlString.concat("/"); 37 | Resource[] resources = resourceResolver.getResources(baseUrlString + "**/*.class"); 38 | return Stream.of(resources).map(resource -> preserveSubpackageName(baseUrlString, resource, path)) 39 | .collect(Collectors.toList()); 40 | } 41 | 42 | private static String preserveSubpackageName(final String baseUrlString, final Resource resource, 43 | final String rootPath) { 44 | try { 45 | return rootPath + (rootPath.endsWith("/") ? "" : "/") 46 | + resource.getURL().toString().substring(baseUrlString.length()); 47 | } catch (IOException e) { 48 | throw new UncheckedIOException(e); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/config/MappingConfig.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.config; 2 | 3 | import org.apache.ibatis.session.SqlSessionFactory; 4 | 5 | /** 6 | * 一个 SqlSessionFactory一个Configuration 7 | * 8 | * @author ljl 9 | * @date 2020-11-12 Dscription: 10 | * 11 | */ 12 | public class MappingConfig { 13 | 14 | private String tablePackages; 15 | private SqlSessionFactory sqlSessionFactory; 16 | private String sqlSessionFactoryBeanName; 17 | private String dialect; 18 | 19 | /** 20 | * 21 | * @param tablePackages 要扫描的实体类对应的包 22 | * @param sqlSessionFactory 23 | * @param sqlSessionFactoryBeanName sqlSessionFactory对应的spirng IOC 24 | * bean名称(一个sqlSessionFactory默认名称就是"sqlSessionFactory") 25 | */ 26 | public MappingConfig(String tablePackages, SqlSessionFactory sqlSessionFactory) { 27 | super(); 28 | this.tablePackages = tablePackages; 29 | this.sqlSessionFactory = sqlSessionFactory; 30 | } 31 | 32 | 33 | 34 | public MappingConfig() { 35 | } 36 | 37 | public String getTablePackages() { 38 | return tablePackages; 39 | } 40 | 41 | public void setTablePackages(String tablePackages) { 42 | this.tablePackages = tablePackages; 43 | } 44 | 45 | public SqlSessionFactory getSqlSessionFactory() { 46 | return sqlSessionFactory; 47 | } 48 | 49 | public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { 50 | this.sqlSessionFactory = sqlSessionFactory; 51 | } 52 | 53 | public String getDialect() { 54 | return dialect; 55 | } 56 | 57 | public void setDialect(String dialect) { 58 | this.dialect = dialect; 59 | } 60 | 61 | public String getSqlSessionFactoryBeanName() { 62 | return sqlSessionFactoryBeanName; 63 | } 64 | 65 | void setSqlSessionFactoryBeanName(String sqlSessionFactoryBeanName) { 66 | this.sqlSessionFactoryBeanName = sqlSessionFactoryBeanName; 67 | } 68 | 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/barracks/Tool.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.barracks; 2 | 3 | import java.sql.Connection; 4 | import java.sql.SQLException; 5 | import java.util.List; 6 | 7 | import org.apache.ibatis.binding.MapperMethod.ParamMap; 8 | 9 | import com.mingri.mybatissmart.annotation.SmartTable; 10 | 11 | public class Tool { 12 | 13 | private Tool() { 14 | } 15 | 16 | /** 17 | * 根据连接对象获取数据库url 18 | * 19 | * @param conn 连接对象 20 | * @return 返回url字符串 21 | */ 22 | private static String getUrl(Connection conn) { 23 | try { 24 | return conn.getMetaData().getURL(); 25 | } catch (SQLException e) { 26 | throw new MybatisSmartException(e.getMessage()); 27 | } 28 | } 29 | 30 | /** 31 | * 根据连接对象获取数据库方言 32 | * 33 | * @param conn 连接对象 34 | * @return 返回方言枚举 35 | */ 36 | public static DialectEnum getDialect(Connection conn) { 37 | String url = getUrl(conn); 38 | DialectEnum[] enums = DialectEnum.values(); 39 | for (DialectEnum dialectEnum : enums) { 40 | if (url.indexOf(dialectEnum.name) != -1) { 41 | return dialectEnum; 42 | } 43 | } 44 | throw new MybatisSmartException("MybatisSmart无法解析出数据库方言,请配置数据库方言"); 45 | } 46 | 47 | public static String unifiedColumnName(String columnName) { 48 | return columnName.toLowerCase(); 49 | } 50 | 51 | public static Class getClassByParam(Object parameter) { 52 | if (parameter instanceof ParamMap) { 53 | Object enParam = ((ParamMap) parameter).get(Constant.PARAM_KEY); 54 | if (enParam == null) { 55 | return null; 56 | } 57 | return enParam instanceof List ? (((List) enParam).get(0).getClass()) : enParam.getClass(); 58 | } 59 | return null; 60 | } 61 | 62 | public static String getTableName(SmartTable tableInfo) { 63 | String tableName=tableInfo.value(); 64 | return tableName.isEmpty()?tableInfo.name():tableName; 65 | 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/ex/SmartConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.ex; 2 | 3 | import java.lang.reflect.Type; 4 | import java.util.List; 5 | import java.util.Map; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | import org.apache.ibatis.mapping.MappedStatement; 9 | import org.apache.ibatis.session.Configuration; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import com.mingri.langhuan.cabinet.tool.ClassTool; 14 | import com.mingri.mybatissmart.mapper.SmartMapper; 15 | 16 | /** 17 | * 18 | * @author ljl 19 | * @date 2020-12-16 Dscription: 扩展 mybatis 的 Configuration 20 | * 21 | */ 22 | public class SmartConfiguration extends Configuration { 23 | private static final Logger logger = LoggerFactory.getLogger(SmartConfiguration.class); 24 | public static final Map> MODEL_MAP = new ConcurrentHashMap<>(); 25 | 26 | public static Class getIfSmartMapperSubOfModel(String id) { 27 | 28 | return MODEL_MAP.computeIfAbsent(id, (k) -> { 29 | int idx = k.lastIndexOf("."); 30 | String className = k.substring(0, idx); 31 | try { 32 | Class clazz = Class.forName(className); 33 | if (!SmartMapper.class.isAssignableFrom(clazz)) { 34 | return null; 35 | } 36 | List tps = ClassTool.getExtendGenericity(clazz, SmartMapper.class); 37 | if (tps == null || tps.isEmpty()) { 38 | logger.warn("继承SmartMapper接口必须设置泛型"); 39 | return null; 40 | } 41 | return Class.forName(tps.get(0).getTypeName()); 42 | } catch (Exception e) { 43 | if (!(e instanceof ClassNotFoundException)) { 44 | logger.warn("不支持SmartMapper的子接口的子接口调用SmartMapper的函数"); 45 | } 46 | e.printStackTrace(); 47 | } 48 | 49 | return null; 50 | }); 51 | } 52 | 53 | static final ThreadLocal> MODEL=new ThreadLocal<>(); 54 | 55 | public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) { 56 | removeModel(); 57 | Class model=getIfSmartMapperSubOfModel(id); 58 | setModel(model); 59 | return super.getMappedStatement(id, validateIncompleteStatements); 60 | } 61 | 62 | 63 | 64 | public static void setModel(Class model) { 65 | MODEL.set(model); 66 | } 67 | 68 | 69 | private static void removeModel() { 70 | MODEL.remove(); 71 | } 72 | 73 | 74 | public static Class currentModel() { 75 | Class clazz= MODEL.get(); 76 | return clazz; 77 | } 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/WhereNode.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import java.util.List; 4 | 5 | import com.mingri.langhuan.cabinet.constant.LogicCmp; 6 | import com.mingri.langhuan.cabinet.constant.NexusCmp; 7 | 8 | /** 9 | * where 条件 节点 10 | * 11 | * @author ljl 12 | * 13 | */ 14 | public class WhereNode { 15 | 16 | /** 17 | * 关系运算符:> < = ... 18 | */ 19 | private NexusCmp nexusCmp; 20 | 21 | /** 22 | * 逻辑运算符 :and or 23 | */ 24 | private LogicCmp logicCmp; 25 | 26 | /** 27 | * 列名称 28 | */ 29 | private String columnName; 30 | 31 | /** 32 | * 值 33 | */ 34 | private Object val; 35 | 36 | /** 37 | * 是否Statement值 38 | */ 39 | private boolean isStatementVal = false; 40 | 41 | private List childCond; 42 | 43 | public WhereNode(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp, Object val) { 44 | this.logicCmp = logicCmp; 45 | this.nexusCmp = nexusCmp; 46 | this.columnName = columnName; 47 | this.val = val; 48 | } 49 | 50 | public WhereNode(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp, Object val, boolean isStatementVal) { 51 | this.logicCmp = logicCmp; 52 | this.nexusCmp = nexusCmp; 53 | this.columnName = columnName; 54 | this.val = val; 55 | this.isStatementVal = isStatementVal; 56 | } 57 | 58 | public WhereNode(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp) { 59 | this.logicCmp = logicCmp; 60 | this.nexusCmp = nexusCmp; 61 | this.columnName = columnName; 62 | } 63 | 64 | public WhereNode(LogicCmp logicCmp, List childCond) { 65 | this.logicCmp = logicCmp; 66 | this.childCond = childCond; 67 | } 68 | 69 | public NexusCmp getNexusCmp() { 70 | return nexusCmp; 71 | } 72 | 73 | public void setNexusCmp(NexusCmp nexusCmp) { 74 | this.nexusCmp = nexusCmp; 75 | } 76 | 77 | public String getColumnName() { 78 | return columnName; 79 | } 80 | 81 | public void setColumnName(String columnName) { 82 | this.columnName = columnName; 83 | } 84 | 85 | public Object getVal() { 86 | return val; 87 | } 88 | 89 | public void setVal(Object val) { 90 | this.val = val; 91 | } 92 | 93 | public LogicCmp getLogicCmp() { 94 | return logicCmp; 95 | } 96 | 97 | public void setLogicCmp(LogicCmp logicCmp) { 98 | this.logicCmp = logicCmp; 99 | } 100 | 101 | public boolean isStatementVal() { 102 | return isStatementVal; 103 | } 104 | 105 | public void setStatementVal(boolean isStatementVal) { 106 | this.isStatementVal = isStatementVal; 107 | } 108 | 109 | public List getChildCond() { 110 | return childCond; 111 | } 112 | 113 | public void setChildCond(List childCond) { 114 | this.childCond = childCond; 115 | } 116 | 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/provider/SqlBuildParam.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.provider; 2 | 3 | import java.sql.SQLException; 4 | 5 | import org.apache.ibatis.binding.MapperMethod.ParamMap; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import com.mingri.mybatissmart.barracks.Constant; 10 | import com.mingri.mybatissmart.config.MybatisSmartContext; 11 | import com.mingri.mybatissmart.dbo.SmartTableInfo; 12 | import com.mingri.mybatissmart.dbo.Where; 13 | import com.mingri.mybatissmart.ex.SmartConfiguration; 14 | 15 | /** 16 | * mapper sql构建所需要的参数类 17 | * @author ljl 18 | * 2019年11月30日 19 | */ 20 | public class SqlBuildParam { 21 | 22 | 23 | private Class clazz; 24 | private Object param; 25 | private Where filterSqlBuild; 26 | private SmartTableInfo smti; 27 | 28 | public Class getClazz() { 29 | return clazz; 30 | } 31 | 32 | private void setClazz(Class clazz) { 33 | this.clazz = clazz; 34 | } 35 | 36 | public Object getParam() { 37 | return param; 38 | } 39 | 40 | private void setParam(Object param) { 41 | this.param = param; 42 | } 43 | 44 | private void setFilterSqlBuild(Where filterSqlBuild) { 45 | this.filterSqlBuild = filterSqlBuild; 46 | } 47 | 48 | public SmartTableInfo getSmti() { 49 | return smti; 50 | } 51 | 52 | public void setSmti(SmartTableInfo smti) { 53 | this.smti = smti; 54 | } 55 | 56 | public Where getFilterSqlBuild() { 57 | return filterSqlBuild; 58 | } 59 | 60 | private SqlBuildParam() { 61 | } 62 | 63 | public static class Builder { 64 | private static final Logger LOGGER = LoggerFactory.getLogger(Builder.class); 65 | 66 | private Object providerParam; 67 | private Class clazz; 68 | 69 | public Class getClazz() { 70 | return clazz; 71 | } 72 | 73 | public Builder setClazz(Class clazz) { 74 | this.clazz = clazz; 75 | return this; 76 | } 77 | 78 | /** 79 | * 构建 80 | * 81 | * @param providerParam 82 | * @return 83 | * @throws SQLException 84 | */ 85 | private void construct(SqlBuildParam paramWrapper) throws SQLException { 86 | Object param = null; 87 | ParamMap paramMap=null; 88 | Where filterSqlBuild=null; 89 | if (providerParam instanceof ParamMap) { 90 | paramMap=(ParamMap) providerParam; 91 | param = paramMap.getOrDefault(Constant.PARAM_KEY,null); 92 | filterSqlBuild = (Where)paramMap.getOrDefault(Constant.COND_KEY,null); 93 | } else { 94 | param = providerParam; 95 | } 96 | 97 | this.clazz=SmartConfiguration.currentModel(); 98 | SmartTableInfo smti = MybatisSmartContext.getSmartTableInfo(this.clazz); 99 | paramWrapper.setClazz(this.clazz); 100 | paramWrapper.setSmti(smti); 101 | paramWrapper.setParam(param); 102 | paramWrapper.setFilterSqlBuild(filterSqlBuild); 103 | } 104 | 105 | public Builder(Object providerParam) { 106 | this.providerParam = providerParam; 107 | } 108 | 109 | public SqlBuildParam build() { 110 | SqlBuildParam param = new SqlBuildParam(); 111 | try { 112 | construct(param); 113 | return param; 114 | } catch (SQLException e) { 115 | LOGGER.error("sql构建异常: {}", e); 116 | } 117 | return null; 118 | } 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | com.github.ljinlin 6 | mybatis-smart 7 | 2.0.0-beta1 8 | mybatis-smart 9 | This is a encapsulation of mybatis. It adds a more flexible and simple use method based on mybatis 10 | https://github.com/ljinlin/mybatis-smart 11 | 2020 12 | 13 | 14 | 15 | 16 | UTF-8 17 | 3.5.0 18 | 2.0.0 19 | 2.1.1.RELEASE 20 | 21 | 22 | 23 | The Apache Software License, Version 2.0 24 | http://www.apache.org/licenses/LICENSE-2.0.txt 25 | repo 26 | 27 | 28 | 29 | master 30 | git@gitee.com:ljinlin/mybatis-smart.git 31 | scm:git:git@gitee.com:ljinlin/mybatis-smart.git 32 | scm:git:git@gitee.com:ljinlin/mybatis-smart.git 33 | 34 | 35 | 36 | Jinlin Lee 37 | 594255598@qq.com 38 | ljinlin 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | org.springframework.boot 47 | spring-boot-starter 48 | ${spring-boot.version} 49 | 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-jdbc 54 | ${spring-boot.version} 55 | 56 | 57 | com.github.ljinlin 58 | langhuan-cabinet 59 | 1.2.0-beta1 60 | 61 | 62 | org.mybatis 63 | mybatis 64 | ${mybatis.version} 65 | 66 | 67 | org.mybatis 68 | mybatis-spring 69 | ${mybatis-spring.version} 70 | 71 | 72 | 77 | 78 | 79 | 80 | sonatype-nexus-snapshots 81 | Sonatype Nexus Snapshots 82 | https://oss.sonatype.org/content/repositories/snapshots 83 | 84 | 85 | sonatype-nexus-staging 86 | Nexus Release Repository 87 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | org.apache.maven.plugins 98 | maven-compiler-plugin 99 | 100 | 1.8 101 | 1.8 102 | 104 | 105 | 106 | 107 | maven-source-plugin 108 | 2.1 109 | 110 | true 111 | 112 | 113 | 114 | compile 115 | 116 | jar 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | org.apache.maven.plugins 125 | maven-javadoc-plugin 126 | 2.9.1 127 | 128 | 129 | package 130 | 131 | jar 132 | 133 | 134 | 135 | 136 | 137 | 138 | 141 | 142 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/provider/MapperSqlProvider.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.provider; 2 | 3 | import org.apache.ibatis.annotations.Param; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import com.mingri.mybatissmart.barracks.Constant; 8 | import com.mingri.mybatissmart.barracks.SqlPrint; 9 | import com.mingri.mybatissmart.config.MybatisSmartContext; 10 | import com.mingri.mybatissmart.dbo.SetSql; 11 | import com.mingri.mybatissmart.dbo.SmartTableInfo; 12 | import com.mingri.mybatissmart.dbo.Where; 13 | import com.mingri.mybatissmart.ex.SmartConfiguration; 14 | 15 | /** 16 | * mapper sql 提供者 17 | * @author ljl 18 | * 2019年11月30日 19 | */ 20 | public class MapperSqlProvider { 21 | 22 | private static final Logger LOGGER = LoggerFactory.getLogger(MapperSqlProvider.class); 23 | 24 | 25 | public static String select(Object obj) { 26 | Class cl=SmartConfiguration.currentModel(); 27 | String sql = null; 28 | try { 29 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(obj).build(); 30 | SmartTableInfo smti = paramWrapper.getSmti(); 31 | Where filterSqlBuild=paramWrapper.getFilterSqlBuild(); 32 | smti = MybatisSmartContext.getSmartTableInfo(cl); 33 | sql = smti.getSelectByWhereSql(paramWrapper.getParam(), filterSqlBuild); 34 | SqlPrint.instance().print(LOGGER,sql); 35 | } catch (Exception e) { 36 | LOGGER.error("sql构建异常:", e); 37 | } 38 | return sql; 39 | } 40 | 41 | public static String selectById(Object idV) { 42 | SmartTableInfo smti; 43 | Class cl=SmartConfiguration.currentModel(); 44 | String sql = null; 45 | try { 46 | smti = MybatisSmartContext.getSmartTableInfo(cl); 47 | sql = smti.getSelectByIdSql(idV); 48 | LOGGER.info(sql); 49 | } catch (Exception e) { 50 | LOGGER.error("sql构建异常:", e); 51 | } 52 | return sql; 53 | } 54 | 55 | public static String count(Object obj,@Param(Constant.COND_KEY) Where where) { 56 | String sql = null; 57 | Class cl=SmartConfiguration.currentModel(); 58 | try { 59 | SmartTableInfo smti = MybatisSmartContext.getSmartTableInfo(cl); 60 | sql = smti.getCountByWhereSql(obj, where); 61 | SqlPrint.instance().print(LOGGER,sql); 62 | } catch (Exception e) { 63 | LOGGER.error("sql构建异常:", e); 64 | } 65 | return sql; 66 | } 67 | 68 | 69 | public static String delete(@Param(Constant.PARAM_KEY) Object obj, @Param(Constant.COND_KEY) Where where) { 70 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(obj).build(); 71 | SmartTableInfo smti = paramWrapper.getSmti(); 72 | 73 | String sql = null; 74 | try { 75 | sql = smti.getDeleteByWhereSql(paramWrapper.getParam(), where); 76 | SqlPrint.instance().print(LOGGER,sql); 77 | } catch (Exception e) { 78 | LOGGER.error("sql构建异常:", e); 79 | } 80 | return sql; 81 | } 82 | public static String inserts(@Param(Constant.PARAM_KEY) Object obj) { 83 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(obj).build(); 84 | SmartTableInfo smti = paramWrapper.getSmti(); 85 | String sql = null; 86 | try { 87 | sql = smti.getInsertSql(paramWrapper.getParam()); 88 | } catch (Exception e) { 89 | LOGGER.error("sql构建异常:", e); 90 | } 91 | return sql; 92 | } 93 | 94 | public static String updateById(@Param(Constant.PARAM_KEY) Object obj) { 95 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(obj).build(); 96 | SmartTableInfo smti = paramWrapper.getSmti(); 97 | String sql = null; 98 | try { 99 | sql = smti.getUpdateByIdSql(paramWrapper.getParam()); 100 | SqlPrint.instance().print(LOGGER,sql); 101 | } catch (Exception e) { 102 | LOGGER.error("sql构建异常:", e); 103 | } 104 | return sql; 105 | } 106 | public static String updateBySets(@Param(Constant.TABLE_KEY) Class tableClazz,@Param(Constant.PARAM_KEY) Object obj, @Param(Constant.COND_KEY) Where where) { 107 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(obj).setClazz(tableClazz).build(); 108 | SmartTableInfo smti = paramWrapper.getSmti(); 109 | String sql = null; 110 | try { 111 | sql = smti.getUpdateBySetSAndWhereSql((SetSql)paramWrapper.getParam(),where); 112 | SqlPrint.instance().print(LOGGER,sql); 113 | } catch (Exception e) { 114 | LOGGER.error("sql构建异常:", e); 115 | } 116 | return sql; 117 | } 118 | 119 | public static String updateByWhere(@Param(Constant.PARAM_KEY) Object obj, @Param(Constant.COND_KEY) Where where) { 120 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(obj).build(); 121 | SmartTableInfo smti = paramWrapper.getSmti(); 122 | String sql = null; 123 | try { 124 | sql = smti.getUpdateByWhereSql(paramWrapper.getParam(), where); 125 | SqlPrint.instance().print(LOGGER,sql); 126 | } catch (Exception e) { 127 | LOGGER.error("sql构建异常:", e); 128 | } 129 | return sql; 130 | } 131 | 132 | public static String deleteById(Object idV) { 133 | Class cl=SmartConfiguration.currentModel(); 134 | SqlBuildParam paramWrapper=new SqlBuildParam.Builder(idV).setClazz(cl).build(); 135 | SmartTableInfo smti; 136 | String sql = null; 137 | try { 138 | smti = paramWrapper.getSmti(); 139 | sql = smti.getDeleteByIdSql(paramWrapper.getParam()); 140 | SqlPrint.instance().print(LOGGER,sql); 141 | } catch (Exception e) { 142 | LOGGER.error("sql构建异常: ", e); 143 | } 144 | return sql; 145 | } 146 | 147 | 148 | 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/ex/MybatisProperties.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.ex; 2 | 3 | import java.io.IOException; 4 | import java.util.Optional; 5 | import java.util.Properties; 6 | import java.util.stream.Stream; 7 | 8 | import org.apache.ibatis.scripting.LanguageDriver; 9 | import org.apache.ibatis.session.Configuration; 10 | import org.apache.ibatis.session.ExecutorType; 11 | import org.springframework.boot.context.properties.ConfigurationProperties; 12 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 13 | import org.springframework.core.io.Resource; 14 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver; 15 | import org.springframework.core.io.support.ResourcePatternResolver; 16 | 17 | import com.mingri.mybatissmart.config.SmartProperties; 18 | 19 | /** 20 | * Configuration properties for MyBatis. 21 | * 22 | * @author Eddú Meléndez 23 | * @author Kazuki Shimizu 24 | */ 25 | @ConfigurationProperties(prefix = MybatisProperties.MYBATIS_PREFIX) 26 | public class MybatisProperties { 27 | 28 | public static final String MYBATIS_PREFIX = "mybatis"; 29 | 30 | private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(); 31 | 32 | /** 33 | * Location of MyBatis xml config file. 34 | */ 35 | private String configLocation; 36 | 37 | /** 38 | * Locations of MyBatis mapper files. 39 | */ 40 | private String[] mapperLocations; 41 | 42 | /** 43 | * Packages to search type aliases. (Package delimiters are ",; \t\n") 44 | */ 45 | private String typeAliasesPackage; 46 | 47 | /** 48 | * The super class for filtering type alias. If this not specifies, the MyBatis 49 | * deal as type alias all classes that searched from typeAliasesPackage. 50 | */ 51 | private Class typeAliasesSuperType; 52 | 53 | /** 54 | * Packages to search for type handlers. (Package delimiters are ",; \t\n") 55 | */ 56 | private String typeHandlersPackage; 57 | 58 | /** 59 | * Indicates whether perform presence check of the MyBatis xml config file. 60 | */ 61 | private boolean checkConfigLocation = false; 62 | 63 | /** 64 | * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}. 65 | */ 66 | private ExecutorType executorType; 67 | 68 | /** 69 | * The default scripting language driver class. (Available when use together 70 | * with mybatis-spring 2.0.2+) 71 | */ 72 | private Class defaultScriptingLanguageDriver; 73 | 74 | /** 75 | * Externalized properties for MyBatis configuration. 76 | */ 77 | private Properties configurationProperties; 78 | 79 | /** 80 | * Externalized properties for MyBatis configuration. 81 | */ 82 | private SmartProperties smart; 83 | 84 | 85 | 86 | /** 87 | * A Configuration object for customize default settings. If 88 | * {@link #configLocation} is specified, this property is not used. 89 | */ 90 | @NestedConfigurationProperty 91 | private SmartConfiguration configuration; 92 | 93 | /** 94 | * @since 1.1.0 95 | */ 96 | public String getConfigLocation() { 97 | return this.configLocation; 98 | } 99 | 100 | /** 101 | * @since 1.1.0 102 | */ 103 | public void setConfigLocation(String configLocation) { 104 | this.configLocation = configLocation; 105 | } 106 | 107 | public String[] getMapperLocations() { 108 | return this.mapperLocations; 109 | } 110 | 111 | public void setMapperLocations(String[] mapperLocations) { 112 | this.mapperLocations = mapperLocations; 113 | } 114 | 115 | public String getTypeHandlersPackage() { 116 | return this.typeHandlersPackage; 117 | } 118 | 119 | public void setTypeHandlersPackage(String typeHandlersPackage) { 120 | this.typeHandlersPackage = typeHandlersPackage; 121 | } 122 | 123 | public String getTypeAliasesPackage() { 124 | return this.typeAliasesPackage; 125 | } 126 | 127 | public void setTypeAliasesPackage(String typeAliasesPackage) { 128 | this.typeAliasesPackage = typeAliasesPackage; 129 | } 130 | 131 | /** 132 | * @since 1.3.3 133 | */ 134 | public Class getTypeAliasesSuperType() { 135 | return typeAliasesSuperType; 136 | } 137 | 138 | /** 139 | * @since 1.3.3 140 | */ 141 | public void setTypeAliasesSuperType(Class typeAliasesSuperType) { 142 | this.typeAliasesSuperType = typeAliasesSuperType; 143 | } 144 | 145 | public boolean isCheckConfigLocation() { 146 | return this.checkConfigLocation; 147 | } 148 | 149 | public void setCheckConfigLocation(boolean checkConfigLocation) { 150 | this.checkConfigLocation = checkConfigLocation; 151 | } 152 | 153 | public ExecutorType getExecutorType() { 154 | return this.executorType; 155 | } 156 | 157 | public void setExecutorType(ExecutorType executorType) { 158 | this.executorType = executorType; 159 | } 160 | 161 | /** 162 | * @since 2.1.0 163 | */ 164 | public Class getDefaultScriptingLanguageDriver() { 165 | return defaultScriptingLanguageDriver; 166 | } 167 | 168 | /** 169 | * @since 2.1.0 170 | */ 171 | public void setDefaultScriptingLanguageDriver(Class defaultScriptingLanguageDriver) { 172 | this.defaultScriptingLanguageDriver = defaultScriptingLanguageDriver; 173 | } 174 | 175 | /** 176 | * @since 1.2.0 177 | */ 178 | public Properties getConfigurationProperties() { 179 | return configurationProperties; 180 | } 181 | 182 | /** 183 | * @since 1.2.0 184 | */ 185 | public void setConfigurationProperties(Properties configurationProperties) { 186 | this.configurationProperties = configurationProperties; 187 | } 188 | 189 | public Configuration getConfiguration() { 190 | return configuration; 191 | } 192 | 193 | public void setConfiguration(SmartConfiguration configuration) { 194 | this.configuration = configuration; 195 | } 196 | 197 | public Resource[] resolveMapperLocations() { 198 | return Stream.of(Optional.ofNullable(this.mapperLocations).orElse(new String[0])) 199 | .flatMap(location -> Stream.of(getResources(location))).toArray(Resource[]::new); 200 | } 201 | 202 | private Resource[] getResources(String location) { 203 | try { 204 | return resourceResolver.getResources(location); 205 | } catch (IOException e) { 206 | return new Resource[0]; 207 | } 208 | } 209 | 210 | public SmartProperties getSmart() { 211 | return smart; 212 | } 213 | 214 | public void setSmart(SmartProperties smart) { 215 | this.smart = smart; 216 | } 217 | 218 | } 219 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/config/MybatisSmartAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.config; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Collections; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | 10 | import javax.sql.DataSource; 11 | 12 | import org.apache.ibatis.mapping.DatabaseIdProvider; 13 | import org.apache.ibatis.plugin.Interceptor; 14 | import org.apache.ibatis.session.Configuration; 15 | import org.apache.ibatis.session.SqlSessionFactory; 16 | import org.apache.ibatis.type.TypeHandler; 17 | import org.mybatis.spring.SqlSessionFactoryBean; 18 | import org.springframework.beans.factory.InitializingBean; 19 | import org.springframework.beans.factory.ObjectProvider; 20 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 21 | import org.springframework.boot.autoconfigure.AutoConfigureBefore; 22 | import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 23 | import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 24 | import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; 25 | import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; 26 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 27 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 28 | import org.springframework.context.annotation.Bean; 29 | import org.springframework.core.io.Resource; 30 | import org.springframework.core.io.ResourceLoader; 31 | import org.springframework.util.Assert; 32 | import org.springframework.util.CollectionUtils; 33 | import org.springframework.util.ObjectUtils; 34 | import org.springframework.util.StringUtils; 35 | 36 | import com.mingri.langhuan.cabinet.tool.StrTool; 37 | import com.mingri.mybatissmart.ex.MybatisProperties; 38 | import com.mingri.mybatissmart.ex.SmartConfiguration; 39 | 40 | @org.springframework.context.annotation.Configuration 41 | @EnableConfigurationProperties(value = { MybatisProperties.class }) 42 | @ConditionalOnSingleCandidate(DataSource.class) 43 | @ConditionalOnClass({ SqlSessionFactory.class, SqlSessionFactoryBean.class }) 44 | @AutoConfigureAfter(DataSourceAutoConfiguration.class) 45 | @AutoConfigureBefore(name = "org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration") 46 | public class MybatisSmartAutoConfiguration implements InitializingBean { 47 | 48 | private final MybatisProperties properties; 49 | private final SmartProperties smartProperties; 50 | 51 | private final Interceptor[] interceptors; 52 | 53 | @SuppressWarnings("rawtypes") 54 | private final TypeHandler[] typeHandlers; 55 | 56 | private final ResourceLoader resourceLoader; 57 | 58 | private final DatabaseIdProvider databaseIdProvider; 59 | 60 | private final List configurationCustomizers; 61 | 62 | 63 | @SuppressWarnings("rawtypes") 64 | public MybatisSmartAutoConfiguration(MybatisProperties properties, 65 | ObjectProvider interceptorsProvider, ObjectProvider typeHandlersProvider, 66 | ResourceLoader resourceLoader, ObjectProvider databaseIdProvider, 67 | ObjectProvider> configurationCustomizersProvider) { 68 | this.properties = properties; 69 | this.smartProperties = properties.getSmart(); 70 | this.interceptors = interceptorsProvider.getIfAvailable(); 71 | this.typeHandlers = typeHandlersProvider.getIfAvailable(); 72 | this.resourceLoader = resourceLoader; 73 | this.databaseIdProvider = databaseIdProvider.getIfAvailable(); 74 | this.configurationCustomizers = configurationCustomizersProvider.getIfAvailable(); 75 | } 76 | 77 | @Bean 78 | @ConditionalOnMissingBean 79 | public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { 80 | SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); 81 | factory.setDataSource(dataSource); 82 | factory.setVfs(SpringBootVFS.class); 83 | if (StringUtils.hasText(this.properties.getConfigLocation())) { 84 | factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); 85 | } 86 | applyConfiguration(factory); 87 | 88 | if (this.properties.getConfigurationProperties() != null) { 89 | factory.setConfigurationProperties(this.properties.getConfigurationProperties()); 90 | } 91 | if (!ObjectUtils.isEmpty(this.interceptors)) { 92 | factory.setPlugins(this.interceptors); 93 | } 94 | if (this.databaseIdProvider != null) { 95 | factory.setDatabaseIdProvider(this.databaseIdProvider); 96 | } 97 | if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) { 98 | factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage()); 99 | } 100 | if (this.properties.getTypeAliasesSuperType() != null) { 101 | factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType()); 102 | } 103 | if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) { 104 | factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage()); 105 | } 106 | if (!ObjectUtils.isEmpty(this.typeHandlers)) { 107 | factory.setTypeHandlers(this.typeHandlers); 108 | } 109 | if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) { 110 | factory.setMapperLocations(this.properties.resolveMapperLocations()); 111 | } 112 | 113 | return factory.getObject(); 114 | } 115 | 116 | private void applyConfiguration(SqlSessionFactoryBean factory) { 117 | Configuration configuration = this.properties.getConfiguration(); 118 | if (configuration == null && !StringUtils.hasText(this.properties.getConfigLocation())) { 119 | configuration = new SmartConfiguration(); 120 | } 121 | if (configuration != null && !CollectionUtils.isEmpty(this.configurationCustomizers)) { 122 | for (ConfigurationCustomizer customizer : this.configurationCustomizers) { 123 | customizer.customize(configuration); 124 | } 125 | } 126 | factory.setConfiguration(configuration); 127 | } 128 | 129 | @Bean 130 | @ConditionalOnBean(SqlSessionFactory.class) 131 | public MybatisSmartContext mybatisSmartContext(Map sessionFactoryMap) { 132 | MybatisSmartContext mybatisSmartContext = new MybatisSmartContext(); 133 | List mappingConfigList=parseToMappingConfigList(smartProperties, sessionFactoryMap); 134 | mybatisSmartContext.setMappingConfigList(mappingConfigList); 135 | return mybatisSmartContext; 136 | } 137 | 138 | 139 | public List parseToMappingConfigList(SmartProperties smartProperties,Map sessionFactoryMap) { 140 | SqlSessionFactory sqlSessionFactory = null; 141 | Map tablePackages = smartProperties.getTablePackages(); 142 | if (tablePackages == null || tablePackages.isEmpty()) { 143 | return Collections.emptyList(); 144 | } 145 | List configurations = new ArrayList<>(); 146 | Map tablePackageMap = new HashMap<>(); 147 | tablePackages.forEach((tablePackagesStr, sqlSessionFactoryBeanName) -> { 148 | String key = StrTool.isEmpty(sqlSessionFactoryBeanName) ? null : sqlSessionFactoryBeanName; 149 | tablePackageMap.compute(key, (k, v) -> { 150 | return StrTool.isEmpty(v) ? tablePackagesStr.trim() : (v + "," + (tablePackagesStr.trim())); 151 | }); 152 | }); 153 | String sqlSessionFactoryBeanName = null; 154 | for (Entry entry : tablePackageMap.entrySet()) { 155 | sqlSessionFactoryBeanName = entry.getKey(); 156 | sqlSessionFactory=sessionFactoryMap.get(sqlSessionFactoryBeanName); 157 | Assert.notNull(sqlSessionFactory, "spring IOC 中不存的sqlSessionFactory:" + sqlSessionFactoryBeanName); 158 | MappingConfig conf = new MappingConfig(entry.getValue(), sqlSessionFactory); 159 | conf.setSqlSessionFactoryBeanName(sqlSessionFactoryBeanName); 160 | configurations.add(conf); 161 | } 162 | 163 | return configurations; 164 | } 165 | 166 | 167 | 168 | @Override 169 | public void afterPropertiesSet() { 170 | checkConfigFileExists(); 171 | } 172 | 173 | private void checkConfigFileExists() { 174 | if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) { 175 | Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation()); 176 | Assert.state(resource.exists(), "Cannot find config location: " + resource 177 | + " (please add config file or check your Mybatis configuration)"); 178 | } 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/MapperSql.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import org.slf4j.Logger; 4 | import org.slf4j.LoggerFactory; 5 | 6 | import com.mingri.langhuan.cabinet.constant.LogicCmp; 7 | import com.mingri.langhuan.cabinet.constant.NexusCmp; 8 | import com.mingri.langhuan.cabinet.constant.ValTypeEnum; 9 | import com.mingri.langhuan.cabinet.tool.StrTool; 10 | import com.mingri.mybatissmart.barracks.Constant; 11 | import com.mingri.mybatissmart.barracks.DialectEnum; 12 | import com.mingri.mybatissmart.barracks.MybatisSmartException; 13 | import com.mingri.mybatissmart.barracks.SqlKwd; 14 | import com.mingri.mybatissmart.provider.MapperSqlProvider; 15 | 16 | class MapperSql { 17 | private static final Logger LOGGER = LoggerFactory.getLogger(MapperSql.class); 18 | private StringBuilder statementSql = new StringBuilder(); 19 | 20 | private MapperSql() { 21 | } 22 | 23 | class Select { 24 | 25 | private WhereSql where; 26 | private String orderBy; 27 | private Integer limit; 28 | private Integer offset; 29 | private DialectEnum dialect; 30 | 31 | Select(String columns, String table) { 32 | statementSql = new StringBuilder(SqlKwd.SELECT).append(columns).append(SqlKwd.FROM).append(table); 33 | } 34 | 35 | Select where(WhereSql where) { 36 | this.where = where; 37 | return this; 38 | } 39 | 40 | Select orderBy(String orderBy) { 41 | this.orderBy = orderBy; 42 | return this; 43 | } 44 | 45 | Select limit(Integer limit, Integer offset, DialectEnum dialect) { 46 | this.limit = limit; 47 | this.offset = offset; 48 | this.dialect = dialect; 49 | return this; 50 | } 51 | 52 | MapperSql build() { 53 | if (where != null) { 54 | statementSql.append(where.build()); 55 | } 56 | if (StrTool.checkNotEmpty(orderBy)) { 57 | statementSql.append(orderBy); 58 | } 59 | 60 | if (dialect != null) { 61 | 62 | switch (dialect) { 63 | case MYSQL: 64 | if (limit != null) { 65 | statementSql.append(SqlKwd.LIMIT).append(limit); 66 | if (offset != null) { 67 | statementSql.append(SqlKwd.OFFSET).append(offset); 68 | 69 | } 70 | } 71 | break; 72 | case SQLSERVER: 73 | if (limit != null && offset != null) { 74 | statementSql.append(SqlKwd.OFFSET).append(offset).append(" rows fetch next ").append(limit) 75 | .append(" rows only "); 76 | } 77 | break; 78 | default: 79 | break; 80 | } 81 | } 82 | 83 | return MapperSql.this; 84 | } 85 | } 86 | 87 | class Insert { 88 | 89 | private StringBuilder intoColumns = null; 90 | private StringBuilder intoValues = null; 91 | 92 | Insert(String table) { 93 | intoColumns = new StringBuilder(); 94 | intoValues = new StringBuilder(); 95 | statementSql.append(SqlKwd.INSERT_INTO).append(table); 96 | } 97 | 98 | Insert intoColumn(String column) { 99 | intoColumns.append(column).append(","); 100 | return this; 101 | } 102 | 103 | Insert intoColumn(String column, Integer index) { 104 | if (index == null || index == 0) { 105 | intoColumns.append(column).append(","); 106 | } 107 | return this; 108 | } 109 | 110 | Insert intoValue(String value) { 111 | intoValues.append(value).append(","); 112 | return this; 113 | } 114 | 115 | Insert intoRowEnd() { 116 | intoValues.deleteCharAt(intoValues.length() - 1).append("),("); 117 | return this; 118 | } 119 | 120 | MapperSql build() { 121 | if (StrTool.isEmpty(intoColumns)) { 122 | return MapperSql.this; 123 | } 124 | statementSql.append(" (").append(intoColumns.deleteCharAt(intoColumns.length() - 1).append(")")); 125 | intoValues.insert(0, " values("); 126 | statementSql.append(intoValues.delete(intoValues.length() - 2, intoValues.length())); 127 | return MapperSql.this; 128 | } 129 | 130 | } 131 | 132 | class Delete { 133 | 134 | private WhereSql where = null; 135 | 136 | Delete(String table) { 137 | statementSql = new StringBuilder(SqlKwd.DELETE).append(SqlKwd.FROM).append(table); 138 | } 139 | 140 | Delete setWhere(WhereSql where) { 141 | this.where = where; 142 | return this; 143 | } 144 | 145 | MapperSql build() { 146 | if (where != null) { 147 | statementSql.append(where.build()); 148 | } 149 | return MapperSql.this; 150 | } 151 | } 152 | 153 | class Update { 154 | 155 | private StringBuilder sets = new StringBuilder(); 156 | private WhereSql where = null; 157 | 158 | Update(String table,SetSql setSql) { 159 | statementSql.append(SqlKwd.UPDATE).append(table).append(SqlKwd.SET); 160 | setSql.getSets().forEach((k,v)->{ 161 | if(setSql.isSetEmpty()||StrTool.checkNotEmpty(v)) { 162 | this.set(k, StrTool.concat("#{",Constant.PARAM_KEY,".sets.",k,"}")); 163 | } 164 | }); 165 | } 166 | 167 | Update(String table) { 168 | statementSql.append(SqlKwd.UPDATE).append(table).append(SqlKwd.SET); 169 | } 170 | 171 | Update set(String column, String value) { 172 | sets.append(column).append("=").append(value).append(","); 173 | return this; 174 | } 175 | 176 | Update setWhere(WhereSql where) { 177 | this.where = where; 178 | return this; 179 | } 180 | 181 | MapperSql build() { 182 | if(sets.length()==0) { 183 | throw new MybatisSmartException("update必须要有set语句段"); 184 | } 185 | statementSql.append(sets.substring(0, sets.length() - 1)); 186 | if (where != null) { 187 | statementSql.append(where.build()); 188 | } 189 | return MapperSql.this; 190 | } 191 | } 192 | 193 | private static final String OR_UPCASE = LogicCmp.OR.code.toUpperCase(); 194 | private static final String AND_UPCASE = LogicCmp.AND.code.toUpperCase(); 195 | 196 | class WhereSql { 197 | 198 | private StringBuilder nodes = new StringBuilder(); 199 | 200 | WhereSql add(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp, String columnVal) { 201 | if (nodes.length() > 0 && logicCmp != null) { 202 | nodes.append(Constant.SPACE).append(logicCmp.code); 203 | } 204 | nodes.append(Constant.SPACE); 205 | nodes.append(columnName).append(Constant.SPACE).append(nexusCmp.code).append(Constant.SPACE) 206 | .append(columnVal).append(Constant.SPACE); 207 | return this; 208 | } 209 | 210 | WhereSql add(LogicCmp logicCmp, WhereSql whereSql) { 211 | if (nodes.length() > 0 && logicCmp != null) { 212 | nodes.append(Constant.SPACE).append(logicCmp.code); 213 | } 214 | nodes.append(Constant.SPACE); 215 | if (whereSql != null && whereSql.nodes.length() > 0) { 216 | String condSql = trimCondSql(whereSql.nodes.toString()); 217 | nodes.append(" ( ").append(condSql).append(" ) "); 218 | } 219 | return this; 220 | } 221 | 222 | WhereSql add(String afterConditionSql) { 223 | if (nodes.length() > 0) { 224 | nodes.append(Constant.SPACE).append(afterConditionSql); 225 | } else { 226 | afterConditionSql = trimCondSql(afterConditionSql); 227 | nodes.append(Constant.SPACE).append(afterConditionSql); 228 | } 229 | return this; 230 | } 231 | 232 | private String trimCondSql(String condSql) { 233 | condSql = condSql.trim(); 234 | int len = condSql.length(); 235 | condSql = StrTool.trimEdge(condSql, LogicCmp.OR.code); 236 | if (len == condSql.length()) 237 | condSql = StrTool.trimEdge(condSql, LogicCmp.AND.code); 238 | if (len == condSql.length()) 239 | condSql = StrTool.trimEdge(condSql, OR_UPCASE); 240 | if (len == condSql.length()) 241 | condSql = StrTool.trimEdge(condSql, AND_UPCASE); 242 | return condSql; 243 | } 244 | 245 | boolean isEmpty() { 246 | return nodes.length() == 0; 247 | } 248 | 249 | String build() { 250 | if (nodes.length() > 0) { 251 | nodes.insert(0, SqlKwd.WHERE_PRE); 252 | } 253 | return nodes.toString(); 254 | 255 | } 256 | 257 | } 258 | 259 | static Insert insertInto(String table) { 260 | return new MapperSql().new Insert(table); 261 | } 262 | 263 | static Delete delete(String table) { 264 | return new MapperSql().new Delete(table); 265 | } 266 | 267 | static Update update(String table) { 268 | return new MapperSql().new Update(table); 269 | } 270 | static Update update(String table,SetSql sets) { 271 | return new MapperSql().new Update(table,sets); 272 | } 273 | 274 | static Select select(String columns, String table) { 275 | return new MapperSql().new Select(columns, table); 276 | } 277 | 278 | static WhereSql where() { 279 | return new MapperSql().new WhereSql(); 280 | } 281 | 282 | @Override 283 | public String toString() { 284 | return statementSql.toString(); 285 | } 286 | 287 | } 288 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/MapperSqlTool.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import java.lang.reflect.Field; 4 | import java.text.SimpleDateFormat; 5 | import java.time.format.DateTimeFormatter; 6 | import java.time.temporal.TemporalAccessor; 7 | import java.util.Collection; 8 | import java.util.Date; 9 | import java.util.List; 10 | 11 | import com.alibaba.fastjson.JSONArray; 12 | import com.mingri.langhuan.cabinet.constant.LogicCmp; 13 | import com.mingri.langhuan.cabinet.constant.NexusCmp; 14 | import com.mingri.langhuan.cabinet.constant.ValTypeEnum; 15 | import com.mingri.langhuan.cabinet.tool.ClassTool; 16 | import com.mingri.langhuan.cabinet.tool.CollectionTool; 17 | import com.mingri.langhuan.cabinet.tool.StrTool; 18 | import com.mingri.mybatissmart.annotation.SmartColumn; 19 | import com.mingri.mybatissmart.annotation.SmartTable; 20 | import com.mingri.mybatissmart.barracks.Constant; 21 | import com.mingri.mybatissmart.barracks.IdtacticsEnum; 22 | import com.mingri.mybatissmart.barracks.SqlKwd; 23 | import com.mingri.mybatissmart.config.MybatisSmartContext; 24 | import com.mingri.mybatissmart.dbo.MapperSql.WhereSql; 25 | 26 | class MapperSqlTool { 27 | 28 | static WhereSql buildWhere(Object obj, Where where, SmartTableInfo tableClass) 29 | throws IllegalArgumentException, IllegalAccessException { 30 | 31 | List nodes = where == null ? null : where.getNodes(); 32 | if (where == null || CollectionTool.isEmpty(nodes)) { 33 | return null; 34 | } 35 | 36 | MapperSql.WhereSql whereSql = MapperSql.where(); 37 | if (obj != null) { 38 | MapperSqlTool.buildWhere(obj, nodes, tableClass, whereSql); 39 | } 40 | 41 | String afterConditionSql = where.getAfterConditionSql(); 42 | if (StrTool.isNotEmpty(afterConditionSql)) { 43 | whereSql.add(afterConditionSql); 44 | } 45 | return whereSql; 46 | } 47 | 48 | private static WhereSql buildWhere(Object obj, List conds, SmartTableInfo tableClass, WhereSql whereSql) 49 | throws IllegalArgumentException, IllegalAccessException { 50 | if (conds.isEmpty()) { 51 | return null; 52 | } 53 | 54 | for (WhereNode cond : conds) { 55 | List childConds = cond.getChildCond(); 56 | LogicCmp logicCmp = cond.getLogicCmp(); 57 | if (CollectionTool.notEmpty(childConds)) { 58 | WhereSql childWhere = MapperSqlTool.buildWhere(obj, childConds, tableClass, MapperSql.where()); 59 | whereSql.add(logicCmp, childWhere); 60 | } 61 | String columnName = cond.getColumnName(); 62 | String columnVal = null; 63 | Object condSrcVal = cond.getVal(); 64 | NexusCmp nexusCmp = cond.getNexusCmp(); 65 | SmartColumnInfo fim = tableClass.smartColumnInfoMap.get(columnName); 66 | 67 | if (condSrcVal != null) { 68 | if (cond.isStatementVal()) { 69 | columnVal = condSrcVal.toString(); 70 | } else { 71 | columnVal = MapperSqlTool.buildWhereNode(nexusCmp, null, condSrcVal); 72 | } 73 | } else if (fim != null) { 74 | if (!(obj instanceof Class)) { 75 | Object objSrcVal = ClassTool.reflexVal(obj, fim.getField()); 76 | columnVal = MapperSqlTool.buildWhereNode(nexusCmp, fim, objSrcVal); 77 | } 78 | } 79 | if (columnVal != null) { 80 | whereSql.add(logicCmp, columnName, nexusCmp, columnVal); 81 | } 82 | } 83 | 84 | return whereSql; 85 | } 86 | 87 | /** 88 | * 构建计算值 89 | * 90 | * @param srcVal 91 | * @param fmi 可以为null,无需#{} 解析,则必传此参数 92 | * @param cexusCmp 93 | * @return 关系运算符 columnVal 94 | */ 95 | private static String buildWhereNode(NexusCmp cexusCmp, SmartColumnInfo fmi, Object srcVal) { 96 | if (srcVal == null) { 97 | return null; 98 | } 99 | boolean isString = srcVal instanceof String; 100 | String columnVal = null; 101 | if (isString && srcVal.toString().length() == 0) { 102 | return null; 103 | } 104 | if ((cexusCmp == NexusCmp.IN || cexusCmp == NexusCmp.NOT_IN) && isString) { 105 | columnVal = srcVal.toString(); 106 | } else if (fmi != null) {// 。对象传值 107 | columnVal = MapperSqlTool.buildColumnVal(srcVal, fmi, null); 108 | } else {// 。直接传值 109 | columnVal = MapperSqlTool.buildColumnValOfWhereNodeVal(srcVal); 110 | } 111 | if (columnVal == null) { 112 | return null; 113 | } 114 | int len = columnVal.length(); 115 | if (len == 0) { 116 | return null; 117 | } 118 | switch (cexusCmp) { 119 | case LIKE_LR: 120 | columnVal = " concat('%',".concat(columnVal).concat(",'%')"); 121 | break; 122 | case LIKE_L: 123 | columnVal = " concat('%',".concat(columnVal).concat(")"); 124 | break; 125 | case LIKE_R: 126 | columnVal = " concat(".concat(columnVal).concat(",'%')"); 127 | break; 128 | case IN: 129 | case NOT_IN: 130 | columnVal = " (".concat(columnVal).concat(")"); 131 | break; 132 | default: 133 | break; 134 | } 135 | return columnVal; 136 | } 137 | 138 | static String getColumns(SmartTableInfo tableClass) { 139 | StringBuilder cls = new StringBuilder(); 140 | String clsStr = null; 141 | tableClass.smartColumnInfoMap.forEach((k, v) -> { 142 | cls.append(k).append(SqlKwd.AS).append(v.getField().getName()).append(","); 143 | }); 144 | if (cls.length() > 0) { 145 | clsStr = cls.substring(0, cls.length() - 1); 146 | } 147 | return clsStr; 148 | } 149 | 150 | /** 151 | * 构建column值:
152 | * 1、如果是java.util.Date类型,而且在@SmartColumn注解配置了dateFormart则按dateFormart格式化
153 | * 2、如果是java.util.Date类型,但是没有配置dateFormart;如果是String类型, 则让mybatis解析(用#{}包裹)
154 | * 2、不是1和2的情况直接toString
155 | * 156 | * @param srcVal 原始值 157 | * @param fmi 对应的字段映射信息 158 | * @param index 批量插入时使用的索引 159 | * @return 返回column值 160 | * @throws IllegalAccessException 161 | */ 162 | private static String buildColumnValOfWhereNodeVal(Object srcVal) { 163 | if (srcVal == null) { 164 | return null; 165 | } 166 | String columnVal = null; 167 | String srcStrVal = srcVal.toString(); 168 | if (srcVal.getClass() == String.class) { 169 | columnVal = "'".concat(srcStrVal).concat("'"); 170 | } else if (srcVal == ValTypeEnum.BLANK) { 171 | columnVal = "''"; 172 | } else if (srcVal == ValTypeEnum.NULL) { 173 | columnVal = ValTypeEnum.NULL.code; 174 | } else { 175 | if (srcVal.getClass().isArray()) { 176 | srcVal = JSONArray.parseArray(JSONArray.toJSONString(srcVal), Object.class); 177 | } 178 | if (srcVal instanceof Collection) { 179 | Collection clt = (Collection) srcVal; 180 | if (clt.isEmpty()) { 181 | return null; 182 | } 183 | StringBuilder inVal = new StringBuilder(); 184 | clt.forEach(e -> { 185 | if (e instanceof String) { 186 | inVal.append("'").append(e.toString()).append("'").append(","); 187 | } else { 188 | inVal.append(e.toString()).append(","); 189 | } 190 | }); 191 | if (inVal.length() > 0) { 192 | columnVal = inVal.substring(0, inVal.length() - 1); 193 | } else { 194 | return null; 195 | } 196 | } 197 | } 198 | return columnVal == null ? srcStrVal : columnVal; 199 | } 200 | 201 | /** 202 | * 构建column值:
203 | * 1、如果是java.util.Date或者java.time.temporal.TemporalAccessor,
204 | *   1.1而且在@SmartColumn注解配置了dateFormart则按dateFormart格式化
205 | *   1.2但是没有在@SmartColumn配置dateFormart;如果是String类型, 206 | * 则让mybatis解析(用#{}包裹)
207 | * 2、不是1和2的情况直接toString
208 | * 209 | * @param srcVal 原始值 210 | * @param fmi 对应的字段映射信息 211 | * @param index 批量插入时使用的索引 212 | * @return 返回column值 213 | * @throws IllegalAccessException 214 | */ 215 | static String buildColumnVal(Object srcVal, SmartColumnInfo fmi, Integer index) { 216 | if (srcVal == null) { 217 | return null; 218 | } 219 | String columnVal = null; 220 | Field fi = fmi.getField(); 221 | SmartColumn columInfo = fmi.getSmartColumn(); 222 | Class fieldType = fi.getType(); 223 | if (columInfo != null && columInfo.dateFormart().length() > 0) { 224 | if (srcVal instanceof Date) { 225 | return "'" + new SimpleDateFormat(columInfo.dateFormart()).format((Date) srcVal) + "'"; 226 | } else if (srcVal instanceof TemporalAccessor) { 227 | return "'" + DateTimeFormatter.ofPattern(columInfo.dateFormart()).format((TemporalAccessor) srcVal) 228 | + "'"; 229 | } 230 | } 231 | if (fieldType == String.class || srcVal instanceof Date || srcVal instanceof TemporalAccessor) { 232 | columnVal = MapperSqlTool.toBatisVal(srcVal, fi.getName(), index); 233 | } else { 234 | columnVal = srcVal.toString(); 235 | } 236 | return columnVal; 237 | } 238 | 239 | /** 240 | * 如果是 null、""、" "则处理为对应的sql值,反之不处理 241 | * 242 | * @param emptyVal null、""、" " 243 | * @return 返回处理后的值 244 | */ 245 | static String toSqlEmptyIfStringEmpty(String emptyVal) { 246 | return emptyVal == null ? ValTypeEnum.NULL.code 247 | : (emptyVal.trim().length() == 0 ? "'" + emptyVal + "'" : emptyVal); 248 | } 249 | 250 | /** 251 | * 如果是id字段,并且是默认的id成策略 252 | * 253 | * @param field 254 | * @param rowObj 255 | * @return 256 | */ 257 | static String generateIdIfIdFieldAndDftIdtactic(Field field, Object rowObj, SmartTable tableInfo) { 258 | String idVal = null; 259 | if (field.getName().equals(tableInfo.idFieldName()) && tableInfo.idtactics() == IdtacticsEnum.DFT) { 260 | idVal = MybatisSmartContext.getSequenceGenerate().nexId(tableInfo.value()); 261 | MapperSqlTool.injectIdVal(field, rowObj, idVal); 262 | } 263 | return idVal; 264 | } 265 | 266 | /** 267 | * 注入id值 268 | * 269 | * @param idField 270 | * @param rowObj 271 | * @param idVal 272 | */ 273 | private static void injectIdVal(Field idField, Object rowObj, String idVal) { 274 | idField.setAccessible(true); 275 | Class typeClazz = idField.getType(); 276 | try { 277 | if (typeClazz == String.class) { 278 | idField.set(rowObj, idVal); 279 | } else if (typeClazz == Long.class || typeClazz == long.class) { 280 | idField.set(rowObj, Long.valueOf(idVal)); 281 | } else if (typeClazz == Integer.class || typeClazz == int.class) { 282 | idField.set(rowObj, Integer.valueOf(idVal)); 283 | } else if (typeClazz == Short.class || typeClazz == short.class) { 284 | idField.set(rowObj, Short.valueOf(idVal)); 285 | } 286 | } catch (IllegalArgumentException | IllegalAccessException e) { 287 | e.printStackTrace(); 288 | } 289 | } 290 | 291 | /** 292 | * 293 | * 将原始值处理成mybatis可解析的值,如下:
294 | * 1、int 1 转成 字符串1
295 | * 2、String name 大神 转成 '大神'
296 | * 3、其他类型 fieleName 转成 #{fieleName} 或者 #{参数名称.fieleName} 或者 297 | * 。#{参数名称.[索引].字段名称.name}
298 | * 4、枚举 ValTypeEnum.BLANK 转成 空字符串值
299 | * 5、枚举 ValTypeEnum.NULL 转成 null
300 | * 301 | * @param srcVal 原始值 302 | * @param fieldName 字段名称 303 | * @param index inset集合时使用 304 | * @return 305 | */ 306 | private static String toBatisVal(Object srcVal, String fieldName, Integer index) { 307 | String indexStr = index == null ? "." : "[" + index + "]."; 308 | return "#{".concat(Constant.PARAM_KEY).concat(indexStr).concat(fieldName).concat("}"); 309 | } 310 | } -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/SmartTableInfo.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.Arrays; 5 | import java.util.Collection; 6 | import java.util.Collections; 7 | import java.util.LinkedHashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | import org.apache.ibatis.mapping.MappedStatement; 12 | import org.apache.ibatis.session.SqlSessionFactory; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | 16 | import com.mingri.langhuan.cabinet.constant.ObjTypeEnum; 17 | import com.mingri.langhuan.cabinet.constant.ValTypeEnum; 18 | import com.mingri.langhuan.cabinet.tool.ClassTool; 19 | import com.mingri.langhuan.cabinet.tool.StrTool; 20 | import com.mingri.mybatissmart.annotation.SmartColumn; 21 | import com.mingri.mybatissmart.annotation.SmartTable; 22 | import com.mingri.mybatissmart.barracks.DialectEnum; 23 | import com.mingri.mybatissmart.barracks.MybatisSmartException; 24 | import com.mingri.mybatissmart.dbo.MapperSql.Select; 25 | import com.mingri.mybatissmart.dbo.MapperSql.WhereSql; 26 | 27 | public class SmartTableInfo { 28 | 29 | private SmartTable smartTable; 30 | private Field idField; 31 | private String idColumnName; 32 | private Class clazz; 33 | LinkedHashMap smartColumnInfoMap;// key:columnName 34 | private DialectEnum dialect; 35 | private SqlSessionFactory sqlSessionFactory; 36 | private String[] keyProperties; 37 | 38 | private static final Logger LOGGER = LoggerFactory.getLogger(SmartTable.class); 39 | 40 | public Field getIdField() { 41 | return idField; 42 | } 43 | 44 | public void setIdField(Field idField) { 45 | this.idField = idField; 46 | } 47 | 48 | public SmartTable getSmartTable() { 49 | return smartTable; 50 | } 51 | 52 | public void setSmartTable(SmartTable smartTable) { 53 | this.smartTable = smartTable; 54 | } 55 | 56 | public Class getClazz() { 57 | return clazz; 58 | } 59 | 60 | public void setClazz(Class clazz) { 61 | this.clazz = clazz; 62 | } 63 | 64 | public LinkedHashMap getSmartColumnInfoMap() { 65 | return smartColumnInfoMap; 66 | } 67 | 68 | public void setSmartColumnInfoMap(LinkedHashMap smartColumnInfoMap) { 69 | this.smartColumnInfoMap = smartColumnInfoMap; 70 | } 71 | 72 | public String getIdColumnName() { 73 | return idColumnName; 74 | } 75 | 76 | public void setIdColumnName(String idColumnName) { 77 | this.idColumnName = idColumnName; 78 | } 79 | 80 | public SqlSessionFactory getSqlSessionFactory() { 81 | return sqlSessionFactory; 82 | } 83 | 84 | public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { 85 | this.sqlSessionFactory = sqlSessionFactory; 86 | } 87 | 88 | public DialectEnum getDialect() { 89 | return dialect; 90 | } 91 | 92 | public void setDialect(DialectEnum dialect) { 93 | this.dialect = dialect; 94 | } 95 | 96 | @SuppressWarnings("unchecked") 97 | public String getInsertSql(Object obj) throws Exception { 98 | MapperSql.Insert insert = MapperSql.insertInto(smartTable.value()); 99 | 100 | Collection dataList = null; 101 | Integer index = null; 102 | if (obj instanceof Collection) { 103 | index = 0; 104 | dataList = (Collection) obj; 105 | } else { 106 | dataList = Collections.singletonList(obj); 107 | } 108 | SmartColumn columnInfo = null; 109 | String colmVal = null; 110 | String colmName = null; 111 | Field field = null; 112 | for (Object rowObj : dataList) { 113 | for (Map.Entry en : smartColumnInfoMap.entrySet()) { 114 | columnInfo = en.getValue().getSmartColumn(); 115 | colmName = en.getKey(); 116 | if (columnInfo != null && columnInfo.isInsert() == false) { 117 | continue; 118 | } 119 | field = en.getValue().getField(); 120 | 121 | /* 122 | * id处理 123 | */ 124 | colmVal = MapperSqlTool.generateIdIfIdFieldAndDftIdtactic(field, rowObj, smartTable); 125 | if (colmVal != null) { 126 | insert.intoColumn(colmName, index); 127 | insert.intoValue("'" + colmVal + "'"); 128 | continue; 129 | } 130 | 131 | Object srcVal = ClassTool.reflexVal(rowObj, field); 132 | 133 | /* 134 | * 没配置insertValType 135 | */ 136 | colmVal = MapperSqlTool.buildColumnVal(srcVal, en.getValue(), index); 137 | if (columnInfo == null || columnInfo.insertValType().length == 0) { 138 | /* 139 | * 不插入空字符串和null值、"null"、" " 140 | */ 141 | if (StrTool.checkNotEmpty(srcVal)) { 142 | insert.intoColumn(colmName, index); 143 | insert.intoValue(colmVal); 144 | } else if (index != null) {// 批量新增时 145 | insert.intoColumn(colmName, index); 146 | insert.intoValue(ValTypeEnum.NULL.code); 147 | } 148 | } else { 149 | List otEs = Arrays.asList(columnInfo.insertValType()); 150 | 151 | if (otEs.contains(ObjTypeEnum.ALL)) { 152 | insert.intoColumn(colmName, index); 153 | insert.intoValue(MapperSqlTool.toSqlEmptyIfStringEmpty(colmVal)); 154 | 155 | /* 156 | * 不插入空字符串和null值 157 | */ 158 | } else if (otEs.contains(ObjTypeEnum.OBJ)) { 159 | if (StrTool.checkNotEmpty(srcVal)) { 160 | insert.intoColumn(colmName, index); 161 | insert.intoValue(colmVal); 162 | } else if (index != null) {// 批量新增时 163 | insert.intoColumn(colmName, index); 164 | insert.intoValue(ValTypeEnum.NULL.code); 165 | } 166 | } 167 | } 168 | 169 | } 170 | insert.intoRowEnd(); 171 | if (index != null) { 172 | index++; 173 | } 174 | } 175 | return insert.build().toString(); 176 | } 177 | 178 | public String getUpdateByIdSql(Object obj) throws Exception { 179 | Where where = new Where().andEq(idColumnName, ClassTool.reflexVal(obj, idField)); 180 | return getUpdateByWhereSql(obj, where); 181 | } 182 | 183 | 184 | public String getUpdateBySetSAndWhereSql(SetSql sets, Where where) throws Exception { 185 | WhereSql whereSql = MapperSqlTool.buildWhere(sets, where, this); 186 | if (whereSql == null || whereSql.isEmpty()) { 187 | throw new MybatisSmartException("必须设置where条件"); 188 | } 189 | MapperSql.Update updateSql = MapperSql.update(smartTable.value(),sets); 190 | return updateSql.setWhere(whereSql).build().toString(); 191 | } 192 | 193 | public String getUpdateByWhereSql(Object obj, Where where) throws Exception { 194 | SmartColumn columnInfo = null; 195 | String colmVal = null; 196 | Field field = null; 197 | WhereSql whereSql = MapperSqlTool.buildWhere(obj, where, this); 198 | if (whereSql == null || whereSql.isEmpty()) { 199 | throw new MybatisSmartException("必须设置where条件"); 200 | } 201 | MapperSql.Update updateSql = MapperSql.update(smartTable.value()); 202 | String column = null; 203 | for (Map.Entry en : smartColumnInfoMap.entrySet()) { 204 | field = en.getValue().getField(); 205 | if (field.getName().equals(smartTable.idFieldName())) { 206 | continue; 207 | } 208 | columnInfo = en.getValue().getSmartColumn(); 209 | if (columnInfo != null && !columnInfo.isUpdate()) { 210 | continue; 211 | } 212 | column = en.getKey(); 213 | Object srcVal = ClassTool.reflexVal(obj, field); 214 | colmVal = MapperSqlTool.buildColumnVal(srcVal, en.getValue(), null); 215 | if (columnInfo == null || columnInfo.updateValType().length == 0) { 216 | if (StrTool.checkNotEmpty(srcVal)) { 217 | updateSql.set(column, colmVal); 218 | } 219 | } else { 220 | List otEs = Arrays.asList(columnInfo.updateValType()); 221 | if (otEs.contains(ObjTypeEnum.ALL)) { 222 | updateSql.set(column, MapperSqlTool.toSqlEmptyIfStringEmpty(colmVal)); 223 | } else if (otEs.contains(ObjTypeEnum.OBJ)) { 224 | if (StrTool.checkNotEmpty(srcVal)) { 225 | updateSql.set(column, colmVal); 226 | } 227 | } 228 | } 229 | } 230 | return updateSql.setWhere(whereSql).build().toString(); 231 | } 232 | 233 | public String getSelectByIdSql(Object idV) { 234 | MapperSql sql = MapperSql.select(MapperSqlTool.getColumns(this), smartTable.value()) 235 | .where(MapperSql.where().add(" " + idColumnName + "='" + idV + "'")).build(); 236 | return sql.toString(); 237 | } 238 | 239 | public String getSelectByWhereSql(Object obj, Where where) throws IllegalArgumentException, IllegalAccessException { 240 | WhereSql whereSql = MapperSqlTool.buildWhere(obj, where, this); 241 | Select selectSql = MapperSql.select(MapperSqlTool.getColumns(this), smartTable.value()).where(whereSql); 242 | if (where != null) { 243 | selectSql.orderBy(where.getOrderBy()).limit(where.getLimit(), where.getOffset(), dialect); 244 | } 245 | return selectSql.build().toString(); 246 | } 247 | 248 | public String getCountByWhereSql(Object obj, Where where) throws IllegalArgumentException, IllegalAccessException { 249 | WhereSql whereSql = MapperSqlTool.buildWhere(obj, where, this); 250 | MapperSql sql = MapperSql.select(" count(*) ", smartTable.value()).where(whereSql).build(); 251 | return sql.toString(); 252 | } 253 | 254 | public String getDeleteByWhereSql(Object obj, Where where) throws IllegalArgumentException, IllegalAccessException { 255 | WhereSql whereSql = MapperSqlTool.buildWhere(obj, where, this); 256 | return MapperSql.delete(smartTable.value()).setWhere(whereSql).build().toString(); 257 | } 258 | 259 | public String getDeleteByIdSql(Object idV) { 260 | return MapperSql.delete(smartTable.value()) 261 | .setWhere(MapperSql.where().add(" " + idColumnName + "='" + idV + "'")).build().toString(); 262 | } 263 | 264 | public static class Builder { 265 | 266 | private SmartTableInfo smartTableInfo; 267 | 268 | public Builder(Class smartTableClazz, SqlSessionFactory sqlSessionFactory, DialectEnum dialect) { 269 | smartTableInfo = new SmartTableInfo(); 270 | SmartTable smartTable = smartTableClazz.getAnnotation(SmartTable.class); 271 | try { 272 | validSmartTable(smartTable); 273 | Field idField = ClassTool.searchDecararedField(smartTableClazz, smartTable.idFieldName()); 274 | if (idField == null) { 275 | throw new MybatisSmartException( 276 | StrTool.concat(smartTableClazz.getCanonicalName(), "没有定义字段:", smartTable.idFieldName()) 277 | .toString()); 278 | } 279 | smartTableInfo.setIdField(idField); 280 | } catch (Exception e) { 281 | LOGGER.error("", e); 282 | throw new MybatisSmartException(StrTool.concat(smartTableClazz.getCanonicalName(), " @", 283 | SmartTable.class.getSimpleName(), " 配置有误:", e.getMessage()).toString()); 284 | } 285 | smartTableInfo.setSmartTable(smartTable); 286 | smartTableInfo.setClazz(smartTableClazz); 287 | smartTableInfo.setSqlSessionFactory(sqlSessionFactory); 288 | smartTableInfo.setDialect(dialect); 289 | } 290 | 291 | public SmartTableInfo builder(LinkedHashMap smartColumnInfoMap) { 292 | smartTableInfo.setSmartColumnInfoMap(smartColumnInfoMap); 293 | for (Map.Entry entry : smartColumnInfoMap.entrySet()) { 294 | if (entry.getValue().getField().equals(smartTableInfo.getIdField())) { 295 | smartTableInfo.setIdColumnName(entry.getKey()); 296 | break; 297 | } 298 | } 299 | if (StrTool.isEmpty(smartTableInfo.getIdColumnName())) { 300 | throw new MybatisSmartException(StrTool.concat(smartTableInfo.clazz.getCanonicalName(), " @", 301 | SmartTable.class.getSimpleName(), " 配置有误:默认配置idFieldName值是\"id\",", "表中没有\"id\"列,请正确配置idFieldName").toString()); 302 | } 303 | return smartTableInfo; 304 | } 305 | 306 | private static void validSmartTable(SmartTable smartTable) { 307 | String idFieldName = smartTable.idFieldName(); 308 | if (smartTable.value().length() == 0) { 309 | throw new MybatisSmartException("没有配置映射表"); 310 | } 311 | 312 | if (idFieldName.length() == 0) { 313 | throw new MybatisSmartException("没有配置唯一字段"); 314 | } 315 | } 316 | 317 | } 318 | 319 | private static final Object MODIFYKEYPROPERTIES_LOCK=new Object(); 320 | public void modifyKeyProperties(MappedStatement ms) { 321 | if (keyProperties != null) { 322 | return; 323 | } 324 | final String[] keyProperties2 = ms.getKeyProperties(); 325 | if (keyProperties2 == null) { 326 | LOGGER.warn("keyProperties is null"); 327 | return; 328 | } 329 | int len = keyProperties2.length; 330 | if (len == 0) { 331 | LOGGER.warn("keyProperties is empty"); 332 | } 333 | len = len == 0 ? 1 : len; 334 | synchronized (MODIFYKEYPROPERTIES_LOCK) { 335 | if (keyProperties != null) { 336 | return; 337 | } 338 | keyProperties = new String[len]; 339 | for (int i = 0; i < keyProperties.length; i++) { 340 | keyProperties[i] = this.idField.getName(); 341 | keyProperties2[i] = keyProperties[i]; 342 | } 343 | 344 | } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/dbo/Where.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.dbo; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import com.mingri.langhuan.cabinet.constant.LogicCmp; 7 | import com.mingri.langhuan.cabinet.constant.NexusCmp; 8 | import com.mingri.langhuan.cabinet.constant.OrderChar; 9 | import com.mingri.langhuan.cabinet.constant.ValTypeEnum; 10 | import com.mingri.langhuan.cabinet.tool.CollectionTool; 11 | import com.mingri.langhuan.cabinet.tool.StrTool; 12 | import com.mingri.mybatissmart.barracks.Constant; 13 | import com.mingri.mybatissmart.barracks.SqlKwd; 14 | 15 | /** 16 | * 模仿sql的where语句
17 | * 18 | * @author ljl 19 | * 20 | */ 21 | public class Where { 22 | 23 | private String orderBy = StrTool.EMPTY; 24 | private Integer offset; 25 | private Integer limit; 26 | private List nodes = new ArrayList<>(); 27 | 28 | private String afterConditionSql; 29 | 30 | public Integer getLimit() { 31 | return limit; 32 | } 33 | 34 | public Integer getOffset() { 35 | return offset; 36 | } 37 | 38 | public String getOrderBy() { 39 | return orderBy; 40 | } 41 | 42 | public Where() { 43 | } 44 | 45 | /** 46 | * and columnName nexusCmp 47 | * 48 | * @param columnName 列名称 49 | * @param nexusCmp 关系运算符 50 | */ 51 | public Where(String columnName, NexusCmp nexusCmp) { 52 | nodes.add(new WhereNode(LogicCmp.AND, columnName, nexusCmp)); 53 | } 54 | 55 | /** 56 | * and columnName nexusCmp val 57 | * 58 | * @param columnName 列名称 59 | * @param nexusCmp 关系运算符 60 | * @param val 列值 61 | */ 62 | public Where(String columnName, NexusCmp nexusCmp, Object val) { 63 | nodes.add(new WhereNode(LogicCmp.AND, columnName, nexusCmp, val)); 64 | } 65 | 66 | public Where(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp) { 67 | nodes.add(new WhereNode(logicCmp, columnName, nexusCmp)); 68 | } 69 | 70 | public Where(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp, Object val) { 71 | nodes.add(new WhereNode(logicCmp, columnName, nexusCmp, val)); 72 | } 73 | 74 | public Where(LogicCmp logicCmp, String columnName, NexusCmp nexusCmp, Object val, boolean isStatementVal) { 75 | nodes.add(new WhereNode(logicCmp, columnName, nexusCmp, val, isStatementVal)); 76 | } 77 | 78 | public void setLimit(int offset, int limit) { 79 | this.offset = offset; 80 | this.limit = limit; 81 | } 82 | 83 | public void setOrderBy(String orderBy) { 84 | this.orderBy = orderBy; 85 | } 86 | 87 | public void setOrderByDesc(String column) { 88 | this.orderBy = StrTool.concat(SqlKwd.ORDER_BY, column, Constant.SPACE, OrderChar.DESC); 89 | } 90 | 91 | public void addOrderByDesc(String column) { 92 | if (StrTool.isEmpty(this.orderBy)) { 93 | this.setOrderByDesc(column); 94 | } else { 95 | this.orderBy = StrTool.concat(this.orderBy, ",", column, Constant.SPACE, OrderChar.DESC); 96 | } 97 | } 98 | 99 | public void setOrderByAsc(String column) { 100 | this.orderBy = StrTool.concat(SqlKwd.ORDER_BY, column, Constant.SPACE, OrderChar.ASC); 101 | } 102 | 103 | public void addOrderByAsc(String column) { 104 | if (StrTool.isEmpty(this.orderBy)) { 105 | this.setOrderByAsc(column); 106 | } else { 107 | this.orderBy = StrTool.concat(this.orderBy, ",", column, Constant.SPACE, OrderChar.ASC); 108 | } 109 | } 110 | 111 | public void setNodes(List conds) { 112 | this.nodes = conds; 113 | } 114 | 115 | public List getNodes() { 116 | return nodes; 117 | } 118 | 119 | public Where andChildNodes(List nodes) { 120 | this.nodes.add(new WhereNode(LogicCmp.AND, nodes)); 121 | return this; 122 | } 123 | 124 | public Where orChildNodes(List nodes) { 125 | this.nodes.add(new WhereNode(LogicCmp.OR, nodes)); 126 | return this; 127 | } 128 | 129 | public Where andChildNodes(LogicCmp splitLogicCmp, String column, NexusCmp splitNexusCmp, List valueList) { 130 | addChildNodes(LogicCmp.AND, splitLogicCmp, column, splitNexusCmp, valueList); 131 | return this; 132 | } 133 | 134 | public Where orChildNodes(LogicCmp splitLogicCmp, String column, NexusCmp splitNexusCmp, List valueList) { 135 | addChildNodes(LogicCmp.OR, splitLogicCmp, column, splitNexusCmp, valueList); 136 | return this; 137 | } 138 | 139 | public Where addChildNodes(LogicCmp logicCmp, LogicCmp splitLogicCmp, String column, NexusCmp splitNexusCmp, 140 | List valueList) { 141 | if (CollectionTool.notEmpty(valueList)) { 142 | List childCondList = new ArrayList<>(); 143 | for (int i = 0; i < valueList.size(); i++) { 144 | childCondList.add(new WhereNode(splitLogicCmp, column, splitNexusCmp, valueList.get(i))); 145 | } 146 | this.nodes.add(new WhereNode(logicCmp, childCondList)); 147 | } 148 | return this; 149 | } 150 | 151 | /* 152 | * ================================================================与 153 | * ================================================================条 154 | * ================================================================件 155 | */ 156 | public Where addNode(WhereNode whereCond) { 157 | this.nodes.add(whereCond); 158 | return this; 159 | } 160 | 161 | public Where and(String columnName, NexusCmp nexusCmp) { 162 | nodes.add(new WhereNode(LogicCmp.AND, columnName, nexusCmp)); 163 | return this; 164 | } 165 | 166 | public Where andEq(String columnName) { 167 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.EQ)); 168 | return this; 169 | } 170 | 171 | public Where andLt(String columnName) { 172 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LT)); 173 | return this; 174 | } 175 | 176 | public Where andGt(String columnName) { 177 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.GT)); 178 | return this; 179 | } 180 | 181 | public Where andLtEq(String columnName) { 182 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LT_EQ)); 183 | return this; 184 | } 185 | 186 | public Where andGtEq(String columnName) { 187 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.GT_EQ)); 188 | return this; 189 | } 190 | 191 | public Where andLtGT(String columnName) { 192 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LT_GT)); 193 | return this; 194 | } 195 | 196 | public Where andLike(String columnName) { 197 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE)); 198 | return this; 199 | } 200 | 201 | public Where andLikeL(String columnName) { 202 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE_L)); 203 | return this; 204 | } 205 | 206 | public Where andLikeR(String columnName) { 207 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE_R)); 208 | return this; 209 | } 210 | 211 | public Where andLikeLR(String columnName) { 212 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE_LR)); 213 | return this; 214 | } 215 | 216 | public Where andEq(String columnName, Object val) { 217 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.EQ, val)); 218 | return this; 219 | } 220 | 221 | public Where andNoEq(String columnName, Object val) { 222 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.NO_EQ, val)); 223 | return this; 224 | } 225 | 226 | public Where andLt(String columnName, Object val) { 227 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LT, val)); 228 | return this; 229 | } 230 | 231 | public Where andGt(String columnName, Object val) { 232 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.GT, val)); 233 | return this; 234 | } 235 | 236 | public Where andLtEq(String columnName, Object val) { 237 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LT_EQ, val)); 238 | return this; 239 | } 240 | 241 | public Where andGtEq(String columnName, Object val) { 242 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.GT_EQ, val)); 243 | return this; 244 | } 245 | 246 | public Where andLtGT(String columnName, Object val) { 247 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LT_GT, val)); 248 | return this; 249 | } 250 | 251 | public Where andLike(String columnName, Object val) { 252 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE, val)); 253 | return this; 254 | } 255 | 256 | public Where andLikeL(String columnName, Object val) { 257 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE_L, val)); 258 | return this; 259 | } 260 | 261 | public Where andLikeR(String columnName, Object val) { 262 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE_R, val)); 263 | return this; 264 | } 265 | 266 | public Where andLikeLR(String columnName, Object val) { 267 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.LIKE_LR, val)); 268 | return this; 269 | } 270 | 271 | public Where andIsNull(String columnName) { 272 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.IS, ValTypeEnum.NULL)); 273 | return this; 274 | } 275 | 276 | public Where andIsNotNull(String columnName) { 277 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.IS_NOT, ValTypeEnum.NULL)); 278 | return this; 279 | } 280 | 281 | public Where andIn(String columnName, Object val) { 282 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.IN, val)); 283 | return this; 284 | } 285 | 286 | public Where andNotIn(String columnName, Object val) { 287 | nodes.add(new WhereNode(LogicCmp.AND, columnName, NexusCmp.NOT_IN, val)); 288 | return this; 289 | } 290 | 291 | /* 292 | * ================================================================或 293 | * ================================================================条 294 | * ================================================================件 295 | */ 296 | public Where or(String columnName, NexusCmp nexusCmp) { 297 | nodes.add(new WhereNode(LogicCmp.OR, columnName, nexusCmp)); 298 | return this; 299 | } 300 | 301 | public Where orEq(String columnName) { 302 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.EQ)); 303 | return this; 304 | } 305 | 306 | public Where orLt(String columnName) { 307 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LT)); 308 | return this; 309 | } 310 | 311 | public Where orGt(String columnName) { 312 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.GT)); 313 | return this; 314 | } 315 | 316 | public Where orLtEq(String columnName) { 317 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LT_EQ)); 318 | return this; 319 | } 320 | 321 | public Where orGtEq(String columnName) { 322 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.GT_EQ)); 323 | return this; 324 | } 325 | 326 | public Where orLtGT(String columnName) { 327 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LT_GT)); 328 | return this; 329 | } 330 | 331 | public Where orLike(String columnName) { 332 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE)); 333 | return this; 334 | } 335 | 336 | public Where orLikeL(String columnName) { 337 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE_L)); 338 | return this; 339 | } 340 | 341 | public Where orLikeR(String columnName) { 342 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE_R)); 343 | return this; 344 | } 345 | 346 | public Where orLikeLR(String columnName) { 347 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE_LR)); 348 | return this; 349 | } 350 | 351 | public Where orEq(String columnName, Object val) { 352 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.EQ, val)); 353 | return this; 354 | } 355 | 356 | public Where orLt(String columnName, Object val) { 357 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LT, val)); 358 | return this; 359 | } 360 | 361 | public Where orGt(String columnName, Object val) { 362 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.GT, val)); 363 | return this; 364 | } 365 | 366 | public Where orLtEq(String columnName, Object val) { 367 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LT_EQ, val)); 368 | return this; 369 | } 370 | 371 | public Where orGtEq(String columnName, Object val) { 372 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.GT_EQ, val)); 373 | return this; 374 | } 375 | 376 | public Where orLtGT(String columnName, Object val) { 377 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LT_GT, val)); 378 | return this; 379 | } 380 | 381 | public Where orLike(String columnName, Object val) { 382 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE, val)); 383 | return this; 384 | } 385 | 386 | public Where orLikeL(String columnName, Object val) { 387 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE_L, val)); 388 | return this; 389 | } 390 | 391 | public Where orLikeR(String columnName, Object val) { 392 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE_R, val)); 393 | return this; 394 | } 395 | 396 | public Where orLikeLR(String columnName, Object val) { 397 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.LIKE_LR, val)); 398 | return this; 399 | } 400 | 401 | public Where orIsNull(String columnName) { 402 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.IS, ValTypeEnum.NULL)); 403 | return this; 404 | } 405 | 406 | public Where orIsNotNull(String columnName) { 407 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.IS_NOT, ValTypeEnum.NULL)); 408 | return this; 409 | } 410 | 411 | public Where orIn(String columnName, Object val) { 412 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.IN, val)); 413 | return this; 414 | } 415 | 416 | public Where orNotIn(String columnName, Object val) { 417 | nodes.add(new WhereNode(LogicCmp.OR, columnName, NexusCmp.NOT_IN, val)); 418 | return this; 419 | } 420 | 421 | public String getAfterConditionSql() { 422 | return afterConditionSql; 423 | } 424 | 425 | public void setAfterConditionSql(String afterConditionSql) { 426 | this.afterConditionSql = afterConditionSql; 427 | } 428 | 429 | public Where removeCond(String columnName) { 430 | nodes.removeIf(cond -> cond.getColumnName().equals(columnName)); 431 | return this; 432 | } 433 | } 434 | -------------------------------------------------------------------------------- /src/main/java/com/mingri/mybatissmart/config/MybatisSmartContext.java: -------------------------------------------------------------------------------- 1 | package com.mingri.mybatissmart.config; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.Type; 5 | import java.sql.Connection; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Collections; 10 | import java.util.HashMap; 11 | import java.util.LinkedHashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | import java.util.Set; 15 | import java.util.concurrent.atomic.AtomicInteger; 16 | 17 | import javax.annotation.PostConstruct; 18 | 19 | import org.apache.ibatis.executor.keygen.NoKeyGenerator; 20 | import org.apache.ibatis.mapping.MappedStatement; 21 | import org.apache.ibatis.mapping.SqlCommandType; 22 | import org.apache.ibatis.session.SqlSession; 23 | import org.apache.ibatis.session.SqlSessionFactory; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | import org.springframework.context.ConfigurableApplicationContext; 27 | import org.springframework.util.Assert; 28 | import org.springframework.util.StringUtils; 29 | 30 | import com.mingri.langhuan.cabinet.algorithm.SequenceGenerate; 31 | import com.mingri.langhuan.cabinet.constant.FileSufx; 32 | import com.mingri.langhuan.cabinet.tool.ClassTool; 33 | import com.mingri.langhuan.cabinet.tool.FileTool; 34 | import com.mingri.langhuan.cabinet.tool.StrTool; 35 | import com.mingri.mybatissmart.annotation.SmartColumn; 36 | import com.mingri.mybatissmart.annotation.SmartTable; 37 | import com.mingri.mybatissmart.barracks.Constant; 38 | import com.mingri.mybatissmart.barracks.DialectEnum; 39 | import com.mingri.mybatissmart.barracks.IdtacticsEnum; 40 | import com.mingri.mybatissmart.barracks.MybatisSmartException; 41 | import com.mingri.mybatissmart.barracks.Tool; 42 | import com.mingri.mybatissmart.dbo.SmartColumnInfo; 43 | import com.mingri.mybatissmart.dbo.SmartTableInfo; 44 | import com.mingri.mybatissmart.ex.SmartKeyGenerator; 45 | import com.mingri.mybatissmart.mapper.InsertSmartMapper; 46 | import com.mingri.mybatissmart.mapper.InternalMapper; 47 | import com.mingri.mybatissmart.mapper.SmartMapper; 48 | 49 | /** 50 | * mybatis-smart 上下文,单例的 51 | * 52 | * @author ljl 2019年11月30日 53 | */ 54 | public class MybatisSmartContext { 55 | 56 | private final static Logger LOGGER = LoggerFactory.getLogger(MybatisSmartContext.class); 57 | 58 | private List mappingConfigList=new ArrayList<>(); 59 | 60 | private static SequenceGenerate sequenceGenerate; 61 | 62 | 63 | /** 64 | * 表类映射信息 65 | */ 66 | private static final Map, SmartTableInfo> SMART_TABLE_MAP = new HashMap<>(); 67 | 68 | private static final AtomicInteger SQL_INCR_COUNT = new AtomicInteger(); 69 | 70 | private volatile static int LOAD_STATUS = -1; 71 | 72 | 73 | public static SequenceGenerate getSequenceGenerate() { 74 | if (sequenceGenerate == null) { 75 | sequenceGenerate = SequenceGenerate.getInstance(); 76 | } 77 | return sequenceGenerate; 78 | } 79 | 80 | public void setSequenceGenerate(SequenceGenerate sequenceGenerate) { 81 | MybatisSmartContext.sequenceGenerate = sequenceGenerate; 82 | } 83 | 84 | public List getMappingConfigList() { 85 | return Collections.unmodifiableList(mappingConfigList); 86 | } 87 | 88 | public void setMappingConfigList(List mappingConfigList) { 89 | this.mappingConfigList = mappingConfigList; 90 | } 91 | 92 | public void addConfig(MappingConfig mappingConfig) { 93 | mappingConfigList.add(mappingConfig); 94 | } 95 | 96 | 97 | 98 | @PostConstruct 99 | public void start() { 100 | try { 101 | LOAD_STATUS=0; 102 | org.apache.ibatis.session.Configuration ibatisConfiguration = null; 103 | SqlSessionFactory sessionFactory = null; 104 | for (MappingConfig configuration : mappingConfigList) { 105 | sessionFactory = configuration.getSqlSessionFactory(); 106 | ibatisConfiguration = sessionFactory.getConfiguration(); 107 | if (!ibatisConfiguration.hasMapper(InternalMapper.class)) { 108 | ibatisConfiguration.addMapper(InternalMapper.class); 109 | } 110 | scanSmartTable(configuration); 111 | } 112 | replaceKeyGenerator(); 113 | // addSqlInterceptor(); 114 | } catch (Exception e) { 115 | LOGGER.error("捕获到异常,打印日志", e); 116 | throw new MybatisSmartException(e.getLocalizedMessage() + "---" + e.getMessage()); 117 | } finally { 118 | LOAD_STATUS = 1; 119 | } 120 | } 121 | 122 | public static SmartTableInfo getSmartTableInfo(Class tableClass) { 123 | // 没有scanMapping 124 | SmartTableInfo smti = SMART_TABLE_MAP.get(tableClass); 125 | if (smti != null) { 126 | return smti; 127 | } 128 | 129 | Class tmpTableClass = tableClass; 130 | checkisNeedWaitLoad(); 131 | while (tmpTableClass != null && tmpTableClass != Object.class) { 132 | tmpTableClass = tmpTableClass.getSuperclass(); 133 | if (tmpTableClass.getAnnotation(SmartTable.class) != null) {// 。 拿父类的 134 | smti = SMART_TABLE_MAP.get(tmpTableClass); 135 | if (smti != null) { 136 | return smti; 137 | } 138 | } 139 | } 140 | throw new MybatisSmartException(StrTool 141 | .concat("Class:", tableClass.getCanonicalName(), " 或者其父类 没有配置注解:@", SmartTable.class.getSimpleName()) 142 | .toString()); 143 | } 144 | 145 | private static void checkisNeedWaitLoad() { 146 | int waitNum = 1; 147 | while (LOAD_STATUS==-1 && waitNum < 800) { 148 | try { 149 | Thread.sleep(50); 150 | waitNum++; 151 | } catch (InterruptedException e) { 152 | e.printStackTrace(); 153 | } 154 | } 155 | if(LOAD_STATUS==-1) { 156 | LOAD_STATUS = 1; 157 | throw new MybatisSmartException("未扫描实体类和表的映射关系"); 158 | } 159 | if(LOAD_STATUS==0) { 160 | LOAD_STATUS = 1; 161 | throw new MybatisSmartException("扫描实体类和表的映射关系超时"); 162 | } 163 | } 164 | 165 | public static Set getColumns(Class cl) { 166 | SmartTableInfo smti = getSmartTableInfo(cl); 167 | if (smti != null) { 168 | return smti.getSmartColumnInfoMap().keySet(); 169 | } 170 | return Collections.emptySet(); 171 | } 172 | 173 | public static String getTable(Class cl) { 174 | SmartTableInfo smti = getSmartTableInfo(cl); 175 | if (smti != null) { 176 | return smti.getSmartTable().value(); 177 | } 178 | return null; 179 | } 180 | 181 | private List selectColumns(String tableName, SqlSessionFactory sessionFactory) { 182 | try (SqlSession session = sessionFactory.openSession()) { 183 | return session.selectList(InternalMapper.SELECTFIELDS_STATEMENT, 184 | tableName.replace("[", "").replace("]", "")); 185 | } catch (Exception e) { 186 | LOGGER.error("捕获到异常,打印日志", e); 187 | } 188 | return Collections.emptyList(); 189 | } 190 | 191 | private final static Object MAPPING_LOCAL = new Object(); 192 | 193 | private void validSmartTable(SmartTable tableInfo) { 194 | String idFieldName = tableInfo.idFieldName(); 195 | String tableName = Tool.getTableName(tableInfo); 196 | if (tableName.isEmpty()) { 197 | throw new MybatisSmartException(SmartTable.class.getCanonicalName() + " 的value 不能为空"); 198 | } 199 | 200 | if (idFieldName.length() == 0) { 201 | throw new MybatisSmartException(SmartTable.class.getCanonicalName() + " 的idFieldName value 不能为空"); 202 | } 203 | } 204 | 205 | /** 206 | * 映射表模型 207 | * 208 | * @param smartTableClass 209 | * @return 210 | * @throws SQLException 211 | */ 212 | private LinkedHashMap mappingSmartTable(Class smartTableClass, 213 | SqlSessionFactory sqlSessionFactory) throws SQLException { 214 | 215 | SmartTable tableInfo = smartTableClass.getAnnotation(SmartTable.class); 216 | if (tableInfo == null) { 217 | return null; 218 | } 219 | validSmartTable(tableInfo); 220 | String tableName = Tool.getTableName(tableInfo); 221 | Map fieldColNameDbMap = getFieldAndColumnNameMap(tableName, sqlSessionFactory); 222 | 223 | if (fieldColNameDbMap == null || fieldColNameDbMap.isEmpty()) { 224 | LOGGER.warn("---------------扫描警告:{} 没有映射表", smartTableClass); 225 | return null; 226 | } 227 | 228 | List fieldList = ClassTool.getDecararedFields(smartTableClass, false); 229 | LinkedHashMap columnFieldMap = new LinkedHashMap<>(); 230 | 231 | for (Field field : fieldList) { 232 | 233 | SmartColumn columnInfo = field.getAnnotation(SmartColumn.class); 234 | String columnName = columnInfo == null ? StrTool.EMPTY 235 | : Tool.unifiedColumnName(StrTool.toString(columnInfo.value())); 236 | 237 | if (columnName.isEmpty()) { 238 | // 。根据驼峰规则自动映射 239 | columnName = fieldColNameDbMap.get(field.getName()); 240 | if (columnName == null) { 241 | // 。 该字段没有映射的列 242 | continue; 243 | } 244 | } else { 245 | // 。根据注解配置映射 246 | if (!fieldColNameDbMap.containsValue(columnName)) { 247 | throw new MybatisSmartException(StrTool.concat(tableName, " 表中没有字段:", columnName).toString()); 248 | } 249 | } 250 | 251 | SmartColumnInfo smci = columnFieldMap.get(columnName); 252 | if (smci == null) { 253 | columnFieldMap.put(columnName, new SmartColumnInfo(field, columnInfo)); 254 | } else { 255 | if (field.getDeclaringClass() == smci.getField().getDeclaringClass()) { 256 | throw new MybatisSmartException(StrTool.concat(smartTableClass.getCanonicalName(), 257 | " 类中字段名称解析相同,字段:", smci.getField().getName(), "和", field.getName()).toString()); 258 | } else { 259 | smci.setField(field); 260 | smci.setSmartColumn(columnInfo); 261 | } 262 | } 263 | } 264 | return columnFieldMap; 265 | } 266 | 267 | /** 268 | * 扫描数据模型 269 | */ 270 | private void scanSmartTable(MappingConfig configuration) throws ClassNotFoundException, SQLException { 271 | String mdpkg = configuration.getTablePackages(); 272 | SqlSessionFactory sqlSessionFactory = configuration.getSqlSessionFactory(); 273 | DialectEnum dialect = DialectEnum.ofName(configuration.getDialect()); 274 | String sqlSessionFactoryBeanName = StrTool.toString(configuration.getSqlSessionFactoryBeanName()); 275 | if (StrTool.isNotEmpty(mdpkg)) { 276 | String[] mdpkgArray = StringUtils.tokenizeToStringArray(mdpkg, 277 | ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); 278 | ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 279 | for (String packageName : mdpkgArray) { 280 | LOGGER.info("==============================MybatisSmart {} 开始扫描tablePackage:{}", 281 | sqlSessionFactoryBeanName, packageName); 282 | List classList = FileTool.scanClass(packageName, true); 283 | LOGGER.info("==============================MybatisSmart {} 开始扫描{}", sqlSessionFactoryBeanName, 284 | classList); 285 | for (String classFileName : classList) { 286 | try { 287 | Class smartTableClazz = classLoader.loadClass( 288 | classFileName.substring(0, classFileName.length() - FileSufx.CLAZZ.length())); 289 | if (smartTableClazz.getAnnotation(SmartTable.class) == null) { 290 | continue; 291 | } 292 | synchronized (MAPPING_LOCAL) { 293 | SmartTableInfo tableModelInfo = SMART_TABLE_MAP.get(smartTableClazz); 294 | if (tableModelInfo != null) { 295 | return; 296 | } 297 | LinkedHashMap smartColumnInfoMap = mappingSmartTable( 298 | smartTableClazz, sqlSessionFactory); 299 | if (smartColumnInfoMap == null) { 300 | continue; 301 | } 302 | DialectEnum dialectEnum = getDialect(sqlSessionFactory); 303 | if (dialectEnum != null) { 304 | dialect = dialectEnum; 305 | } 306 | SmartTableInfo smartTableInfo = new SmartTableInfo.Builder(smartTableClazz, 307 | sqlSessionFactory, dialect).builder(smartColumnInfoMap); 308 | 309 | SMART_TABLE_MAP.put(smartTableClazz, smartTableInfo); 310 | if (smartTableInfo.getSmartTable().idtactics() == IdtacticsEnum.SQL_INCR) { 311 | SQL_INCR_COUNT.incrementAndGet(); 312 | } 313 | } 314 | LOGGER.info("MybatisSmart {} Scanned class: {} for tablePackage: {}", sqlSessionFactoryBeanName, 315 | classFileName, packageName); 316 | } catch (ClassNotFoundException | SQLException e) { 317 | LOGGER.error("MybatisSmart {} 扫描tablePackage出错: {}", sqlSessionFactoryBeanName, e); 318 | throw e; 319 | } 320 | } 321 | 322 | } 323 | } 324 | } 325 | 326 | /** 327 | * 获取数据库方言 328 | * 329 | * @return 330 | * @throws SQLException 331 | */ 332 | private DialectEnum getDialect(SqlSessionFactory sessionFactory) throws SQLException { 333 | try (Connection conn = sessionFactory.openSession().getConnection()) { 334 | return Tool.getDialect(conn); 335 | } 336 | } 337 | 338 | /** 339 | * 获取java字段名称和数据库字段名称 340 | * 341 | * @param tableName 表名 342 | * @return key:fieldName(columnName转驼峰后的name) val:columnName(大写) 343 | */ 344 | private Map getFieldAndColumnNameMap(String tableName, SqlSessionFactory sqlSessionFactory) { 345 | List columns = selectColumns(tableName, sqlSessionFactory); 346 | Map columnsCamel = new HashMap<>(); 347 | columns.forEach(column -> { 348 | String columnName = Tool.unifiedColumnName(column); 349 | String fieldName = StrTool.camel(columnName); 350 | columnsCamel.put(fieldName, columnName); 351 | }); 352 | return columnsCamel; 353 | } 354 | 355 | /** 356 | * 为InsertSmartMapper 子类更换id生成器 357 | * 358 | * @author jinlin Li 359 | */ 360 | private void replaceKeyGenerator() { 361 | if (SMART_TABLE_MAP.isEmpty()) { 362 | return; 363 | } 364 | org.apache.ibatis.session.Configuration ibatisConfiguration = null; 365 | Field fi = ClassTool.searchDecararedField(MappedStatement.class, "keyGenerator"); 366 | fi.setAccessible(true); 367 | for (MappingConfig configuration : mappingConfigList) { 368 | ibatisConfiguration = configuration.getSqlSessionFactory().getConfiguration(); 369 | Collection stList = ibatisConfiguration.getMappedStatements(); 370 | for (Object obj : stList) { 371 | boolean isSmartSubMapper = false; 372 | if (!(obj instanceof MappedStatement)) { 373 | continue; 374 | } 375 | MappedStatement mappedStatement = (MappedStatement) obj; 376 | SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType(); 377 | String resource = mappedStatement.getResource(); 378 | try { 379 | if (sqlCommandType != SqlCommandType.INSERT || !(fi.get(mappedStatement) instanceof NoKeyGenerator) 380 | || !(mappedStatement.getId().endsWith(Constant.INSERT_METHOD))) { 381 | continue; 382 | } 383 | int index = resource.indexOf(".java"); 384 | resource = FileTool.dirToPkg(resource.substring(0, index)); 385 | 386 | Class mapperClazz = Class.forName(resource); 387 | boolean isInsertMapper = SmartMapper.class.isAssignableFrom(mapperClazz) 388 | || InsertSmartMapper.class.isAssignableFrom(mapperClazz); 389 | if (isInsertMapper == false) { 390 | continue; 391 | } 392 | 393 | List types = ClassTool.getExtendGenericity(mapperClazz, SmartMapper.class); 394 | if (types.isEmpty()) { 395 | types = ClassTool.getExtendGenericity(mapperClazz, InsertSmartMapper.class); 396 | if (types.isEmpty()) { 397 | Assert.notEmpty(types, "mapper:" + mappedStatement.getResource() + "没有设定泛型!!!"); 398 | } 399 | } 400 | 401 | isSmartSubMapper = true; 402 | Class tableClazz = null; 403 | try { 404 | tableClazz = Class.forName(types.get(0).getTypeName()); 405 | 406 | SmartTableInfo smtb = getSmartTableInfo(tableClazz); 407 | if (smtb == null) { 408 | LOGGER.warn("============》 {} 的泛型类没有配置注解:@ {} ", mappedStatement.getResource(), 409 | SmartTable.class.getCanonicalName()); 410 | continue; 411 | } 412 | if (smtb.getSmartTable().idtactics() != IdtacticsEnum.SQL_INCR) { 413 | continue; 414 | } 415 | } catch (Exception e) { 416 | if (tableClazz == null) { 417 | LOGGER.error("扫描", mappedStatement.getResource(), "的泛型出错", e); 418 | } 419 | continue; 420 | } 421 | fi.set(mappedStatement, SmartKeyGenerator.INSTANCE); 422 | LOGGER.info("\"数据库id自增\"扫描===》:{}", tableClazz.getCanonicalName()); 423 | } catch (Exception e) { 424 | if (isSmartSubMapper && SQL_INCR_COUNT.getAndDecrement() > 0) { 425 | // fi.set(mappedStatement, SmartKeyGenerator.INSTANCE); 426 | LOGGER.warn("\"数据库id自增扫描\"===》:{},", resource, "未扫描到它的泛型实体类"); 427 | } 428 | LOGGER.error("捕获到异常,打印日志", e); 429 | } 430 | } 431 | } 432 | } 433 | 434 | } --------------------------------------------------------------------------------