欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解如何開發(fā)一個(gè)MyBatis通用Mapper的輪子

 更新時(shí)間:2022年12月21日 09:29:37   作者:失足成萬古風(fēng)流人物  
因?yàn)橐恍┰颍纾和ㄓ脭?shù)據(jù)權(quán)限控制、MyBatis-Plus好像不支持聯(lián)合主鍵等,我們不得不開發(fā)一個(gè)MyBatis通用Mapper的輪子。文中的示例代碼講解詳細(xì),需要的可以參考一下

一、前言

程序猿為什么如此執(zhí)著于造輪子?MyBatis-Plus如此強(qiáng)大的工具流行這么多年了,我為啥還在重復(fù)造這樣的輪子?

1、公司的技術(shù)規(guī)范不允許使用MyBatis-Plus,咱也不知道什么原因;

3、以前使用SpringDataJpa慣了,今年第一次用MyBatis,必須把它打造成我想要的樣子;

6、MyBatis-Plus好像不支持聯(lián)合主鍵;

7、還有一些其它的需求,比如對(duì)字典字段自動(dòng)翻譯:字典可能來自枚舉、字典表、Redis......

10、通用數(shù)據(jù)權(quán)限控制;

11、如果不造此輪子,就沒有這篇文章。

以上12點(diǎn)原因,便是造這個(gè)輪子的理由。實(shí)際上,輪子不重要,重要的是掌握輪子的原理,取其精華,去其糟粕。也歡迎大家拍磚,請(qǐng)輕拍,數(shù)學(xué)能力被誰拍壞了誰來陪。

二、需求

通用Mapper起碼應(yīng)該包含以下功能:

1、增

2、刪

3、改

4、批量增

5、批量刪

6、只更新指定字段

7、分頁查詢查當(dāng)前頁

8、分頁查詢查總數(shù)

9、字典字段翻譯

10、數(shù)據(jù)權(quán)限控制

大概長(zhǎng)下面這個(gè)樣子: 

public interface BaseMapper<T,K> {

    int insert(T t);

    int batchInsert(List<T> entity);
    
    int deleteById(K id);
    
    int deleteBatchIds(Collection<K> ids);
    
    int updateById(T entity);
    
    int updateSelectiveById(T entity);
    
    T selectById(K id);
    
    List<T> selectBatchIds(Collection<K> ids);
    
    List<T> selectAll();
    
    List<T> selectPage(PageRequest<T> pageRequest);
    
    Long selectCount(T entity);

}

三、實(shí)現(xiàn)原理

1、基于MyBatis3提供的SqlProvider構(gòu)建動(dòng)態(tài)Sql

例如如下代碼:

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(String name);

class UserSqlBuilder {
  public static String buildGetUsersByName(final String name) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      if (name != null) {
        WHERE("name like #{value} || '%'");
      }
      ORDER_BY("id");
    }}.toString();
  }
}

2、基于自定義注解,為實(shí)體和數(shù)據(jù)庫表建立對(duì)應(yīng)關(guān)系

例如如下代碼:

@Table("user")
public class User {
    @Id(auto = true)
    @Column(value = "id")
    private Long id;

    @Column(value = "name", filterOperator = FilterOperator.LIKE)
    @OrderBy(orderPriority = 0)
    private String name;

    @OrderBy(order = Order.DESC, orderPriority = 1)
    private Integer age;

    private String email;

    @Transient
    private String test;
}

基于以上兩個(gè)原理,當(dāng)方法被調(diào)用時(shí),我們便可構(gòu)建出相應(yīng)的動(dòng)態(tài)Sql,從而實(shí)現(xiàn)該通用Mapper。

四、代碼實(shí)現(xiàn)

1、自定義注解

1)@Table

了解Jpa的朋友一定很熟悉,這個(gè)就是為實(shí)體指定表名,實(shí)體不加這個(gè)注解就認(rèn)為實(shí)體名與表名一致:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
    //表名,不指定則使用實(shí)體類名
    String value() default "";
}

2)@Column

指定完表名,該指定列名了,同樣的如果字段不指定則認(rèn)為字段名與表列名一致:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
    //對(duì)應(yīng)數(shù)據(jù)庫列名
    String value() default "";
    //查詢時(shí)的過濾類型
    FilterOperator filterOperator() default FilterOperator.EQ;
    //是否查詢,select是否帶上該字段
    boolean selectable() default true;
    //是否插入,insert是否帶上該字段
    boolean insertable() default true;
    //是否更新,update是否帶上該字段
    boolean updatable() default true;
}

3)@Id

這個(gè)注解就是為了表明該字段是否是數(shù)據(jù)庫主鍵。當(dāng)然,這個(gè)注解可以與@Column合并,但為了更清晰,我還是決定單獨(dú)使用這個(gè)注解。并且,也方便后期擴(kuò)展。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Id {
    //主鍵是否自動(dòng)生成
    boolean auto() default false;
}

4)@OrderBy

這個(gè)注解來標(biāo)明查詢時(shí)的排序字段,同時(shí)考慮如果排序字段有多個(gè),可定義優(yōu)先級(jí):

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface OrderBy {
    //排序
    Order order() default Order.ASC;
    //多個(gè)排序字段先后順序
    int orderPriority() default 0;
}

5)@Transient

考慮實(shí)體中有些字段在數(shù)據(jù)庫中不存在的情況。使用這個(gè)注解來標(biāo)注這樣的字段:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Transient {
}

2、幾個(gè)pojo,用來保存實(shí)體對(duì)應(yīng)的信息

1)TableInfo,表示一個(gè)實(shí)體對(duì)應(yīng)的數(shù)據(jù)庫表信息

public class TableInfo {
    //表對(duì)應(yīng)的實(shí)體類型
    private Class<?> entityClass;

    //表名
    private String tableName;

    //列
    private List<ColumnInfo> columns;

    //是否聯(lián)合主鍵
    private boolean isUnionId;
}

2)ColumnInfo,表示實(shí)體中的一個(gè)字段對(duì)應(yīng)的數(shù)據(jù)庫表字段信息

public class ColumnInfo {
    //對(duì)應(yīng)的java類型
    private Class<?> fieldClass;
    private Field field;
    private FilterOperator filterOperator;
    //數(shù)據(jù)庫列
    private String column;
    //是否主鍵
    private boolean isPrimaryKey;
    //主鍵填充方式
    private boolean isPrimaryKeyAuto;
    //排序
    private Order orderBy;
    private int orderByPriority;
    //是否參與insert
    private boolean insertable;
    //是否參與update
    private boolean updatable;
    //是否參與select
    private boolean selectable;
}

以上只需要注意一點(diǎn),如何判斷一個(gè)實(shí)體是否是聯(lián)合主鍵。這里用的比較粗暴的方法,如果有多個(gè)字段加了@Id,那么認(rèn)為是聯(lián)合主鍵。

3、定義開頭說的BaseMapper

這個(gè)BaseMapper的定義模仿了SpringDataJpa,它需要兩個(gè)泛型,T表示實(shí)體類型,K表示主鍵類型。

一般情況下K為簡(jiǎn)單數(shù)據(jù)類型,比如Long,String;

聯(lián)合主鍵情況下,K為自定義的一個(gè)復(fù)雜數(shù)據(jù)類型,具體使用方法見文章最后章節(jié)。

public interface BaseMapper<T,K> {

    @InsertProvider(type = SqlProvider.class,method = "insert")
    @Options(useGeneratedKeys = true, keyProperty = "id",keyColumn = "id")
    int insert(T t);

    @InsertProvider(type = SqlProvider.class,method = "batchInsert")
    int batchInsert(@Param("list") List<T> entity);

    @DeleteProvider(type = SqlProvider.class,method = "deleteById")
    int deleteById(@Param("id") K id);

    @DeleteProvider(type = SqlProvider.class,method = "deleteBatchIds")
    int deleteBatchIds(@Param("ids") Collection<K> ids);

    @UpdateProvider(type = SqlProvider.class,method = "updateById")
    int updateById(T entity);

    @UpdateProvider(type = SqlProvider.class,method = "updateSelectiveById")
    int updateSelectiveById(T entity);

    @SelectProvider(type = SqlProvider.class,method = "selectById")
    T selectById(@Param("id") K id);

    @SelectProvider(type = SqlProvider.class,method = "selectBatchIds")
    List<T> selectBatchIds(@Param("ids") Collection<K> ids);

    @SelectProvider(type = SqlProvider.class,method = "selectAll")
    List<T> selectAll();

    @SelectProvider(type = SqlProvider.class,method = "selectPage")
    List<T> selectPage(PageRequest<T> pageRequest);

    @SelectProvider(type = SqlProvider.class,method = "selectCount")
    Long selectCount(T entity);

}

4、SqlProvider

public class SqlProvider<T> {
    private static Logger logger = LoggerFactory.getLogger(SqlProvider.class);
    private static Map<Class<?>, TableInfo> tableCache = new ConcurrentHashMap<>();

    public String insert(T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        String intoColumns = tableInfo.getColumns()
                .stream()
                .filter(ColumnInfo::isInsertable)
                .map(ColumnInfo::getColumn)
                .collect(Collectors.joining(","));
        String values = tableInfo.getColumns()
                .stream()
                .filter(ColumnInfo::isInsertable)
                .map(ColumnInfo::variable)
                .collect(Collectors.joining(","));
        String sql = new SQL()
                .INSERT_INTO(tableName)
                .INTO_COLUMNS(intoColumns)
                .INTO_VALUES(values).toString();
        logger.info("sql->{},params->{}",sql,entity);
        return sql;
    }

    public String batchInsert(@Param("list" ) List<?> entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        String intoColumns = tableInfo.getColumns()
                .stream()
                .filter(ColumnInfo::isInsertable)
                .map(ColumnInfo::getColumn)
                .collect(Collectors.joining(","));
        String values = tableInfo.getColumns()
                .stream()
                .filter(ColumnInfo::isInsertable)
                .map(column->column.variableWithPrefix("item"))
                .collect(Collectors.joining(","));
        String sql = new SQL()
                .INSERT_INTO(tableName)
                .INTO_COLUMNS(intoColumns).toString();
        sql += " values ";
        sql += "<foreach collection=\"list\" item=\"item\" separator=\",\">" +
                "  <trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">" +
                "    " + values +
                "  </trim>" +
                "</foreach>";
        sql = "<script>"+sql+"</script>";
        logger.info("sql->{},params->{}",sql,entity);
        return sql;
    }

    public String deleteById(@Param("id") T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        String[] where = null;
        if (tableInfo.isUnionId()){
            where = tableInfo.getColumns()
                    .stream()
                    .filter(ColumnInfo::isPrimaryKey)
                    .map(columnInfo -> columnInfo.getColumn()+" = #{id."+columnInfo.getField().getName()+"}")
                    .toArray(String[]::new);
        }else {
            where = tableInfo.getColumns()
                    .stream()
                    .filter(ColumnInfo::isPrimaryKey)
                    .map(columnInfo -> columnInfo.getColumn()+" = #{id}")
                    .toArray(String[]::new);
        }
        String sql = new SQL()
                .DELETE_FROM(tableName)
                .WHERE(where)
                .toString();
        logger.info("sql->{},params->{}",sql,entity);
        return sql;
    }

    public String deleteBatchIds(@Param("ids") Collection<?> entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        if (tableInfo.isUnionId()){
            String[] where = new String[entity.size()];
            for (int i = 0; i < entity.size(); i++){
                List<String> list = new ArrayList<>();
                String s = "%s=#{ids[%d].%s}";
                for (ColumnInfo columnInfo:tableInfo.getColumns()){
                    if (columnInfo.isPrimaryKey()){
                        list.add(String.format(s,columnInfo.getColumn(),i,columnInfo.getField().getName()));
                    }
                }
                where[i] = "("+StringUtils.join(list," and ")+")";
            }
            String sql = "delete from %s where %s ";
            sql = String.format(sql,tableName,StringUtils.join(where," or "));
            logger.info("sql->{},params->{}",sql,entity);
            return sql;
        }else {
            String idName = tableInfo.getColumns()
                    .stream()
                    .filter(ColumnInfo::isPrimaryKey)
                    .findFirst()
                    .get()
                    .getColumn();
            String sql = "DELETE FROM %s WHERE %s IN (%s) ";
            String[] arr = new String[entity.size()];
            for (int i = 0; i < entity.size(); i++){
                arr[i] = "#{ids["+i+"]}";
            }
            sql = String.format(sql,tableName,idName,StringUtils.join(arr,","));
            logger.info("sql->{},params->{}",sql,entity);
            return sql;
        }
    }

    public String updateById(T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        String[] where = tableInfo.getColumns()
                .stream()
                .filter(ColumnInfo::isPrimaryKey)
                .map(columnInfo -> columnInfo.getColumn()+" = "+columnInfo.variable())
                .toArray(String[]::new);
        String sql = new SQL().UPDATE(tableName).SET(tableInfo.updateSetColumn()).WHERE(where).toString();
        logger.info("sql->{},params->{}",sql,entity);
        return sql;
    }

    public String updateSelectiveById(T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        String[] where = tableInfo.getColumns()
                .stream()
                .filter(ColumnInfo::isPrimaryKey)
                .map(columnInfo -> columnInfo.getColumn()+" = "+columnInfo.variable())
                .toArray(String[]::new);
        String sql = new SQL().UPDATE(tableName).SET(tableInfo.updateSetSelectiveColumn(entity)).WHERE(where).toString();
        logger.info("sql->{},params->{}",sql,entity);
        return sql;
    }

    public String selectById(@Param("id")T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String[] where = null;
        if (tableInfo.isUnionId()){
            where = tableInfo.getColumns().stream().filter(ColumnInfo::isPrimaryKey)
                    .map(columnInfo -> columnInfo.getColumn()+" = #{id."+columnInfo.getField().getName()+"}")
                    .toArray(String[]::new);
        }else {
            where = tableInfo.getColumns().stream().filter(ColumnInfo::isPrimaryKey)
                    .map(columnInfo -> columnInfo.getColumn()+" = #{id}")
                    .toArray(String[]::new);
        }
        String sql = new SQL()
                .SELECT(tableInfo.selectColumnAsProperty())
                .FROM(tableInfo.getTableName())
                .WHERE(where)
                .toString();
        logger.info("sql->{},params->{}",sql,entity);
        return sql;
    }

    public String selectBatchIds(@Param("ids")Collection<?> entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        String tableName = tableInfo.getTableName();
        if (tableInfo.isUnionId()){
            String[] where = new String[entity.size()];
            for (int i = 0; i < entity.size(); i++){
                List<String> list = new ArrayList<>();
                String s = "%s=#{ids[%d].%s}";
                for (ColumnInfo columnInfo:tableInfo.getColumns()){
                    if (columnInfo.isPrimaryKey()){
                        list.add(String.format(s,columnInfo.getColumn(),i,columnInfo.getField().getName()));
                    }
                }
                where[i] = "("+StringUtils.join(list," and ")+")";
            }
            String sql = "select %s from %s where %s";
            sql = String.format(sql,tableInfo.selectColumnAsProperty(),tableInfo.getTableName(),StringUtils.join(where," or "));
            logger.info("sql->{},params->{}",sql,entity);
            return sql;
        }else {
            String idName = tableInfo.getColumns()
                    .stream()
                    .filter(ColumnInfo::isPrimaryKey)
                    .findFirst()
                    .get()
                    .getColumn();
            String sql = "select %s from %s where %s in (%s) ";
            String[] arr = new String[entity.size()];
            for (int i = 0; i < entity.size(); i++){
                arr[i] = "#{ids["+i+"]}";
            }
            sql = String.format(sql,tableInfo.selectColumnAsProperty(),tableName,idName,StringUtils.join(arr,","));
            logger.info("sql->{},params->{}",sql,entity);
            return sql;
        }
    }

    public String selectAll(T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        SQL sql =  new SQL()
                .SELECT(tableInfo.selectColumnAsProperty())
                .FROM(tableInfo.getTableName());
        String orderBy = tableInfo.orderByColumn();
        if (StringUtils.isNotEmpty(orderBy)){
            sql.ORDER_BY(orderBy);
        }
        return sql.toString();
    }

    public String selectPage(PageRequest<T> entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        SQL sql = new SQL()
                .SELECT(tableInfo.selectColumnAsProperty())
                .FROM(tableInfo.getTableName());
        String[] where = tableInfo.getColumns().stream()
                .filter(column -> {
                    Field field = column.getField();
                    T bean = entity.getPageParams();
                    Object value = Util.getFieldValue(bean, field);
                    if (value == null) {
                        return false;
                    }
                    return StringUtils.isNotEmpty(value.toString());
                })
                .map(column -> {
                    String param = " #{pageParams." + column.getField().getName()+"}";
                    if (column.getFilterOperator() == FilterOperator.LIKE){
                        param = "concat('%', "+param+", '%')";
                    }
                    if (column.getFilterOperator() == FilterOperator.LEFTLIKE){
                        param = "concat("+param+", '%')";
                    }
                    if (column.getFilterOperator() == FilterOperator.RIGHTLIKE){
                        param = "concat('%', "+param+")";
                    }
                    return column.getColumn()+column.filterOperator()+param;
                })
                .toArray(String[]::new);
        sql.WHERE(where);
        if (StringUtils.isNotEmpty(entity.getOrder())){
            ColumnInfo columnInfo = tableInfo.getColumns().stream()
                    .filter(columnInfo1 -> columnInfo1.getField().getName().equalsIgnoreCase(entity.getOrder()))
                    .findFirst().orElse(null);
            if (columnInfo != null){
                String direction = entity.getOrderDirection();
                direction = (StringUtils.isEmpty(direction) || direction.equalsIgnoreCase("asc"))?" asc ":" desc ";
                sql.ORDER_BY(columnInfo.getColumn() + direction);
            }
        }else {
            String orderBy = tableInfo.orderByColumn();
            if (StringUtils.isNotEmpty(orderBy)){
                sql.ORDER_BY(orderBy);
            }
        }
        sql.OFFSET("#{offset}").LIMIT("#{pageSize}");
        String s = sql.toString();
        logger.info("sql->{},params->{}",s,entity);
        return s;
    }

    public String selectCount(T entity, ProviderContext context){
        TableInfo tableInfo = getTableInfo(context);
        SQL sql = new SQL()
                .SELECT("count(1)")
                .FROM(tableInfo.getTableName());
        String[] where = tableInfo.getColumns().stream()
                .filter(column -> {
                    Field field = column.getField();
                    Object value = Util.getFieldValue(entity, field);
                    if (value == null) {
                        return false;
                    }
                    return StringUtils.isNotEmpty(value.toString());
                })
                .map(column -> {
                    String param = " #{" + column.getField().getName()+"}";
                    if (column.getFilterOperator() == FilterOperator.LIKE){
                        param = "concat('%', "+param+", '%')";
                    }
                    if (column.getFilterOperator() == FilterOperator.LEFTLIKE){
                        param = "concat("+param+", '%')";
                    }
                    if (column.getFilterOperator() == FilterOperator.RIGHTLIKE){
                        param = "concat('%', "+param+")";
                    }
                    return column.getColumn()+column.filterOperator()+param;
                })
                .toArray(String[]::new);
        sql.WHERE(where);
        String s = sql.toString();
        logger.info("sql->{},params->{}",s,entity);
        return s;
    }

    private TableInfo getTableInfo(ProviderContext context){
        Class<?> clz = getEntityType(context);
        return tableCache.computeIfAbsent(context.getMapperType(), t-> Util.tableInfo(clz));
    }

    private Class<?> getEntityType(ProviderContext context) {
        return Stream.of(context.getMapperType().getGenericInterfaces())
                .filter(ParameterizedType.class::isInstance)
                .map(ParameterizedType.class::cast)
                .filter(type -> type.getRawType() == BaseMapper.class)
                .findFirst()
                .map(type -> type.getActualTypeArguments()[0])
                .filter(Class.class::isInstance)
                .map(Class.class::cast)
                .orElseThrow(() -> new IllegalStateException("未找到BaseMapper的泛型類 " + context.getMapperType().getName() + "."));
    }


}

5、實(shí)體類轉(zhuǎn)TableInfo

public static TableInfo tableInfo(Class<?> entityClass) {
        TableInfo info = new TableInfo();
        info.setEntityClass(entityClass);
        Table table = entityClass.getAnnotation(Table.class);
        String tableName = entityClass.getSimpleName();
        if (table != null && StringUtils.isNotEmpty(table.value())){
            tableName = table.value();
        }
        info.setTableName(tableName);
        Field[] allFields = getFields(entityClass);
        Field[] fields = Stream.of(allFields)
                //過濾@Transient注解的field
                .filter(field -> !field.isAnnotationPresent(Transient.class))
                .toArray(Field[]::new);
        List<ColumnInfo> columns = new ArrayList<>();
        int idCount = 0;
        for (Field field:fields){
            ColumnInfo columnInfo = new ColumnInfo();
            columnInfo.setFieldClass(field.getDeclaringClass());
            columnInfo.setField(field);
            Id id = field.getAnnotation(Id.class);
            idCount = idCount + (id == null?0:1);
            columnInfo.setPrimaryKey(id == null?Boolean.FALSE:Boolean.TRUE);
            columnInfo.setPrimaryKeyAuto(id == null?Boolean.FALSE:id.auto());
            Column column = field.getAnnotation(Column.class);
            String columnName = field.getName();
            if (column != null && StringUtils.isNotEmpty(column.value())){
                columnName = column.value();
            }
            columnInfo.setColumn(columnName);
            FilterOperator filterOperator = FilterOperator.EQ;
            if (column != null && column.filterOperator() != null){
                filterOperator = column.filterOperator();
            }
            columnInfo.setFilterOperator(filterOperator);

            if (columnInfo.isPrimaryKeyAuto()){
                columnInfo.setInsertable(false);
            }else {
                columnInfo.setInsertable(true);
                if (column != null){
                    columnInfo.setInsertable(column.insertable());
                }
            }
            columnInfo.setUpdatable(true);
            columnInfo.setSelectable(true);
            if (column != null){
                columnInfo.setSelectable(column.selectable());
                columnInfo.setUpdatable(column.updatable());
            }
            OrderBy orderBy = field.getAnnotation(OrderBy.class);
            if (orderBy != null){
                columnInfo.setOrderBy(orderBy.order());
                columnInfo.setOrderByPriority(orderBy.orderPriority());
            }
            columns.add(columnInfo);
        }
        if (idCount > 1){
            info.setUnionId(Boolean.TRUE);
        }
        info.setColumns(columns);
        return info;
    }

6、字典字段自動(dòng)翻譯

簡(jiǎn)單實(shí)現(xiàn)思路:對(duì)需要翻譯的字段加上@FieldTrans注解來表明這個(gè)字段需要翻譯,通過AOP方式對(duì)結(jié)果數(shù)據(jù)進(jìn)行增強(qiáng),來將字段進(jìn)行翻譯更新。

此部分內(nèi)容留待后續(xù)實(shí)現(xiàn),同時(shí)調(diào)研一下是否還有更優(yōu)雅簡(jiǎn)單的實(shí)現(xiàn)方式。

7、數(shù)據(jù)權(quán)限

我們先來思考一下數(shù)據(jù)權(quán)限到底要干啥?一句話來概括:查一張表的數(shù)據(jù)時(shí)在where條件中追加“and 控制權(quán)限的列 in (???)”。

簡(jiǎn)單實(shí)現(xiàn)方法:在控制權(quán)限的字段加上@DataAuthrity注解來表明通過這個(gè)字段控制權(quán)限,而???的內(nèi)容肯定是由業(yè)務(wù)代碼來生成的,因此考慮給這個(gè)注解增加一個(gè)屬性,用來指明權(quán)限數(shù)據(jù)由執(zhí)行哪個(gè)接口或方法來獲取。

此部分內(nèi)容留待后續(xù)實(shí)現(xiàn),同時(shí)調(diào)研一下是否還有更優(yōu)雅簡(jiǎn)單的實(shí)現(xiàn)方式。

五、使用示例

1、數(shù)據(jù)庫表

CREATE TABLE `user` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `email` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

2、實(shí)體

@Table("user")
public class User {
    @Id(auto = true)
    @Column(value = "id")
    private Long id;

    @Column(value = "name", filterOperator = FilterOperator.LIKE)
    @OrderBy(orderPriority = 0)
    private String name;

    @OrderBy(order = Order.DESC, orderPriority = 1)
    private Integer age;

    private String email;

    @Transient
    private String test;
}

3、Mapper

public interface UserMapper extends BaseMapper<User, Long> {

}

至此,不需要寫任何mapper.xml,UserMapper已經(jīng)具備了增刪改查能力。

4、聯(lián)合主鍵示例

public class User1 {
    @Id
    @Column(value = "id1")
    private String id1;
    
    @Id
    @Column(value = "id2")
    private String id2;
    
    @Column(value = "name", filterOperator = FilterOperator.LIKE)
    @OrderBy(orderPriority = 0)
    private String name;
    
    @OrderBy(order = Order.DESC, orderPriority = 1)
    private Integer age;
    
    private String email;
    
    @Transient
    private String test;
}


public class User1Id {
    private String id1;
    private String id2;
}


public interface User1Mapper extends BaseMapper<User1,User1Id> {
}

六、總結(jié)

本輪子目前基本上不值一提,但相信后面我再把字典翻譯、通用數(shù)據(jù)權(quán)限加上的話,仍然會(huì)不值一提。

實(shí)際上輪子本身不重要,開發(fā)過程中的各種思考、試驗(yàn)更重要吧。

以上就是詳解如何開發(fā)一個(gè)MyBatis通用Mapper的輪子的詳細(xì)內(nèi)容,更多關(guān)于MyBatis通用Mapper輪子的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Spring Boot示例分析講解自動(dòng)化裝配機(jī)制核心注解

    Spring Boot示例分析講解自動(dòng)化裝配機(jī)制核心注解

    這篇文章主要分析了Spring Boot 自動(dòng)化裝配機(jī)制核心注解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-07-07
  • JAVA設(shè)計(jì)模式之解釋器模式詳解

    JAVA設(shè)計(jì)模式之解釋器模式詳解

    這篇文章主要介紹了JAVA設(shè)計(jì)模式之解釋器模式詳解,解釋器模式是類的行為模式,給定一個(gè)語言之后,解釋器模式可以定義出其文法的一種表示,并同時(shí)提供一個(gè)解釋器,需要的朋友可以參考下
    2015-04-04
  • Spring?MVC文件請(qǐng)求處理MultipartResolver詳解

    Spring?MVC文件請(qǐng)求處理MultipartResolver詳解

    這篇文章主要介紹了Spring?MVC文件請(qǐng)求處理詳解:MultipartResolver,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-11-11
  • Java匿名內(nèi)部類的寫法示例

    Java匿名內(nèi)部類的寫法示例

    這篇文章主要給大家介紹了關(guān)于Java匿名內(nèi)部類的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • Spring Cloud Config工作原理概述

    Spring Cloud Config工作原理概述

    Spring Cloud Config 是 Spring Cloud 生態(tài)系統(tǒng)的一部分,它提供了一種集中化管理應(yīng)用配置的方法,本文給大家介紹Spring Cloud Config工作原理概述,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • IDEA的Terminal無法執(zhí)行g(shù)it命令問題

    IDEA的Terminal無法執(zhí)行g(shù)it命令問題

    這篇文章主要介紹了IDEA的Terminal無法執(zhí)行g(shù)it命令問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09
  • Java 獲取Html文本中的img標(biāo)簽下src中的內(nèi)容方法

    Java 獲取Html文本中的img標(biāo)簽下src中的內(nèi)容方法

    今天小編就為大家分享一篇Java 獲取Html文本中的img標(biāo)簽下src中的內(nèi)容方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06
  • Java中的抽象工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java中的抽象工廠模式_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    抽象工廠模式是工廠方法模式的升級(jí)版本,他用來創(chuàng)建一組相關(guān)或者相互依賴的對(duì)象。下面通過本文給大家分享Java中的抽象工廠模式,感興趣的朋友一起看看吧
    2017-08-08
  • springboot新建項(xiàng)目pom.xml文件第一行報(bào)錯(cuò)的解決

    springboot新建項(xiàng)目pom.xml文件第一行報(bào)錯(cuò)的解決

    這篇文章主要介紹了springboot新建項(xiàng)目pom.xml文件第一行報(bào)錯(cuò)的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • java 回調(diào)機(jī)制的實(shí)例詳解

    java 回調(diào)機(jī)制的實(shí)例詳解

    這篇文章主要介紹了java 回調(diào)機(jī)制的實(shí)例詳解的相關(guān)資料,希望通過本文的示例能幫助到大家理解使用回調(diào)機(jī)制,需要的朋友可以參考下
    2017-09-09

最新評(píng)論