30个类手写Spring核心原理之自定义ORM(上)(6)

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 说到ResultSet,有Java开发经验的“小伙伴”自然最熟悉不过了,不过我相信对于大多数人来说也算是“最熟悉的陌生人”。从ResultSet取值操作大家都会,比如:

本文节选自《Spring 5核心原理》

1 实现思路概述

1.1 从ResultSet说起

说到ResultSet,有Java开发经验的“小伙伴”自然最熟悉不过了,不过我相信对于大多数人来说也算是“最熟悉的陌生人”。从ResultSet取值操作大家都会,比如:

private static List<Member> select(String sql) {
    List<Member> result = new ArrayList<>();
    Connection con = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    try {
        //1. 加载驱动类
        Class.forName("com.mysql.jdbc.Driver");
        //2. 建立连接
        con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo", "root","123456");
        //3. 创建语句集
        pstm =  con.prepareStatement(sql);
        //4. 执行语句集
        rs = pstm.executeQuery();
        while (rs.next()){
            Member instance = new Member();
            instance.setId(rs.getLong("id"));
            instance.setName(rs.getString("name"));
            instance.setAge(rs.getInt("age"));
            instance.setAddr(rs.getString("addr"));
            result.add(instance);
        }
        //5. 获取结果集
    }catch (Exception e){
        e.printStackTrace();
    }
    //6. 关闭结果集、关闭语句集、关闭连接
    finally {
        try {
            rs.close();
            pstm.close();
            con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    return result;
}

以上我们在没有使用框架以前的常规操作。随着业务和开发量的增加,在数据持久层这样的重复代码出现频次非常高。因此,我们就想到将非功能性代码和业务代码进行分离。我们首先想到将ResultSet封装数据的代码逻辑分离,增加一个mapperRow()方法,专门处理对结果的封装,代码如下:

private static List<Member> select(String sql) {
    List<Member> result = new ArrayList<>();
    Connection con = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    try {
        //1. 加载驱动类
        Class.forName("com.mysql.jdbc.Driver");
        //2. 建立连接
        con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo", "root","123456");
        //3. 创建语句集
        pstm =  con.prepareStatement(sql);
        //4. 执行语句集
        rs = pstm.executeQuery();
        while (rs.next()){
            Member instance = mapperRow(rs,rs.getRow());
            result.add(instance);
        }
        //5. 获取结果集
    }catch (Exception e){
        e.printStackTrace();
    }
    //6. 关闭结果集、关闭语句集、关闭连接
    finally {
        try {
            rs.close();
            pstm.close();
            con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    return result;
}
private static Member mapperRow(ResultSet rs, int i) throws Exception {
    Member instance = new Member();
    instance.setId(rs.getLong("id"));
    instance.setName(rs.getString("name"));
    instance.setAge(rs.getInt("age"));
    instance.setAddr(rs.getString("addr"));
    return instance;
}

但在真实的业务场景中,这样的代码逻辑重复率实在太高,上面的改造只能应用Member类,换一个实体类又要重新封装,聪明的程序员肯定不会通过纯体力劳动给每一个实体类写一个mapperRow()方法,一定会想到代码复用方案。我们不妨来做这样一个改造。

先创建Member类:

package com.gupaoedu.vip.orm.demo.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
@Entity
@Table(name="t_member")
@Data
public class Member implements Serializable {
    @Id private Long id;
    private String name;
    private String addr;
    private Integer age;
    @Override
    public String toString() {
        return "Member{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", addr='" + addr + '\'' +
                ", age=" + age +
                '}';
    }
}

优化JDBC操作:

public static void main(String[] args) {
    Member condition = new Member();
    condition.setName("Tom");
    condition.setAge(19);
    List<?> result =  select(condition);
    System.out.println(Arrays.toString(result.toArray()));
}
private static List<?> select(Object condition) {
    List<Object> result = new ArrayList<>();
    Class<?> entityClass = condition.getClass();
    Connection con = null;
    PreparedStatement pstm = null;
    ResultSet rs = null;
    try {
        //1. 加载驱动类
        Class.forName("com.mysql.jdbc.Driver");
        //2. 建立连接
        con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/gp-vip-spring-db-demo? characterEncoding=UTF-8&rewriteBatchedStatements=true","root","123456");
        //根据类名找属性名
        Map<String,String> columnMapper = new HashMap<String,String>();
        //根据属性名找字段名
        Map<String,String> fieldMapper = new HashMap<String,String>();
        Field[] fields =  entityClass.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            String fieldName = field.getName();
            if(field.isAnnotationPresent(Column.class)){
                Column column = field.getAnnotation(Column.class);
                String columnName = column.name();
                columnMapper.put(columnName,fieldName);
                fieldMapper.put(fieldName,columnName);
            }else {
                //默认就是字段名、属性名一致
                columnMapper.put(fieldName, fieldName);
                fieldMapper.put(fieldName,fieldName);
            }
        }
        //3. 创建语句集
        Table table = entityClass.getAnnotation(Table.class);
        String sql = "select * from " + table.name();
        StringBuffer where = new StringBuffer(" where 1=1 ");
        for (Field field : fields) {
            Object value =field.get(condition);
            if(null != value){
                if(String.class == field.getType()) {
                    where.append(" and " + fieldMapper.get(field.getName()) + " = '" + value + "'");
                }else{
                    where.append(" and " + fieldMapper.get(field.getName()) + " = " + value + "");
                }
                //其他的在这里就不一一列举,后面我们手写ORM框架时会完善
            }
        }
        System.out.println(sql + where.toString());
        pstm =  con.prepareStatement(sql + where.toString());
        //4. 执行语句集
        rs = pstm.executeQuery();
        //元数据?
        //保存了处理真正数值以外的所有附加信息
        int columnCounts = rs.getMetaData().getColumnCount();
        while (rs.next()){
            Object instance = entityClass.newInstance();
            for (int i = 1; i <= columnCounts; i++) {
                //实体类属性名,对应数据库表的字段名
                //可以通过反射机制拿到实体类的所有字段
                //从rs中取得当前这个游标下的类名
                String columnName = rs.getMetaData().getColumnName(i);
                //有可能是私有的
                Field field = entityClass.getDeclaredField(columnMapper.get(columnName));
                field.setAccessible(true);
                field.set(instance,rs.getObject(columnName));
            }
            result.add(instance);
        }
        //5. 获取结果集
    }catch (Exception e){
        e.printStackTrace();
    }
    //6. 关闭结果集、关闭语句集、关闭连接
    finally {
        try {
            rs.close();
            pstm.close();
            con.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
    return result;
}

上面巧妙地利用反射机制读取Class信息和Annotation信息,将数据库表中的列和类中的字段进行关联映射并赋值,以减少重复代码。

1.2 为什么需要ORM框架

通过前面的讲解,我们已经了解ORM框架的基本实现原理。ORM是指对象关系映射(Object Relation Mapping),映射的不只是对象值,还有对象与对象之间的关系,例如一对多、多对多、一对一这样的表关系。现在市面上ORM框架也非常多,有大家所熟知的Hibernate、Spring JDBC、MyBatis、JPA等。在这里做一个简单的总结,如下表所示。

名称 特征 描述
Hibernate 全自动(挡) 不需要写一句SQL
MyBatis 半自动(挡) 手自一体,支持简单的映射,复杂关系需要自己写SQL
Spring JDBC 纯手动(挡) 所有的SQL都要自己写,它帮我们设计了一套标准流程

既然市面上有这么多选择,我为什么还要自己写 ORM框架呢?

这得从我的一次空降担任架构师的经验说起。空降面临最大的难题就是如何取得团队“小伙伴们”的信任。当时,团队总共就8人,每个人的水平参差不齐,甚至有些人还没接触过MySQL,诸如Redis等缓存中间件更不用说了。基本只会使用Hibernate的CRUD,而且已经影响到了系统性能。由于工期紧张,没有时间和精力给团队做系统培训,也为了兼顾可控性,于是就产生了自研ORM框架的想法。我做了这样的顶层设计,以降低团队“小伙伴们”的存息成本,顶层接口统一参数、统一返回值,具体如下。

**(1)规定查询方法的接口模型为: **

/**
 * 获取列表
 * @param queryRule 查询条件
 * @return
 */
List<T> select(QueryRule queryRule) throws Exception;
/**
 * 获取分页结果
 * @param queryRule 查询条件
 * @param pageNo 页码
 * @param pageSize 每页条数
 * @return
 */
Page<?> select(QueryRule queryRule,int pageNo,int pageSize) throws Exception;
/**
 * 根据SQL获取列表
 * @param sql SQL语句
 * @param args 参数
 * @return
 */
List<Map<String,Object>> selectBySql(String sql, Object... args) throws Exception;
/**
 * 根据SQL获取分页
 * @param sql SQL语句
 * @param pageNo 页码
 * @param pageSize 每页条数
 * @return
 */
Page<Map<String,Object>> selectBySqlToPage(String sql, Object [] param, int pageNo, int pageSize) throws Exception;

(2)规定删除方法的接口模型为:

/**
 * 删除一条记录
 * @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空不予执行
 * @return
 */
boolean delete(T entity) throws Exception;
/**
 * 批量删除
 * @param list
 * @return 返回受影响的行数
 * @throws Exception
 */
int deleteAll(List<T> list) throws Exception;

(3)规定插入方法的接口模型为:

/**
 * 插入一条记录并返回插入后的ID
 * @param entity 只要entity不等于null,就执行插入
 * @return
 */
PK insertAndReturnId(T entity) throws Exception;
/**
 * 插入一条记录自增ID
 * @param entity
 * @return
 * @throws Exception
 */
boolean insert(T entity) throws Exception;
/**
 * 批量插入
 * @param list
 * @return 返回受影响的行数
 * @throws Exception
 */
int insertAll(List<T> list) throws Exception;

(4)规定修改方法的接口模型为:

/**
 *  修改一条记录
 * @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空不予执行
 * @return
 * @throws Exception
 */
boolean update(T entity) throws Exception;

利用这套基础的API,后面我又基于Redis、MongoDB、ElasticSearch、Hive、HBase各封装了一套,以此来降低团队的学习成本,也大大提升了程序的可控性,更方便统一监控。

2 搭建基础架构

2.1 Page

定义Page类的主要目的是为后面的分页查询统一返回结果做顶层支持,其主要功能包括分页逻辑的封装、分页数据。

package javax.core.common;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
 * 分页对象,包含当前页数据及分页信息,如总记录数
 * 能够支持和JQuery EasyUI直接对接,能够支持和BootStrap Table直接对接
 */
public class Page<T> implements Serializable {
   private static final long serialVersionUID = 1L;
   private static final int DEFAULT_PAGE_SIZE = 20;
   private int pageSize = DEFAULT_PAGE_SIZE; //每页的记录数
   private long start; //当前页第一条数据在List中的位置,从0开始
   private List<T> rows; //当前页中存放的记录,类型一般为List
   private long total; //总记录数
   /**
    * 构造方法,只构造空页
    */
   public Page() {
      this(0, 0, DEFAULT_PAGE_SIZE, new ArrayList<T>());
   }
   /**
    * 默认构造方法
    * 
    * @param start 本页数据在数据库中的起始位置
    * @param totalSize 数据库中总记录条数
    * @param pageSize 本页容量
    * @param rows 本页包含的数据
    */
   public Page(long start, long totalSize, int pageSize, List<T> rows) {
      this.pageSize = pageSize;
      this.start = start;
      this.total = totalSize;
      this.rows = rows;
   }
   /**
    * 取总记录数
    */
   public long getTotal() {
      return this.total;
   }
   public void setTotal(long total) {
      this.total = total;
   }
   /**
    * 取总页数
    */
   public long getTotalPageCount() {
      if (total % pageSize == 0){
         return total / pageSize;
      }else{
         return total / pageSize + 1;
      }
   }
   /**
    * 取每页数据容量
    */
   public int getPageSize() {
      return pageSize;
   }
   /**
    * 取当前页中的记录
    */
   public List<T> getRows() {
      return rows;
   }
   public void setRows(List<T> rows) {
      this.rows = rows;
   }
   /**
    * 取该页的当前页码,页码从1开始
    */
   public long getPageNo() {
      return start / pageSize + 1;
   }
   /**
    * 该页是否有下一页
    */
   public boolean hasNextPage() {
      return this.getPageNo() < this.getTotalPageCount() - 1;
   }
   /**
    * 该页是否有上一页
    */
   public boolean hasPreviousPage() {
      return this.getPageNo() > 1;
   }
   /**
    * 获取任意一页第一条数据在数据集中的位置,每页条数使用默认值
    * 
    * @see #getStartOfPage(int,int)
    */
   protected static int getStartOfPage(int pageNo) {
      return getStartOfPage(pageNo, DEFAULT_PAGE_SIZE);
   }
   /**
    * 获取任意一页第一条数据在数据集中的位置
    * 
    * @param pageNo 从1开始的页号
    * @param pageSize 每页记录条数
    * @return 该页第一条数据
    */
   public static int getStartOfPage(int pageNo, int pageSize) {
      return (pageNo - 1) * pageSize;
   }
}

2.2 ResultMsg

ResultMsg类主要是为统一返回结果做的顶层设计,主要包括状态码、结果说明内容和返回数据。

package javax.core.common;
import java.io.Serializable;
//底层设计
public class ResultMsg<T> implements Serializable {
   private static final long serialVersionUID = 2635002588308355785L;
   private int status; //状态码,系统的返回码
   private String msg;  //状态码的解释
   private T data;  //放任意结果
   public ResultMsg() {}
   public ResultMsg(int status) {
      this.status = status;
   }
   public ResultMsg(int status, String msg) {
      this.status = status;
      this.msg = msg;
   }
   public ResultMsg(int status, T data) {
      this.status = status;
      this.data = data;
   }
   public ResultMsg(int status, String msg, T data) {
      this.status = status;
      this.msg = msg;
      this.data = data;
   }
   public int getStatus() {
      return status;
   }
   public void setStatus(int status) {
      this.status = status;
   }
   public String getMsg() {
      return msg;
   }
   public void setMsg(String msg) {
      this.msg = msg;
   }
   public T getData() {
      return data;
   }
   public void setData(T data) {
      this.data = data;
   }
}

2.3 BaseDao

作为所有BaseDao持久化框架的顶层接口,主要定义增、删、改、查统一的参数列表和返回值。

package javax.core.common.jdbc;
import com.gupaoedu.vip.orm.framework.QueryRule;
import javax.core.common.Page;
import java.util.List;
import java.util.Map;
public interface BaseDao<T,PK> {
    /**
     * 获取列表
     * @param queryRule 查询条件
     * @return
     */
    List<T> select(QueryRule queryRule) throws Exception;
    /**
     * 获取分页结果
     * @param queryRule 查询条件
     * @param pageNo 页码
     * @param pageSize 每页条数
     * @return
     */
    Page<?> select(QueryRule queryRule,int pageNo,int pageSize) throws Exception;
    /**
     * 根据SQL获取列表
     * @param sql SQL语句
     * @param args 参数
     * @return
     */
    List<Map<String,Object>> selectBySql(String sql, Object... args) throws Exception;
    /**
     * 根据SQL获取分页
     * @param sql SQL语句
     * @param pageNo 页码
     * @param pageSize 每页条数
     * @return
     */
    Page<Map<String,Object>> selectBySqlToPage(String sql, Object [] param, int pageNo, int pageSize) throws Exception;
    /**
     * 删除一条记录
     * @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空则不予执行
     * @return
     */
    boolean delete(T entity) throws Exception;
    /**
     * 批量删除
     * @param list
     * @return 返回受影响的行数
     * @throws Exception
     */
    int deleteAll(List<T> list) throws Exception;
    /**
     * 插入一条记录并返回插入后的ID
     * @param entity 只要entity不等于null,就执行插入操作
     * @return
     */
    PK insertAndReturnId(T entity) throws Exception;
    /**
     * 插入一条记录自增ID
     * @param entity
     * @return
     * @throws Exception
     */
    boolean insert(T entity) throws Exception;
    /**
     * 批量插入
     * @param list
     * @return 返回受影响的行数
     * @throws Exception
     */
    int insertAll(List<T> list) throws Exception;
    /**
     *  修改一条记录
     * @param entity entity中的ID不能为空,如果ID为空,其他条件不能为空,都为空则不予执行
     * @return
     * @throws Exception
     */
    boolean update(T entity) throws Exception;
}

2.4 QueryRule

如果用QueryRule类来构建查询条件,用户在做条件查询时不需要手写SQL,实现业务代码与SQL解耦。

package com.gupaoedu.vip.orm.framework;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
 * QueryRule,主要功能用于构造查询条件
 */
public final class QueryRule implements Serializable
{
   private static final long serialVersionUID = 1L;
   public static final int ASC_ORDER = 101;
   public static final int DESC_ORDER = 102;
   public static final int LIKE = 1;
   public static final int IN = 2;
   public static final int NOTIN = 3;
   public static final int BETWEEN = 4;
   public static final int EQ = 5;
   public static final int NOTEQ = 6;
   public static final int GT = 7;
   public static final int GE = 8;
   public static final int LT = 9;
   public static final int LE = 10;
   public static final int ISNULL = 11;
   public static final int ISNOTNULL = 12;
   public static final int ISEMPTY = 13;
   public static final int ISNOTEMPTY = 14;
   public static final int AND = 201;
   public static final int OR = 202;
   private List<Rule> ruleList = new ArrayList<Rule>();
   private List<QueryRule> queryRuleList = new ArrayList<QueryRule>();
   private String propertyName;
   private QueryRule() {}
   private QueryRule(String propertyName) {
      this.propertyName = propertyName;
   }
   public static QueryRule getInstance() {
      return new QueryRule();
   }
   /**
    * 添加升序规则
    * @param propertyName
    * @return
    */
   public QueryRule addAscOrder(String propertyName) {
      this.ruleList.add(new Rule(ASC_ORDER, propertyName));
      return this;
   }
   /**
    * 添加降序规则
    * @param propertyName
    * @return
    */
   public QueryRule addDescOrder(String propertyName) {
      this.ruleList.add(new Rule(DESC_ORDER, propertyName));
      return this;
   }
   public QueryRule andIsNull(String propertyName) {
      this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(AND));
      return this;
   }
   public QueryRule andIsNotNull(String propertyName) {
      this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(AND));
      return this;
   }
   public QueryRule andIsEmpty(String propertyName) {
      this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(AND));
      return this;
   }
   public QueryRule andIsNotEmpty(String propertyName) {
      this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(AND));
      return this;
   }
   public QueryRule andLike(String propertyName, Object value) {
      this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule andEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule andBetween(String propertyName, Object... values) {
      this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(AND));
      return this;
   }
   public QueryRule andIn(String propertyName, List<Object> values) {
      this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(AND));
      return this;
   }
   public QueryRule andIn(String propertyName, Object... values) {
      this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(AND));
      return this;
   }
   public QueryRule andNotIn(String propertyName, List<Object> values) {
      this.ruleList.add(new Rule(NOTIN, propertyName, new Object[] { values }).setAndOr(AND));
      return this;
   }
   public QueryRule orNotIn(String propertyName, Object... values) {
      this.ruleList.add(new Rule(NOTIN, propertyName, values).setAndOr(OR));
      return this;
   }
   public QueryRule andNotEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule andGreaterThan(String propertyName, Object value) {
      this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule andGreaterEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule andLessThan(String propertyName, Object value) {
      this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule andLessEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(AND));
      return this;
   }
   public QueryRule orIsNull(String propertyName) {
      this.ruleList.add(new Rule(ISNULL, propertyName).setAndOr(OR));
      return this;
   }
   public QueryRule orIsNotNull(String propertyName) {
      this.ruleList.add(new Rule(ISNOTNULL, propertyName).setAndOr(OR));
      return this;
   }
   public QueryRule orIsEmpty(String propertyName) {
      this.ruleList.add(new Rule(ISEMPTY, propertyName).setAndOr(OR));
      return this;
   }
   public QueryRule orIsNotEmpty(String propertyName) {
      this.ruleList.add(new Rule(ISNOTEMPTY, propertyName).setAndOr(OR));
      return this;
   }
   public QueryRule orLike(String propertyName, Object value) {
      this.ruleList.add(new Rule(LIKE, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public QueryRule orEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(EQ, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public QueryRule orBetween(String propertyName, Object... values) {
      this.ruleList.add(new Rule(BETWEEN, propertyName, values).setAndOr(OR));
      return this;
   }
   public QueryRule orIn(String propertyName, List<Object> values) {
      this.ruleList.add(new Rule(IN, propertyName, new Object[] { values }).setAndOr(OR));
      return this;
   }
   public QueryRule orIn(String propertyName, Object... values) {
      this.ruleList.add(new Rule(IN, propertyName, values).setAndOr(OR));
      return this;
   }
   public QueryRule orNotEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(NOTEQ, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public QueryRule orGreaterThan(String propertyName, Object value) {
      this.ruleList.add(new Rule(GT, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public QueryRule orGreaterEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(GE, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public QueryRule orLessThan(String propertyName, Object value) {
      this.ruleList.add(new Rule(LT, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public QueryRule orLessEqual(String propertyName, Object value) {
      this.ruleList.add(new Rule(LE, propertyName, new Object[] { value }).setAndOr(OR));
      return this;
   }
   public List<Rule> getRuleList() {
      return this.ruleList;
   }
   public List<QueryRule> getQueryRuleList() {
      return this.queryRuleList;
   }
   public String getPropertyName() {
      return this.propertyName;
   }
   protected class Rule implements Serializable {
      private static final long serialVersionUID = 1L;
      private int type;  //规则的类型
      private String property_name;
      private Object[] values;
      private int andOr = AND;
      public Rule(int paramInt, String paramString) {
         this.property_name = paramString;
         this.type = paramInt;
      }
      public Rule(int paramInt, String paramString,
            Object[] paramArrayOfObject) {
         this.property_name = paramString;
         this.values = paramArrayOfObject;
         this.type = paramInt;
      }
      public Rule setAndOr(int andOr){
         this.andOr = andOr;
         return this;
      }
      public int getAndOr(){
         return this.andOr;
      }
      public Object[] getValues() {
         return this.values;
      }
      public int getType() {
         return this.type;
      }
      public String getPropertyName() {
         return this.property_name;
      }
   }
}

2.5 Order

Order类主要用于封装排序规则,代码如下:

package com.gupaoedu.vip.orm.framework;
/**
 * SQL排序组件
 */
public class Order {
   private boolean ascending; //升序还是降序
   private String propertyName; //哪个字段升序,哪个字段降序
   public String toString() {
      return propertyName + ' ' + (ascending ? "asc" : "desc");
   }
   /**
    * Constructor for Order.
    */
   protected Order(String propertyName, boolean ascending) {
      this.propertyName = propertyName;
      this.ascending = ascending;
   }
   /**
    * Ascending order
    *
    * @param propertyName
    * @return Order
    */
   public static Order asc(String propertyName) {
      return new Order(propertyName, true);
   }
   /**
    * Descending order
    *
    * @param propertyName
    * @return Order
    */
   public static Order desc(String propertyName) {
      return new Order(propertyName, false);
   }
}

因篇幅原因,具体的操作类下一篇继续。

本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。

原创不易,坚持很酷,都看到这里了,小伙伴记得点赞、收藏、在看,一键三连加关注!如果你觉得内容太干,可以分享转发给朋友滋润滋润!

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3天前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
10 0
|
1月前
|
Java Spring 容器
Spring底层原理大致脉络
Spring底层原理大致脉络
|
1月前
|
Java Spring 容器
Spring IOC、AOP与事务管理底层原理及源码解析
【10月更文挑战第1天】Spring框架以其强大的控制反转(IOC)和面向切面编程(AOP)功能,成为Java企业级开发中的首选框架。本文将深入探讨Spring IOC和AOP的底层原理,并通过源码解析来揭示其实现机制。同时,我们还将探讨Spring事务管理的核心原理,并给出相应的源码示例。
126 9
|
1月前
|
XML 前端开发 Java
拼多多1面:聊聊Spring MVC的工作原理!
本文详细剖析了Spring MVC的工作原理,涵盖其架构、工作流程及核心组件。Spring MVC采用MVC设计模式,通过DispatcherServlet、HandlerMapping、Controller和ViewResolver等组件高效处理Web请求。文章还探讨了DispatcherServlet的初始化和请求处理流程,以及HandlerMapping和Controller的角色。通过理解这些核心概念,开发者能更好地构建可维护、可扩展的Web应用。适合面试准备和技术深挖
42 0
|
1月前
|
负载均衡 Java API
Spring Cloud原理详解
Spring Cloud原理详解
67 0
|
1月前
|
负载均衡 Java 网络架构
Spring Cloud原理详解
介绍了Spring Cloud的原理和核心组件,包括服务注册与发现、配置管理、负载均衡、断路器、智能路由、分布式消息传递、分布式追踪和服务熔断等,旨在帮助开发人员快速构建和管理微服务架构中的分布式系统。
52 0
|
3月前
|
缓存 Java 开发者
Spring高手之路22——AOP切面类的封装与解析
本篇文章深入解析了Spring AOP的工作机制,包括Advisor和TargetSource的构建与作用。通过详尽的源码分析和实际案例,帮助开发者全面理解AOP的核心技术,提升在实际项目中的应用能力。
45 0
Spring高手之路22——AOP切面类的封装与解析
|
3月前
|
监控 安全 Java
【开发者必备】Spring Boot中自定义注解与处理器的神奇魔力:一键解锁代码新高度!
【8月更文挑战第29天】本文介绍如何在Spring Boot中利用自定义注解与处理器增强应用功能。通过定义如`@CustomProcessor`注解并结合`BeanPostProcessor`实现特定逻辑处理,如业务逻辑封装、配置管理及元数据分析等,从而提升代码整洁度与可维护性。文章详细展示了从注解定义、处理器编写到实际应用的具体步骤,并提供了实战案例,帮助开发者更好地理解和运用这一强大特性,以实现代码的高效组织与优化。
170 0
|
SQL 关系型数据库 Java
【spring源码学习】spring集成orm数据框架
【一】简易的数据源配置 (1)配置文件 jdbc:mysql://localhost:3306/mobile_thinks root shangxiaofei ...
1143 0
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。