30 уроков написанных от руки основных принципов пользовательского ORM Spring (на) (6)

Java Spring

Эта статья взята из «Основных принципов Spring 5».

1 Обзор идей реализации

1.1 Начните с набора результатов

Когда дело доходит до 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;
}

Вышеприведенное умело использует механизм отражения для чтения информации о классе и информации об аннотациях, а также связывает и отображает столбцы в таблице базы данных с полями в классе, чтобы уменьшить повторяющийся код.

1.2 Зачем вам нужен ORM-фреймворк

Благодаря предыдущему объяснению мы поняли основной принцип реализации структуры ORM. ORM относится к отображению отношений объектов, которое отображает не только значения объектов, но и отношения между объектами, такие как отношения «один ко многим», «многие ко многим» и «один к одному». Сейчас на рынке существует множество ORM-фреймворков, таких как Hibernate, Spring JDBC, MyBatis, JPA и так далее. Здесь делается краткое резюме, как показано в таблице ниже.

имя характерная черта описывать
Hibernate Полностью автоматический (блок) Нет необходимости писать один SQL
MyBatis Полуавтомат (блок) Рука в одном, поддержка простого сопоставления, сложные отношения должны писать свой собственный SQL
Spring JDBC Чистый ручной (блок) Все SQL должны быть написаны нами самими, это помогает нам разработать стандартный процесс

Почему я должен писать свой собственный ORM-фреймворк, когда на рынке так много вариантов? Это должно начаться с моего опыта архитектора на парашюте. Самая большая проблема, стоящая перед ВДВ, — как завоевать доверие «друзей» команды. На тот момент в команде было всего 8 человек, и уровень у всех был разный, у некоторых даже не было опыта работы с MySQL, не говоря уже о кеширующем промежуточном программном обеспечении, таком как Redis. В основном используйте только CRUD Hibernate, и это повлияло на производительность системы. Из-за плотного графика нет времени и сил заниматься систематическим обучением команды, а чтобы учесть управляемость, так и возникла идея самостоятельной разработки 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);
   }
}

Из-за недостатка места конкретный класс операций будет продолжен в следующей статье.

Эта статья является оригиналом "Архитектуры бомбы Тома", пожалуйста, указывайте источник при перепечатке. Технология заключается в обмене, я разделяю свое счастье! Если у вас есть какие-либо предложения, вы также можете оставить комментарий или личное сообщение, Ваша поддержка является движущей силой для меня, чтобы упорствовать в создании. Обратите внимание на «архитектуру бомбы Тома», чтобы получить больше технической галантереи!

Нелегко быть оригинальным, и круто настаивать. Вы все это видели здесь. Не забудьте поставить лайк, добавить в закладки, посмотреть и подписаться одним щелчком мыши! Если вы считаете, что контент слишком сух, вы можете поделиться им и отправить своим друзьям, чтобы они питались и питались!