Record + Jackson VS ActiveRecord,解放双手,不写SQL(下)

3.BaseDTO

package com.jfan.dto;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apdplat.word.WordSegmenter;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.github.stuxuhai.jpinyin.PinyinException;
import com.github.stuxuhai.jpinyin.PinyinFormat;
import com.github.stuxuhai.jpinyin.PinyinHelper;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.jfinal.json.Jackson;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Config;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.DbKit;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;

/**
 * Base DTO
 */
public abstract class BaseDTO<T extends BaseDTO<T>> extends Record {

	private static final long serialVersionUID = 1L;

	/**
	 * 树表缓存
	 */
	private static final LoadingCache<Class<? extends BaseDTO<?>>, Map<Integer, ? extends BaseDTO<?>>> CACHE = CacheBuilder
			.newBuilder().maximumSize(100)
			.build(new CacheLoader<Class<? extends BaseDTO<?>>, Map<Integer, ? extends BaseDTO<?>>>() {

				@Override
				public Map<Integer, ? extends BaseDTO<?>> load(Class<? extends BaseDTO<?>> key) {
					LogKit.info(key + ":开始加载树表缓存==========");
					Map<Integer, ? extends BaseDTO<?>> baseDTOs = BaseDTO.select(key, "*").where(PID).eq(0).orderAsc()
							.tree().stream().collect(Collectors.toMap(e -> e.get_id(), e -> e,
									(first, last) -> last, () -> new LinkedHashMap<>()));
					baseDTOs.values().forEach(e -> {
						BaseDTO<?> pBaseDTO = baseDTOs.get(e.get_pid());
						if (pBaseDTO != null) {
							pBaseDTO.addChildDTO(e);
						}
					});
					LogKit.info(key + ":结束加载树表缓存==========");
					return baseDTOs;
				}

			});

	/**
	 * Table ATO
	 */
	@Inherited
	@Retention(RetentionPolicy.RUNTIME)
	@Target({ ElementType.TYPE })
	public @interface TableATO {

		/**
		 * 类型
		 */
		public enum Type {

			LIST("列表"), TREE("树表");

			private String key;

			private Type(String key) {
				this.key = key;
			}

			public String getKey() {
				return key;
			}

			public int getValue() {
				return ordinal();
			}

			public boolean isList() {
				return this == LIST;
			}

			public boolean isTree() {
				return this == TREE;
			}

		}

		/**
		 * 表名
		 * 
		 * @return String
		 */
		String key();

		/**
		 * 名称
		 * 
		 * @return String
		 */
		String title();

		/**
		 * 类型
		 * 
		 * @return Type
		 */
		Type type() default Type.LIST;

	}

	/**
	 * Column ATO
	 */
	@Inherited
	@Retention(RetentionPolicy.RUNTIME)
	@Target({ ElementType.FIELD })
	public @interface ColumnATO {

		/**
		 * 类型
		 */
		public enum Type {

			EDITOR("富文本"), IMAGE("图片"), JSONB_OBJECT_INFO("单对象"), JSONB_ARRAY_LIST("列对象"), JSONB_ARRAY_TREE(
					"树对象"), INPUT_INTEGER(
							"整数"), INPUT_NUMBER("数字"), INPUT_TEXT("文本"), INPUT_TIME("时间"), SELECT("列举"), TEXTAREA("多文本");

			private String key;

			private Type(String key) {
				this.key = key;
			}

			public String getKey() {
				return key;
			}

			public int getValue() {
				return ordinal();
			}

		}

		/**
		 * 列名
		 * 
		 * @return String
		 */
		String key();

		/**
		 * 名称
		 * 
		 * @return String
		 */
		String title();

		/**
		 * 类型
		 * 
		 * @return Type
		 */
		Type type();

		/**
		 * 排序
		 * 
		 * @return int
		 */
		int order() default 0;

		/**
		 * 注释
		 * 
		 * @return String
		 */
		String remark() default "";

	}

	public static final String ID = "_id";
	public static final String PID = "_pid";
	public static final String TITLE = "_title";
	public static final String LETTER = "_letter";
	public static final String ORDER = "_order";
	public static final String FEVER = "_fever";
	public static final String WORDS = "_words";
	public static final String POWER = "_power";

	/**
	 * 开关
	 */
	public enum Power {

		ON("打开"), OFF("关闭");

		private String key;

		private Power(String key) {
			this.key = key;
		}

		public String getKey() {
			return key;
		}

		public int getValue() {
			return ordinal();
		}

		public boolean isOn() {
			return this == ON;
		}

		public boolean isOff() {
			return this == OFF;
		}

	}

	public static final String REMARK = "_remark";
	public static final String USER = "_user";
	public static final String ROLERS = "_rolers";
	public static final String SOURCE = "_source";

	/**
	 * 操作来源
	 */
	public class Source extends Record {

		private static final long serialVersionUID = 1L;

		public static final String IP = "_ip";
		public static final String CS = "_cs";
		public static final String OS = "_os";

		/**
		 * IP
		 */
		@ColumnATO(key = IP, title = "IP", type = ColumnATO.Type.INPUT_TEXT)
		private String _ip;

		/**
		 * 客户端
		 */
		@ColumnATO(key = CS, title = "客户端", type = ColumnATO.Type.INPUT_TEXT)
		private String _cs;

		/**
		 * 操作系统
		 */
		@ColumnATO(key = OS, title = "操作系统", type = ColumnATO.Type.INPUT_TEXT)
		private String _os;

		public Source() {
			super();
		}

		public Source(String _ip, String _cs, String _os) {
			super();
			this._ip = _ip;
			this._cs = _cs;
			this._os = _os;
		}

		public String get_ip() {
			return _ip;
		}

		public Source set_ip(String _ip) {
			set(IP, this._ip = _ip);
			return this;
		}

		public String get_cs() {
			return _cs;
		}

		public Source set_cs(String _cs) {
			set(CS, this._cs = _cs);
			return this;
		}

		public String get_os() {
			return _os;
		}

		public Source set_os(String _os) {
			set(OS, this._os = _os);
			return this;
		}

	}

	public static final String DEVISE = "_devise";
	public static final String REVISE = "_revise";
	public static final String VERSION = "_version";

	/**
	 * ID
	 */
	@ColumnATO(key = ID, title = "ID", type = ColumnATO.Type.INPUT_INTEGER, order = -99, remark = "唯一性标识")
	protected Integer _id;

	/**
	 * PID
	 */
	@ColumnATO(key = PID, title = "PID", type = ColumnATO.Type.INPUT_INTEGER, order = -89, remark = "关系性标识")
	protected Integer _pid;

	/**
	 * 名称
	 */
	@ColumnATO(key = TITLE, title = "名称", type = ColumnATO.Type.INPUT_TEXT, order = -79, remark = "显示名称")
	protected String _title;

	/**
	 * 顺序
	 */
	@ColumnATO(key = LETTER, title = "顺序", type = ColumnATO.Type.INPUT_TEXT, order = 99, remark = "自然顺序")
	protected String _letter;

	/**
	 * 排序
	 */
	@ColumnATO(key = ORDER, title = "排序", type = ColumnATO.Type.INPUT_INTEGER, order = 109, remark = "手动排序")
	protected Integer _order;

	/**
	 * 权重
	 */
	@ColumnATO(key = FEVER, title = "权重", type = ColumnATO.Type.INPUT_INTEGER, order = 119, remark = "检索权重")
	protected Integer _fever;

	/**
	 * 分词
	 */
	@ColumnATO(key = WORDS, title = "分词", type = ColumnATO.Type.INPUT_TEXT, order = 129, remark = "检索分词")
	protected String _words;

	/**
	 * 开关
	 */
	@ColumnATO(key = POWER, title = "开关", type = ColumnATO.Type.SELECT, order = 139, remark = "有效性标识")
	protected Power _power;

	/**
	 * 注释
	 */
	@ColumnATO(key = REMARK, title = "注释", type = ColumnATO.Type.TEXTAREA, order = 149, remark = "注释信息")
	protected String _remark;

	/**
	 * 操作用户
	 */
	@ColumnATO(key = USER, title = "操作用户", type = ColumnATO.Type.JSONB_OBJECT_INFO, order = 159, remark = "操作用户")
	protected UserDTO _user;

	/**
	 * 操作角色
	 */
	@ColumnATO(key = ROLERS, title = "操作角色", type = ColumnATO.Type.JSONB_ARRAY_LIST, order = 169, remark = "操作角色")
	protected List<RoleDTO> _rolers;

	/**
	 * 操作来源
	 */
	@ColumnATO(key = SOURCE, title = "操作来源", type = ColumnATO.Type.JSONB_OBJECT_INFO, order = 179, remark = "操作来源")
	protected Source _source;

	/**
	 * 新建时间
	 */
	@ColumnATO(key = DEVISE, title = "新建时间", type = ColumnATO.Type.INPUT_TIME, order = 189, remark = "新建时间")
	protected Timestamp _devise;

	/**
	 * 编辑时间
	 */
	@ColumnATO(key = REVISE, title = "编辑时间", type = ColumnATO.Type.TIME, order = 199, remark = "编辑时间")
	protected Timestamp _revise;

	/**
	 * 版本快照
	 */
	@ColumnATO(key = VERSION, title = "版本快照", type = ColumnATO.Type.INPUT_INTEGER, order = 209, remark = "一致性标识")
	protected Integer _version;

	/**
	 * 树表子集
	 */
	@JsonIgnore
	protected Map<Integer, T> childDTOs = new LinkedHashMap<>();

	public BaseDTO() {
		super();
	}

	public Integer get_id() {
		return _id;
	}

	public T set_id(Integer _id) {
		return set(ID, this._id = _id);
	}

	public Integer get_pid() {
		return _pid;
	}

	public T set_pid(Integer _pid) {
		return set(PID, this._pid = _pid);
	}

	public String get_title() {
		return _title;
	}

	public T set_title(String _title) {
		return set(TITLE, this._title = _title);
	}

	public String get_letter() {
		return _letter;
	}

	public T set_letter(String _letter) {
		return set(LETTER, this._letter = _letter);
	}

	public Integer get_order() {
		return _order;
	}

	public T set_order(Integer _order) {
		return set(ORDER, this._order = _order);
	}

	public Integer get_fever() {
		return _fever;
	}

	public T set_fever(Integer _fever) {
		return set(FEVER, this._fever = _fever);
	}

	public String get_words() {
		return _words;
	}

	public T set_words(String _words) {
		return set(WORDS, this._words = _words);
	}

	public Power get_power() {
		return _power;
	}

	public T set_power(Power _power) {
		return set(POWER, this._power = _power);
	}

	public String get_remark() {
		return _remark;
	}

	public T set_remark(String _remark) {
		return set(REMARK, this._remark = _remark);
	}

	public UserDTO get_user() {
		return _user;
	}

	public T set_user(UserDTO _user) {
		return set(USER, this._user = _user);
	}

	public List<RoleDTO> get_rolers() {
		return _rolers;
	}

	public T set_rolers(List<RoleDTO> _rolers) {
		return set(ROLERS, this._rolers = _rolers);
	}

	public Source get_source() {
		return _source;
	}

	public T set_source(Source _source) {
		return set(SOURCE, this._source = _source);
	}

	public Timestamp get_devise() {
		return _devise;
	}

	public T set_devise(Timestamp _devise) {
		return set(DEVISE, this._devise = _devise);
	}

	public Timestamp get_revise() {
		return _revise;
	}

	public T set_revise(Timestamp _revise) {
		return set(REVISE, this._revise = _revise);
	}

	public Integer get_version() {
		return _version;
	}

	public T set_version(Integer _version) {
		return set(VERSION, this._version = _version);
	}

	public Map<Integer, T> getChildDTOs() {
		return childDTOs;
	}

	@SuppressWarnings("unchecked")
	public T setChildDTOs(Map<Integer, T> childDTOs) {
		this.childDTOs = childDTOs;
		return (T) this;
	}

	@SuppressWarnings("unchecked")
	public T addChildDTO(BaseDTO<?> childDTO) {
		childDTOs.put(childDTO.get_id(), (T) childDTO);
		return (T) this;
	}

	/**
	 * PostgreSql
	 */
	public static class PostgreSql<T extends BaseDTO<T>> {

		/**
		 * 表列
		 */
		private Map<String, String> selects;

		/**
		 * 表类
		 */
		private From from;

		/**
		 * 关联
		 */
		private Map<String, String> joins;

		/**
		 * 搜索
		 */
		private Map<String, Object> wheres;

		/**
		 * 排序
		 */
		private Map<String, String> orders;

		private PostgreSql(Config config, Class<T> clazz) {
			super();
			this.selects = new LinkedHashMap<>();
			this.from = new From(config, clazz);
			this.joins = new LinkedHashMap<>();
			this.wheres = new LinkedHashMap<>();
			this.orders = new LinkedHashMap<>();
		}

		/**
		 * 表列
		 */
		public class Select {

			private String[] keys;

			private Select(String... keys) {
				super();
				this.keys = keys;
			}

			public PostgreSql<T> select() {
				select: for (String key : keys) {
					switch (key) {
					case "*":
						selects.put("*", "*");
						selects.put(WORDS,
								Joiner.on("").join("ARRAY_TO_STRING(TSVECTOR_TO_ARRAY(", WORDS, "), ' ') AS ", WORDS));
						break select;
					case WORDS:
						selects.put(WORDS,
								Joiner.on("").join("ARRAY_TO_STRING(TSVECTOR_TO_ARRAY(", WORDS, "), ' ') AS ", WORDS));
						break;
					default:
						selects.put(key, key);
						break;
					}
				}
				where(POWER).eq(Power.ON.getValue());
				return PostgreSql.this;
			}

		}

		/**
		 * 表类
		 */
		public class From {

			private Config config;

			private Connection connection;

			private String key;

			private TableATO.Type type;

			private Class<T> clazz;

			private From(Config config, Class<T> clazz) {
				super();
				this.config = config;
				try {
					this.connection = config.getConnection();
				} catch (SQLException e) {
					LogKit.error(e.getMessage(), e);
				}
				TableATO tableATO = clazz.getAnnotation(TableATO.class);
				this.key = tableATO.key();
				this.type = tableATO.type();
				this.clazz = clazz;
			}

			public Config getConfig() {
				return config;
			}

			public Connection getConnection() {
				return connection;
			}

			public String getKey() {
				return key;
			}

			public TableATO.Type getType() {
				return type;
			}

			public Class<T> getClazz() {
				return clazz;
			}

			public T getFirst(String json) {
				return parseObject(json, clazz);
			}

			public List<T> getList(String json) {
				return parseArray(json, clazz);
			}

			public void close() {
				config.close(connection);
			}

			public void close(int result) {
				config.close(connection);
				if (result > 0 && type.isTree()) {
					CACHE.refresh(clazz);
				}
			}

		}

		/**
		 * 关联
		 */
		public class Join {

			private String key;

			private TableATO.Type type;

			private Class<T> clazz;

			private Join(Class<T> clazz) {
				super();
				TableATO tableATO = clazz.getAnnotation(TableATO.class);
				this.key = tableATO.key();
				this.type = tableATO.type();
				this.clazz = clazz;
			}

			private PostgreSql<T> by(String value) {
				joins.put(key, Joiner.on("").join(" LEFT JOIN ", key, " ON ", value, " = ", key, ".", ID));
				return PostgreSql.this;
			}

			public String getKey() {
				return key;
			}

			public TableATO.Type getType() {
				return type;
			}

			public Class<T> getClazz() {
				return clazz;
			}

			public PostgreSql<T> on(String value) {
				return by(value);
			}

		}

		/**
		 * 搜索
		 */
		public class Where {

			private String to;

			private String key;

			private Where(String to, String key) {
				super();
				this.to = to;
				this.key = key;
			}

			private PostgreSql<T> by(String vs, Object value) {
				if (wheres.isEmpty()) {
					wheres.put(Joiner.on(" ").join(" WHERE", key, vs, "?"), value);
				} else {
					wheres.put(Joiner.on(" ").join(to, key, vs, "?"), value);
				}
				return PostgreSql.this;
			}

			private PostgreSql<T> like(Object value) {
				if (wheres.isEmpty()) {
					wheres.put(Joiner.on(" ").join(" WHERE", key, "@@ TO_TSQUERY('?:*')"), value);
				} else {
					wheres.put(Joiner.on(" ").join(to, key, "@@ TO_TSQUERY('?:*')"), value);
				}
				order(FEVER).desc();
				return PostgreSql.this;
			}

			public PostgreSql<T> eq(Object value) {
				return by("=", value);
			}

			public PostgreSql<T> ne(Object value) {
				return by("!=", value);
			}

			public PostgreSql<T> ge(Object value) {
				return by(">=", value);
			}

			public PostgreSql<T> le(Object value) {
				return by("<=", value);
			}

			public PostgreSql<T> gt(Object value) {
				return by(">", value);
			}

			public PostgreSql<T> lt(Object value) {
				return by("<", value);
			}

			public PostgreSql<T> in(Object... values) {
				return by("IN", Joiner.on("").join("(", Joiner.on(", ").join(values), ")"));
			}

			public WhereElse info(String key) {
				return new WhereElse(ColumnATO.Type.JSONB_OBJECT_INFO, key);
			}

			public WhereElse list(String key) {
				return new WhereElse(ColumnATO.Type.JSONB_ARRAY_LIST, key);
			}

			public WhereElse tree(String key) {
				return new WhereElse(ColumnATO.Type.JSONB_ARRAY_TREE, key);
			}

			public class WhereElse {

				private ColumnATO.Type to;

				private String key;

				private WhereElse(ColumnATO.Type to, String key) {
					super();
					this.to = to;
					this.key = key;
				}

				private PostgreSql<T> by(String vs, Object value) {
					switch (to) {
					case JSONB_OBJECT_INFO:
						return Where.this.by(vs, parseJson(ImmutableMap.of(key, value)));
					case JSONB_ARRAY_LIST:
						return Where.this.by(vs, parseJson(ImmutableList.of(ImmutableMap.of(key, value))));
					case JSONB_ARRAY_TREE:
						return Where.this.by(vs, parseJson(ImmutableList.of(ImmutableMap.of(key, value))));
					default:
						return Where.this.by(vs, parseJson(ImmutableMap.of(key, value)));
					}
				}

				public PostgreSql<T> eq(Object value) {
					return by("@>", value);
				}

			}

		}

		/**
		 * 排序
		 */
		public class Order {

			private String key;

			private Order(String key) {
				super();
				this.key = key;
			}

			private PostgreSql<T> by(String value) {
				if (orders.isEmpty()) {
					orders.put(key, Joiner.on(" ").join(" ORDER BY", key, value));
				} else {
					orders.put(key, Joiner.on(" ").join(key, value));
				}
				return PostgreSql.this;
			}

			public PostgreSql<T> asc() {
				return by("ASC");
			}

			public PostgreSql<T> desc() {
				return by("DESC");
			}

		}

		/**
		 * 表列
		 * 
		 * @param keys
		 * @return PostgreSql<T>
		 */
		private PostgreSql<T> select(String... keys) {
			return new Select(keys).select();
		}

		/**
		 * 关联(不建议,推荐单表查询)
		 * 
		 * @param clazz
		 * @return Join
		 */
		public Join join(Class<T> clazz) {
			return new Join(clazz);
		}

		/**
		 * 搜索
		 * 
		 * @param key
		 * @return Where
		 */
		public Where where(String key) {
			return new Where("AND", key);
		}

		/**
		 * 搜索(全文检索)
		 * 
		 * @param value
		 * @return PostgreSql<T>
		 */
		public PostgreSql<T> whereLike(Object value) {
			return where(WORDS).like(value);
		}

		/**
		 * 搜索或
		 * 
		 * @param key
		 * @return Where
		 */
		public Where whereOr(String key) {
			return new Where("OR", key);
		}

		/**
		 * 搜索或(全文检索)
		 * 
		 * @param value
		 * @return PostgreSql<T>
		 */
		public PostgreSql<T> whereOrLike(Object value) {
			return whereOr(WORDS).like(value);
		}

		/**
		 * 排序
		 * 
		 * @param key
		 * @return Order
		 */
		public Order order(String key) {
			return new Order(key);
		}

		/**
		 * 排序升(自然顺序)
		 * 
		 * @return PostgreSql<T>
		 */
		public PostgreSql<T> orderAsc() {
			return new Order(LETTER).asc();
		}

		/**
		 * 排序降(自然顺序)
		 * 
		 * @return PostgreSql<T>
		 */
		public PostgreSql<T> orderDesc() {
			return new Order(LETTER).desc();
		}

		/**
		 * 注入参数
		 * 
		 * @param sql
		 * @param paras
		 * @return PreparedStatement
		 * @throws SQLException
		 */
		private PreparedStatement fillStatement(String sql, Object... paras) throws SQLException {
			PreparedStatement preparedStatement = from.getConnection().prepareStatement(sql,
					Statement.RETURN_GENERATED_KEYS);
			for (int i = 0, size = paras.length; i < size; i++) {
				preparedStatement.setObject(i + 1, paras[i]);
			}
			return preparedStatement;
		}

		/**
		 * 创建表和索引
		 * 
		 * @return boolean
		 */
		private boolean create() {
			List<ColumnATO> columnATOs = Stream
					.of(from.getClazz().getDeclaredFields(), from.getClazz().getSuperclass().getDeclaredFields())
					.flatMap(e -> Stream.of(e)).map(e -> e.getAnnotation(ColumnATO.class)).filter(e -> e != null)
					.sorted(Comparator.comparingInt(e -> e.order())).collect(Collectors.toList());
			try (PreparedStatement preparedStatement = fillStatement(
					Joiner.on("").join("CREATE TABLE ", from.getKey(), " (", columnATOs.stream().map(e -> {
						switch (e.key()) {
						case ID:
							return Joiner.on(" ").join(e.key(), "SERIAL4 PRIMARY KEY");
						case WORDS:
							return Joiner.on(" ").join(e.key(), "TSVECTOR");
						default:
							switch (e.type()) {
							case EDITOR:
								return Joiner.on(" ").join(e.key(), "TEXT");
							case IMAGE:
								return Joiner.on(" ").join(e.key(), "TEXT");
							case JSONB_OBJECT_INFO:
								return Joiner.on(" ").join(e.key(), "JSONB");
							case JSONB_ARRAY_LIST:
								return Joiner.on(" ").join(e.key(), "JSONB");
							case JSONB_ARRAY_TREE:
								return Joiner.on(" ").join(e.key(), "JSONB");
							case INPUT_INTEGER:
								return Joiner.on(" ").join(e.key(), "INT4");
							case INPUT_NUMBER:
								return Joiner.on(" ").join(e.key(), "NUMERIC(12,2)");
							case INPUT_TEXT:
								return Joiner.on(" ").join(e.key(), "TEXT");
							case INPUT_TIME:
								return Joiner.on(" ").join(e.key(), "TIMESTAMP(6)");
							case SELECT:
								return Joiner.on(" ").join(e.key(), "INT4");
							case TEXTAREA:
								return Joiner.on(" ").join(e.key(), "TEXT");
							default:
								return null;
							}
						}
					}).filter(e -> e != null).collect(Collectors.joining(", ")), "); ", columnATOs.stream().map(e -> {
						switch (e.key()) {
						case ID:
							return Joiner.on("").join("CREATE UNIQUE INDEX ON ", from.getKey(), " USING BTREE (",
									e.key(), ")");
						case PID:
							return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING BTREE (", e.key(),
									")");
						case LETTER:
							return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING BTREE (", e.key(),
									")");
						case WORDS:
							return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING GIN (", e.key(), ")");
						default:
							switch (e.type()) {
							case EDITOR:
								return null;
							case IMAGE:
								return null;
							case JSONB_OBJECT_INFO:
								return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING GIN (", e.key(),
										")");
							case JSONB_ARRAY_LIST:
								return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING GIN (", e.key(),
										")");
							case JSONB_ARRAY_TREE:
								return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING GIN (", e.key(),
										")");
							case INPUT_INTEGER:
								return null;
							case INPUT_NUMBER:
								return null;
							case INPUT_TEXT:
								return null;
							case INPUT_TIME:
								return null;
							case SELECT:
								return Joiner.on("").join("CREATE INDEX ON ", from.getKey(), " USING BTREE (", e.key(),
										")");
							case TEXTAREA:
								return null;
							default:
								return null;
							}
						}
					}).filter(e -> e != null).collect(Collectors.joining("; ")), "; "))) {
				return preparedStatement.executeUpdate() == 0;
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return false;
		}

		/**
		 * 保存
		 * 
		 * @return int
		 */
		private int save() {
			int result = 0;
			try (PreparedStatement preparedStatement = fillStatement(
					Joiner.on("").join("INSERT INTO ", from.getKey(), " (", Joiner.on(", ").join(selects.keySet()),
							") VALUES (", Joiner.on(", ").join(selects.values()), ")"),
					wheres.values().toArray());
					ResultSet resultSet = preparedStatement.executeUpdate() == 1 ? preparedStatement.getGeneratedKeys()
							: preparedStatement.getGeneratedKeys()) {
				if (resultSet.next()) {
					result = resultSet.getInt(ID);
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close(result);
			}
			return result;
		}

		/**
		 * 计数
		 * 
		 * @return int
		 */
		public int count() {
			int result = 0;
			try (PreparedStatement preparedStatement = fillStatement(Joiner.on("").join("SELECT COUNT(*)", " FROM ",
					from.getKey(), Joiner.on("").join(joins.values()), Joiner.on(" ").join(wheres.keySet())),
					wheres.values().toArray()); ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					result = resultSet.getInt("COUNT");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return result;
		}

		/**
		 * 求和
		 * 
		 * @param key
		 * @return double
		 */
		public double sum(String key) {
			double result = 0;
			try (PreparedStatement preparedStatement = fillStatement(Joiner.on("").join("SELECT SUM(", key, ") FROM ",
					from.getKey(), Joiner.on("").join(joins.values()), Joiner.on(" ").join(wheres.keySet())),
					wheres.values().toArray()); ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					result = resultSet.getDouble("SUM");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return result;
		}

		/**
		 * 查询单行(Json)
		 * 
		 * @return String
		 */
		public String firstToJson() {
			String result = null;
			try (PreparedStatement preparedStatement = fillStatement(
					Joiner.on("").join("SELECT CAST(TO_JSONB(T) AS TEXT) FROM (SELECT ",
							Joiner.on(", ").join(selects.values()), " FROM ", from.getKey(),
							Joiner.on("").join(joins.values()), Joiner.on(" ").join(wheres.keySet()),
							Joiner.on(", ").join(orders.values()), " LIMIT 1 OFFSET 0", ") AS T"),
					wheres.values().toArray()); ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					result = resultSet.getString("TO_JSONB");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return result;
		}

		/**
		 * 查询单行
		 * 
		 * @return T
		 */
		public T first() {
			return from.getFirst(firstToJson());
		}

		/**
		 * ID查询单行(Json)
		 * 
		 * @return String
		 */
		public String firstToJson(Object id) {
			return where(ID).eq(id).firstToJson();
		}

		/**
		 * ID查询单行
		 * 
		 * @return T
		 */
		public T first(Object id) {
			return where(ID).eq(id).first();
		}

		/**
		 * 查询列表(Json)
		 * 
		 * @return String
		 */
		private String listToJson() {
			String result = null;
			try (PreparedStatement preparedStatement = fillStatement(Joiner.on("").join(
					"SELECT CAST(JSONB_AGG(T) AS TEXT) FROM (SELECT ", Joiner.on(", ").join(selects.values()), " FROM ",
					from.getKey(), Joiner.on("").join(joins.values()), Joiner.on(" ").join(wheres.keySet()),
					Joiner.on(", ").join(orders.values()), ") AS T"), wheres.values().toArray());
					ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					result = resultSet.getString("JSONB_AGG");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return result;
		}

		/**
		 * 查询列表
		 * 
		 * @return List<T>
		 */
		@SuppressWarnings("unused")
		private List<T> list() {
			return from.getList(listToJson());
		}

		/**
		 * 查询树表(Json)
		 * 
		 * @return String
		 */
		private String treeToJson() {
			String result = null;
			if (from.getType().isList()) {
				return result;
			}
			String selectSql = Joiner.on("").join("SELECT ", selects.values().stream().map(e -> {
				if (e.contains(WORDS)) {
					return e.replaceFirst(WORDS, "_T." + WORDS);
				}
				return "_T." + e;
			}).collect(Collectors.joining(", ")), " FROM ", from.getKey(), " AS _T");
			try (PreparedStatement preparedStatement = fillStatement(
					Joiner.on("").join("WITH RECURSIVE T AS (", selectSql, wheres.keySet().stream().map(e -> {
						if (e.contains("WHERE")) {
							return e.replace("WHERE", "WHERE _T.");
						} else if (e.contains("AND")) {
							return e.replace("AND", "AND _T.");
						} else if (e.contains("OR")) {
							return e.replace("OR", "OR _T.");
						} else if (e.contains("IN")) {
							return e.replace("IN", "IN _T.");
						}
						return "_T." + e;
					}).collect(Collectors.joining(" ")), " UNION ALL ", selectSql, " INNER JOIN T ON _T.", PID, " = T.",
							ID, ") SELECT CAST(JSONB_AGG(_T) AS TEXT) FROM (SELECT ",
							Joiner.on(", ").join(selects.values()), " FROM ", from.getKey(), " ORDER BY ", ID,
							" ASC) AS _T"),
					wheres.values().toArray()); ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					result = resultSet.getString("JSONB_AGG");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return result;
		}

		/**
		 * 查询树表
		 * 
		 * @return List<T>
		 */
		private List<T> tree() {
			return from.getList(treeToJson());
		}

		/**
		 * 查询分页(Json)
		 * 
		 * @param pageNumber
		 * @param pageSize
		 * @return String
		 */
		public String listToJson(int pageNumber, int pageSize) {
			int totalRow = 0;
			String result = null;
			String fromSql = Joiner.on("").join(" FROM ", from.getKey(), Joiner.on("").join(joins.values()),
					Joiner.on(" ").join(wheres.keySet()));
			try (PreparedStatement preparedStatement = fillStatement(
					Joiner.on("").join("SELECT (SELECT COUNT(*)", fromSql,
							"), CAST(JSONB_AGG(T) AS TEXT) FROM (SELECT ", Joiner.on(", ").join(selects.values()),
							fromSql, Joiner.on(", ").join(orders.values()), " LIMIT ", pageSize, " OFFSET ",
							(pageNumber - 1) * pageSize, ") AS T"),
					Stream.concat(wheres.values().stream(), wheres.values().stream()).collect(Collectors.toList())
							.toArray());
					ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					totalRow = resultSet.getInt("COUNT");
					result = resultSet.getString("JSONB_AGG");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return Joiner.on("").join("{\"list\": ", result, ", \"pageNumber\": ", pageNumber, ", \"pageSize\": ",
					pageSize, ", \"totalPage\": ",
					totalRow % pageSize != 0 ? totalRow / pageSize + 1 : totalRow / pageSize, ", \"totalRow\": ",
					totalRow, "}");
		}

		/**
		 * 查询分页
		 * 
		 * @param pageNumber
		 * @param pageSize
		 * @return Page<T>
		 */
		public Page<T> list(int pageNumber, int pageSize) {
			int totalRow = 0;
			String result = null;
			String fromSql = Joiner.on("").join(" FROM ", from.getKey(), Joiner.on("").join(joins.values()),
					Joiner.on(" ").join(wheres.keySet()));
			try (PreparedStatement preparedStatement = fillStatement(
					Joiner.on("").join("SELECT (SELECT COUNT(*)", fromSql,
							"), CAST(JSONB_AGG(T) AS TEXT) FROM (SELECT ", Joiner.on(", ").join(selects.values()),
							fromSql, Joiner.on(", ").join(orders.values()), " LIMIT ", pageSize, " OFFSET ",
							(pageNumber - 1) * pageSize, ") AS T"),
					Stream.concat(wheres.values().stream(), wheres.values().stream()).collect(Collectors.toList())
							.toArray());
					ResultSet resultSet = preparedStatement.executeQuery()) {
				if (resultSet.next()) {
					totalRow = resultSet.getInt("COUNT");
					result = resultSet.getString("JSONB_AGG");
				}
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close();
			}
			return new Page<>(from.getList(result), pageNumber, pageSize,
					totalRow % pageSize != 0 ? totalRow / pageSize + 1 : totalRow / pageSize, totalRow);
		}

		/**
		 * 更新
		 * 
		 * @return int
		 */
		private int update() {
			int result = 0;
			try (PreparedStatement preparedStatement = fillStatement(Joiner.on("").join("UPDATE ", from.getKey(),
					" SET ", Joiner.on(", ").join(selects.values()), " WHERE ", ID, " = ? AND ", VERSION, " = ?)"),
					wheres.values().toArray())) {
				result = preparedStatement.executeUpdate();
			} catch (SQLException e) {
				LogKit.error(e.getMessage(), e);
			} finally {
				from.close(result);
			}
			return result;
		}

	}

	@JsonIgnore
	@Override
	public Map<String, Object> getColumns() {
		return super.getColumns();
	}

	@SuppressWarnings("unchecked")
	@Override
	public T set(String key, Object value) {
		return (T) super.set(key, value);
	}

	@JsonIgnore
	@Override
	public String[] getColumnNames() {
		return super.getColumnNames();
	}

	@JsonIgnore
	@Override
	public Object[] getColumnValues() {
		return super.getColumnValues();
	}

	public Map<String, Object> toJsonb() {
		return ImmutableMap.of(ID, _id, TITLE, _title, VERSION, _version);
	}

	/**
	 * 事务
	 * 
	 * @param atom
	 * @return boolean
	 */
	public static boolean tx(IAtom atom) {
		return Db.use().tx(atom);
	}

	/**
	 * 自定义事务
	 * 
	 * @param configName
	 * @param atom
	 * @return boolean
	 */
	public static boolean txFrom(String configName, IAtom atom) {
		return Db.use(configName).tx(atom);
	}

	/**
	 * 创建表
	 * 
	 * @param clazz
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	public static <T extends BaseDTO<T>> boolean create(Class<? extends BaseDTO<?>> clazz) {
		return new PostgreSql<T>(DbKit.getConfig(), (Class<T>) clazz).create();
	}

	/**
	 * 自定义创建表
	 * 
	 * @param configName
	 * @param clazz
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	public static <T extends BaseDTO<T>> boolean createFrom(String configName, Class<? extends BaseDTO<?>> clazz) {
		return new PostgreSql<T>(DbKit.getConfig(configName), (Class<T>) clazz).create();
	}

	/**
	 * 保存
	 * 
	 * @param config
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	private boolean save(PostgreSql<T> postgreSql) {
		if (_pid == null) {
			set_pid(0);
		}
		if (_title != null) {
			if (_words == null) {
				_words = _title;
			}
			set_letter(getLetter(_title));
		}
		if (_order == null) {
			set_order(0);
		}
		if (_fever == null) {
			set_fever(0);
		}
		if (_words != null) {
			set_words(getWords(_words));
		}
		if (_power == null) {
			set_power(Power.ON);
		}
		set(DEVISE, "NOW()");
		set(REVISE, "NOW()");
		set_version(0);
		remove(ID).getColumns().forEach((k, v) -> {
			switch (k) {
			case WORDS:
				postgreSql.selects.put(k, "TO_TSVECTOR(?)");
				break;
			default:
				postgreSql.selects.put(k, "?");
				break;
			}
			if (v instanceof BaseDTO) {
				postgreSql.wheres.put(k, parseJson(((BaseDTO<?>) v).toJsonb()));
			} else if (v instanceof Enum) {
				postgreSql.wheres.put(k, parseJson(v));
			} else if (v instanceof List) {
				if (((List<?>) v).get(0) instanceof BaseDTO) {
					postgreSql.wheres.put(k, parseJson(
							((List<BaseDTO<?>>) v).stream().map(e -> e.toJsonb()).collect(Collectors.toList())));
				} else {
					postgreSql.wheres.put(k, parseJson(v));
				}
			} else if (v instanceof Record) {
				postgreSql.wheres.put(k, parseJson(v));
			} else {
				postgreSql.wheres.put(k, v);
			}
		});
		set_id(postgreSql.save());
		return _id > 0;
	}

	/**
	 * 保存
	 * 
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	public boolean save() {
		return save(new PostgreSql<T>(DbKit.getConfig(), (Class<T>) getClass()));
	}

	/**
	 * 自定义保存
	 * 
	 * @param configName
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	public boolean saveFrom(String configName) {
		return save(new PostgreSql<T>(DbKit.getConfig(configName), (Class<T>) getClass()));
	}

	/**
	 * 查询
	 * 
	 * @param clazz
	 * @param keys
	 * @return PostgreSql<T>
	 */
	@SuppressWarnings("unchecked")
	public static <T extends BaseDTO<T>> PostgreSql<T> select(Class<? extends BaseDTO<?>> clazz, String... keys) {
		return new PostgreSql<T>(DbKit.getConfig(), (Class<T>) clazz).select(keys);
	}

	/**
	 * 自定义查询
	 * 
	 * @param configName
	 * @param clazz
	 * @param keys
	 * @return PostgreSql<T>
	 */
	@SuppressWarnings("unchecked")
	public static <T extends BaseDTO<T>> PostgreSql<T> selectFrom(String configName, Class<? extends BaseDTO<?>> clazz,
			String... keys) {
		return new PostgreSql<T>(DbKit.getConfig(configName), (Class<T>) clazz).select(keys);
	}

	/**
	 * 查询树表缓存
	 * 
	 * @param clazz
	 * @return Map<Integer, T>
	 */
	@SuppressWarnings("unchecked")
	public static <T extends BaseDTO<T>> Map<Integer, T> selectFromCache(Class<? extends BaseDTO<?>> clazz) {
		return (Map<Integer, T>) CACHE.getUnchecked(clazz);
	}

	/**
	 * 更新
	 * 
	 * @param config
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	private boolean update(PostgreSql<T> postgreSql) {
		set(REVISE, "NOW()");
		set(VERSION, _version + 1);
		remove(ID).getColumns().forEach((k, v) -> {
			switch (k) {
			case WORDS:
				postgreSql.selects.put(k, k + " = TO_TSVECTOR(?)");
				break;
			default:
				postgreSql.selects.put(k, k + " = ?");
				break;
			}
			if (v instanceof BaseDTO) {
				postgreSql.wheres.put(k, parseJson(((BaseDTO<?>) v).toJsonb()));
			} else if (v instanceof Enum) {
				postgreSql.wheres.put(k, parseJson(v));
			} else if (v instanceof List) {
				if (((List<?>) v).get(0) instanceof BaseDTO) {
					postgreSql.wheres.put(k, parseJson(
							((List<BaseDTO<?>>) v).stream().map(e -> e.toJsonb()).collect(Collectors.toList())));
				} else {
					postgreSql.wheres.put(k, parseJson(v));
				}
			} else if (v instanceof Record) {
				postgreSql.wheres.put(k, parseJson(v));
			} else {
				postgreSql.wheres.put(k, v);
			}
		});
		postgreSql.wheres.put("WHERE" + ID, _id);
		postgreSql.wheres.put("WHERE" + VERSION, _version);
		return postgreSql.update() == 1;
	}

	/**
	 * 更新
	 * 
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	public boolean update() {
		return update(new PostgreSql<T>(DbKit.getConfig(), (Class<T>) getClass()));
	}

	/**
	 * 自定义更新
	 * 
	 * @param configName
	 * @return boolean
	 */
	@SuppressWarnings("unchecked")
	public boolean updateFrom(String configName) {
		return update(new PostgreSql<T>(DbKit.getConfig(configName), (Class<T>) getClass()));
	}

	/**
	 * 获取自然顺序
	 * 
	 * @param text
	 * @return String
	 */
	public static String getLetter(String text) {
		try {
			return PinyinHelper.convertToPinyinString(text.toLowerCase(), "", PinyinFormat.WITH_TONE_NUMBER)
					.replaceAll("[^A-Za-z0-9]", "");
		} catch (PinyinException e) {
			LogKit.error(e.getMessage(), e);
		}
		return text;
	}

	/**
	 * 获取检索分词
	 * 
	 * @param text
	 * @return String
	 */
	public static String getWords(String text) {
		return Splitter
				.on(" ").splitToList(text).stream().map(e -> e.toLowerCase()).flatMap(e -> Stream
						.concat(WordSegmenter.segWithStopWords(e).stream().map(i -> i.getText()), Stream.of(e)))
				.flatMap(e -> {
					try {
						return ImmutableList
								.of(PinyinHelper.getShortPinyin(e),
										PinyinHelper.convertToPinyinString(e, "", PinyinFormat.WITHOUT_TONE), e)
								.stream();
					} catch (PinyinException ex) {
						LogKit.error(ex.getMessage(), ex);
					}
					return null;
				}).filter(e -> e != null).distinct().collect(Collectors.joining(" "));
	}

	/**
	 * 获取序列化文本
	 * 
	 * @param object
	 * @return String
	 */
	public static String parseJson(Object object) {
		Jackson jackson = Jackson.getJson();
		jackson.getObjectMapper().enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);
		return jackson.toJson(object);
	}

	/**
	 * 获取序列化对象
	 * 
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static <T> T parseObject(String json, Class<T> clazz) {
		if (StrKit.isBlank(json)) {
			return null;
		}
		try {
			ObjectMapper objectMapper = Jackson.getJson().getObjectMapper();
			return objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX).readValue(json, clazz);
		} catch (Exception e) {
			throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
		}
	}

	/**
	 * 获取序列化集合
	 * 
	 * @param json
	 * @param clazz
	 * @return
	 */
	public static <T> List<T> parseArray(String json, Class<T> clazz) {
		if (StrKit.isBlank(json)) {
			return ImmutableList.of();
		}
		try {
			ObjectMapper objectMapper = Jackson.getJson().getObjectMapper();
			return objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX).readValue(json,
					objectMapper.getTypeFactory().constructCollectionType(List.class, clazz));
		} catch (Exception e) {
			throw e instanceof RuntimeException ? (RuntimeException) e : new RuntimeException(e);
		}
	}

}

BaseDTO为核心模块,全部代码1700多行,大部分代码添加了注释,表模型继承她即变身成功,查询方法要传入自身类型,当然为了优雅你可以在表模型中加入几个方法,例如:

package com.jfan.dto;

import java.util.Map;

import com.jfan.dto.BaseDTO.TableATO;

/**
 * Area DTO
 */
@TableATO(key = "_area", title = "地区", type = TableATO.Type.TREE)
public class AreaDTO extends BaseDTO<AreaDTO> {

	private static final long serialVersionUID = 1L;

	public static final String TYPE = "_type";

	/**
	 * 类型
	 */
	public enum Type {

		PROVINCE("省份"), CITY("城市"), DISTRICT("区县"), STREET("街道");

		private String key;

		private Type(String key) {
			this.key = key;
		}

		public String getKey() {
			return key;
		}

		public int getValue() {
			return ordinal();
		}

	}

	/**
	 * 类型
	 */
	@ColumnATO(key = TYPE, title = "类型", type = ColumnATO.Type.SELECT)
	private Type _type;

	public AreaDTO() {
		super();
	}

	public Type get_type() {
		return _type;
	}

	public AreaDTO set_type(Type _type) {
		return set(TYPE, this._type = _type);
	}

	public static PostgreSql<AreaDTO> select(String... keys) {
		return select(AreaDTO.class, keys);
	}

	public static PostgreSql<AreaDTO> selectFrom(String configName, String... keys) {
		return selectFrom(configName, AreaDTO.class, keys);
	}

	public static Map<Integer, AreaDTO> selectFromCache() {
		return selectFromCache(AreaDTO.class);
	}

}

以上,使用方法很简单,认真看了代码就懂,或者把代码copy下来直接测试。本人第一次发帖,陆陆续续编写文案和整理代码花了两天时间。这次发帖不仅作为技术交流分享,欢迎大家的批评和指正,更是作为加入俱乐部即将上线的自由开发者平台的敲门砖,欢迎JFinal的审核和检阅,也算是为JFinal的生态尽了一份绵力。本人作为一名真实的全职自由开发者,全力承接各类项目和工程,如果大家有特殊需求,可以去俱乐部找我(笑),QQ名字和本贴作者一样,或者加我微信深入了解。微信图片_20190311215037.jpg


评论区

快乐的蹦豆子

2019-03-12 09:43

奔跑吧骄傲的少年

JFinal

2019-03-12 11:23

这个功能挺大的,这么少的代码实现,楼主功力很深啊,要是加上使用方法的 demo 代码就好了,赞一个

Destiny

2019-03-12 12:05

@JFinal 功能的实现主要得益于ActiveRecord的启发和思考,demo很简单,表模型如AreaDTO继承BaseDTO,然后调用一下create创建表,就可以打完收工了。。。