![2746c8d442adbfdff150fd8ff9d0347a.png](https://i-blog.csdnimg.cn/blog_migrate/5c158d20ed8d6d6d637d70d034ecafce.jpeg)
创建通用接口
在通用接口中使用@InsertProvider,@UpdateProvider,@DeleteProvider,@SelectProvider注解配置增删改查的类和方法,并添加通用方法
public interface BaseMapper { @InsertProvider(type = BaseMapperProvider.class, method = "insert") int insert(T entity); @DeleteProvider(type = BaseMapperProvider.class, method = "deleteByPrimary") int deleteByPrimary(E id); @DeleteProvider(type = BaseMapperProvider.class, method = "delete") int delete(@Param("wrapper") Wrapper wrapper); @UpdateProvider(type = BaseMapperProvider.class, method = "updateByPrimary") int updateByPrimary(T entity); @DeleteProvider(type = BaseMapperProvider.class, method = "update") int update(@Param("entity") T entity, @Param("wrapper") Wrapper wrapper); @SelectProvider(type = BaseMapperProvider.class, method = "selectByPrimary") T selectByPrimary(@Param("id") E id); @SelectProvider(type = BaseMapperProvider.class, method = "select") T selectOne(@Param("wrapper") Wrapper wrapper); @SelectProvider(type = BaseMapperProvider.class, method = "select") List select(); @SelectProvider(type = BaseMapperProvider.class, method = "select") List selectList(@Param("wrapper") Wrapper wrapper);}
自定义注解
通过注解配置表的一些信息
1.@Table 配置表
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface Table {/** * 配置表名 * * @return 表名 */ String value() default "";}
2.@Column 配置字段
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Column { /** * 配置字段名称 * * @return 字段名称 */ String value() default ""; /** * 配置字段排序 * * @return 字段排序 */ boolean order() default false; /** * 配置字段排序类型 * * @return 段排序类型 */ String orderType() default "desc";}
3.@JoinColumn 配置关联表
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface JoinColumn { /** * 配置要关联的表 * * @return 表名 */ String tableName(); /** * 配置字段名称 * * @return 字段名称 */ String column() default ""; /** * 配置两表之间的关系 * * @return 两表之间的关系 */ Association[] relations();}
4.@Association 配置两表之间的关系
public @interface Association { /** * 配置当前表字段名称 * * @return 当前表字段名称 */ String target(); /** * 配置关联表字段名称 * * @return 关联表字段名称 */ String association();}
5.@Primary 配置主键
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public @interface Primary { /** * 配置主键 * * @return 是否是主键 */ boolean value() default true;}
3.编写BaseMapperProvider通过注解动态拼接SQL
这个类的方法可以加入ProviderContext类型的参数,可以通过 ProviderContext 来获取mapper的信息,通过泛型获取实体,通过注解动态生成SQL
public class BaseMapperProvider { /** * 用来缓存已经生成的SQL */ private static final Map CONTEXT = new ConcurrentHashMap<>(); public String insert(ProviderContext context) { return getSqlBuilder(context).insert().build(); } public String deleteByPrimary(Object o, ProviderContext context) { return getSqlBuilder(context).select().byPrimary().build(); } public String delete(Wrapper wrapper, ProviderContext context) { return getSqlBuilder(context).delete().where(wrapper).build(); } public String updateByPrimary(Object o, ProviderContext context) { return getSqlBuilder(context).update().byPrimary().build(); } public String update(Object entity, Wrapper wrapper, ProviderContext context) { return getSqlBuilder(context).update().where(wrapper).build(); } public String select(Wrapper wrapper, ProviderContext context) { return getSqlBuilder(context).select().where(wrapper).build(); } public String selectByPrimary(Object o, ProviderContext context) { return getSqlBuilder(context).select().byPrimary().build(); } private Class getEntityType(ProviderContext context) { return (Class) ((ParameterizedType) (context.getMapperType().getGenericInterfaces()[0])).getActualTypeArguments()[0]; } private SQLBuilder getSqlBuilder(ProviderContext context) { String name = getEntityType(context).getName(); SQLBuilder sqlBuilder = CONTEXT.get(name); if (sqlBuilder == null) { sqlBuilder = new SQLBuilder(getEntityType(context)); CONTEXT.put(name, sqlBuilder); } return sqlBuilder.reset(); }}
4.动态SQL类编写
public class SQLBuilder { private final TableInfo tableInfo; private final Class> type; private SQL sql; public SQLBuilder(Class> type) { this.tableInfo = new TableInfo(type); this.type = type; } public SQLBuilder reset() { sql = new SQL(); return this; } public SQLBuilder insert() { List columns = tableInfo.getColumns(); sql.INSERT_INTO(getTableName()); StringBuilder value = new StringBuilder(); StringBuilder values = new StringBuilder(); for (int i = 0; i < columns.size(); i++) { ColumnInfo columnInfo = columns.get(i); String columnName = columnInfo.getColumnName(); String fieldName = columnInfo.getFieldName(); String separator = ","; if (i + 1 == columns.size()) { separator = ""; } value.append(ifScript(fieldName, columnName, separator)); values.append(ifScript(fieldName, sharp(fieldName), separator)); } sql.VALUES(getPrimaryColumnName(), sharp(getPrimaryFieldName())); sql.VALUES(value.toString(), values.toString()); return this; } public SQLBuilder delete() { sql.DELETE_FROM(getTableName()); return this; } public SQLBuilder update() { List columns = tableInfo.getColumns(); sql.UPDATE(getTableName()); StringBuilder set = new StringBuilder(); for (int i = 0; i < columns.size(); i++) { ColumnInfo columnInfo = columns.get(i); String fieldName = columnInfo.getFieldName(); String columnName = columnInfo.getColumnName(); String separator = ","; if (i + 1 == columns.size()) { separator = ""; } set.append(ifScript(fieldName, set(columnName, fieldName), separator)); } sql.SET(set.toString()); return this; } public SQLBuilder select() { String tableName = getTableName(); sql.SELECT(select(tableName, getPrimaryColumnName(), getPrimaryFieldName())); for (ColumnInfo columnInfo : tableInfo.getColumns()) { sql.SELECT(select(tableName, columnInfo.getColumnName(), columnInfo.getFieldName())); } sql.FROM(tableName); for (JoinColumnInfo joinColumnInfo : tableInfo.getJoinColumns()) { String joinTableName = joinColumnInfo.getTableName(); sql.FROM(joinTableName); sql.SELECT(select(joinTableName, joinColumnInfo.getColumnName(), joinColumnInfo.getFieldName())); List associations = joinColumnInfo.getAssociations(); for (AssociationInfo associationInfo : associations) { sql.WHERE(condition(tableName, associationInfo.getTarget(), joinTableName, associationInfo.getAssociation())); } } return this; } public SQLBuilder byPrimary() { sql.WHERE(condition(getTableName(), getPrimaryColumnName(), "id")); return this; } public SQLBuilder where(Wrapper wrapper) { if (wrapper != null) { List conditions = wrapper.getConditions(); for (Condition condition : conditions) { if (condition.isAnd()) { sql.AND(); } if (!condition.isAnd()) { sql.OR(); } sql.WHERE(condition.render()); } } return this; } public TableInfo getTableInfo() { return tableInfo; } public Class> getType() { return type; } private String getTableName() { return tableInfo.getTableName(); } private PrimaryInfo getPrimaryInfo() { return tableInfo.getPrimaryInfo(); } private String getPrimaryColumnName() { return getPrimaryInfo().getColumnName(); } private String getPrimaryFieldName() { return getPrimaryInfo().getFieldName(); } private String select(String tableName, String columnName, String fieldName) { return String.format("%s.%s "%s"", tableName, columnName, fieldName); } private String sharp(String fieldName) { return String.format("#{%s}", fieldName); } private String set(String columnName, String fieldName) { return String.format("%s = #{%s}", columnName, fieldName); } private String ifScript(String fieldName, String content, String separator) { return String.format("%s%s", fieldName, fieldName, content, separator); } private String condition(String tableName, String columnName, String fieldName) { return String.format("%s.%s = #{%s}", tableName, columnName, fieldName); } private String condition(String tableName, String left, String joinTableName, String right) { return String.format("%s.%s = %s.%s", tableName, left, joinTableName, right); } /** * "; }}
有几个对应注解的实体我就不粘了,这些代码只是给大家提供些思路,这种方式是完全支持xml写法的,具体实现可以看看这个项目
https://gitee.com/931942788/common-mapper