hsweb 的系列学习 --hsweb-easy-orm 分析 (下)

1,163 阅读26分钟
原文链接: zhuanlan.zhihu.com
接上一篇《hsweb的系列学习--hsweb-easy-orm分析》

TableMetaDataStorage定义

以上三个MetaData元素定义完之后,通过TableMetaDataStorage来对表元数据做存储方面的一些操作:

package org.hsweb.ezorm.core.meta.storage;
import org.hsweb.ezorm.core.meta.TableMetaData;
import java.util.Set;
public interface TableMetaDataStorage {
    <T extends TableMetaData> Set<T> getAllTableMetaData();
    <T extends TableMetaData> T getTableMetaData(String nameOrAlias);
    <T extends TableMetaData> T removeTableMeta(String nameOrAlias);
    <T extends TableMetaData> T putTableMetaData(T table);
    void clear();
}

因为本就是key-value形式保存的,那么很自然就衍生成map类型的实现类: 都是一些map方面的操作,就不多说了

package org.hsweb.ezorm.core.meta.storage;
import org.hsweb.ezorm.core.meta.TableMetaData;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
public class MapTableMetaDataStorage implements TableMetaDataStorage {
    private final Map<String, TableMetaData> nameTableMetaDataStorage  = new HashMap<>();
    private final Map<String, TableMetaData> aliasTableMetaDataStorage = new HashMap<>();
    @Override
    public <T extends TableMetaData> Set<T> getAllTableMetaData() {
        Set<T> all = new LinkedHashSet<>();
        all.addAll((Set) nameTableMetaDataStorage.values());
        return all;
    }
    @Override
    public <T extends TableMetaData> T getTableMetaData(String nameOrAlias) {
        T old = (T) nameTableMetaDataStorage.get(nameOrAlias);
        if (old == null) old = (T) aliasTableMetaDataStorage.get(nameOrAlias);
        return old;
    }
    @Override
    public <T extends TableMetaData> T removeTableMeta(String nameOrAlias) {
        T old = (T) nameTableMetaDataStorage.remove(nameOrAlias);
        T old2 = (T) aliasTableMetaDataStorage.remove(nameOrAlias);
        return old != null ? old : old2;
    }
    @Override
    public <T extends TableMetaData> T putTableMetaData(T table) {
        nameTableMetaDataStorage.put(table.getName(), table);
        if (!table.getName().equals(table.getAlias())) {
            nameTableMetaDataStorage.put(table.getAlias(), table);
        }
        return table;
    }
    @Override
    public void clear() {
        nameTableMetaDataStorage.clear();
        aliasTableMetaDataStorage.clear();
    }
}

对上面定义的三个元数据类型接口的抽象实现:

对于DatabaseMetaData的初步通用实现:

package org.hsweb.ezorm.core.meta;
import org.hsweb.ezorm.core.ObjectWrapperFactory;
import org.hsweb.ezorm.core.ValidatorFactory;
import org.hsweb.ezorm.core.meta.storage.MapTableMetaDataStorage;
import org.hsweb.ezorm.core.meta.storage.TableMetaDataStorage;
public abstract class AbstractDatabaseMetaData implements DatabaseMetaData {
    protected ObjectWrapperFactory objectWrapperFactory;
    protected ValidatorFactory     validatorFactory;
    protected TableMetaDataStorage tableMetaDataStorage=new MapTableMetaDataStorage();
    @Override
    public <T extends TableMetaData> T getTableMetaData(String name) {
        return tableMetaDataStorage.getTableMetaData(name);
    }
    @Override
    public ObjectWrapperFactory getObjectWrapperFactory() {
        return objectWrapperFactory;
    }
    @Override
    public ValidatorFactory getValidatorFactory() {
        return validatorFactory;
    }
    public void setObjectWrapperFactory(ObjectWrapperFactory objectWrapperFactory) {
        this.objectWrapperFactory = objectWrapperFactory;
    }
    public void setValidatorFactory(ValidatorFactory validatorFactory) {
        this.validatorFactory = validatorFactory;
    }
    public void setTableMetaDataStorage(TableMetaDataStorage tableMetaDataStorage) {
        this.tableMetaDataStorage = tableMetaDataStorage;
    }
}

对于TableMetaData的初步通用实现:

properties triggerBase都是用map来进行相应包装

package org.hsweb.ezorm.core.meta;
import org.hsweb.ezorm.core.*;
import java.util.*;
public abstract class AbstractTableMetaData<C extends AbstractColumnMetaData> implements TableMetaData {
    //表名称
    protected String               name                   = null;
    //表别名,如果指定了别名,查询结果将使用别名进行封装
    protected String               alias                  = null;
    //备注
    protected String               comment                = null;
    //表字段
    protected Map<String, C>       columnMetaDataMap      = new LinkedHashMap<>();
    protected Map<String, C>       aliasColumnMetaDataMap = new LinkedHashMap<>();
    protected Validator            validator              = null;
    protected ObjectWrapper        objectWrapper          = null;
    protected Map<String, Object>  properties             = new HashMap<>();
    protected Map<String, Trigger> triggerBase            = new HashMap<>();
    @Override
    public <T> ObjectWrapper<T> getObjectWrapper() {
        return objectWrapper;
    }
    public void setObjectWrapper(ObjectWrapper objectWrapper) {
        this.objectWrapper = objectWrapper;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAlias() {
        if (alias == null) alias = name;
        return alias;
    }
    public <T extends AbstractTableMetaData<C>> T addColumn(C columnMetaData) {
        columnMetaData.setTableMetaData(this);
        columnMetaDataMap.put(columnMetaData.getName(), columnMetaData);
        if (!columnMetaData.getName().equals(columnMetaData.getAlias()))
            aliasColumnMetaDataMap.put(columnMetaData.getAlias(), columnMetaData);
        return (T) this;
    }
    public void setAlias(String alias) {
        this.alias = alias;
    }
    public void on(String triggerName, Trigger trigger) {
        triggerBase.put(triggerName, trigger);
    }
    public void on(String triggerName, Map<String, Object> context) {
        if (triggerIsSupport(triggerName)) {
            Trigger trigger = triggerBase.get(triggerName);
            trigger.execute(context);
        }
    }
    @Override
    public Set<C> getColumns() {
        return new LinkedHashSet<>(columnMetaDataMap.values());
    }
    public void removeColumn(String name) {
        columnMetaDataMap.remove(name);
        aliasColumnMetaDataMap.remove(name);
    }
    public boolean triggerIsSupport(String name) {
        return triggerBase.containsKey(name);
    }
    public PropertyWrapper getProperty(String name) {
        return new SimplePropertyWrapper(properties.get(name));
    }
    public PropertyWrapper getProperty(String name, Object defaultValue) {
        return new SimplePropertyWrapper(properties.getOrDefault(name, defaultValue));
    }
    public PropertyWrapper removeProperty(String name) {
        return new SimplePropertyWrapper(properties.remove(name));
    }
    public PropertyWrapper setProperty(String property, Object value) {
        return new SimplePropertyWrapper(properties.put(property, value));
    }
    public abstract C findColumn(String name);
    public String getComment() {
        return comment;
    }
    @Override
    public C getColumn(String name) {
        C metaData = columnMetaDataMap.get(name);
        if (metaData == null) metaData = aliasColumnMetaDataMap.get(name);
        return metaData;
    }
    public void setComment(String comment) {
        this.comment = comment;
    }
    public Map<String, Object> getProperties() {
        return properties;
    }
    public void setProperties(Map<String, Object> properties) {
        this.properties = properties;
    }
    public Validator getValidator() {
        return validator;
    }
    public void setValidator(Validator validator) {
        this.validator = validator;
    }
    @Override
    public String toString() {
        return name + " [" + alias + "]" + "(" + comment + ")";
    }
}

对于ColumnMetaData的初步通用实现:

package org.hsweb.ezorm.core.meta;
import org.hsweb.ezorm.core.OptionConverter;
import org.hsweb.ezorm.core.PropertyWrapper;
import org.hsweb.ezorm.core.SimplePropertyWrapper;
import org.hsweb.ezorm.core.ValueConverter;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public abstract class AbstractColumnMetaData implements ColumnMetaData {
    protected String          name;
    protected String          alias;
    protected String          comment;
    protected Class           javaType;
    protected TableMetaData   tableMetaData;
    protected OptionConverter optionConverter;
    protected ValueConverter  valueConverter;
    protected Set<String>     validator;
    protected Map<String, Object> properties = new HashMap<>();
    @Override
    public String getName() {
        return name;
    }
    @Override
    public String getAlias() {
        if (alias == null) alias = name;
        return alias;
    }
    @Override
    public String getComment() {
        if (comment == null) comment = "";
        return comment;
    }
    @Override
    public Class getJavaType() {
        return javaType;
    }
    @Override
    public Set<String> getValidator() {
        return validator;
    }
    @Override
    public <T extends TableMetaData> T getTableMetaData() {
        return (T) tableMetaData;
    }
    @Override
    public ValueConverter getValueConverter() {
        return valueConverter;
    }
    @Override
    public OptionConverter getOptionConverter() {
        return optionConverter;
    }
    @Override
    public PropertyWrapper getProperty(String property) {
        return new SimplePropertyWrapper(properties.get(property));
    }
    @Override
    public PropertyWrapper getProperty(String property, Object defaultValue) {
        Object value = properties.get(property);
        return new SimplePropertyWrapper(value == null ? defaultValue : value);
    }
    @Override
    public PropertyWrapper setProperty(String property, Object value) {
        return new SimplePropertyWrapper(properties.put(property, value));
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAlias(String alias) {
        this.alias = alias;
    }
    public void setComment(String comment) {
        this.comment = comment;
    }
    public void setJavaType(Class javaType) {
        this.javaType = javaType;
    }
    public void setTableMetaData(TableMetaData tableMetaData) {
        this.tableMetaData = tableMetaData;
    }
    public void setOptionConverter(OptionConverter optionConverter) {
        this.optionConverter = optionConverter;
    }
    public void setValueConverter(ValueConverter valueConverter) {
        this.valueConverter = valueConverter;
    }
    public void setValidator(Set<String> validator) {
        this.validator = validator;
    }
    public Map<String, Object> getProperties() {
        return properties;
    }
    public void setProperties(Map<String, Object> properties) {
        this.properties = properties;
    }
    @Override
    public abstract AbstractColumnMetaData clone();
}

三,curd的逻辑

从sql语句里可以看出,查,删,改,都是伴随着条件进行的,首先对条件进行设计,然后再具体事情具体办

1,设计一个统一的条件类型的支持接口来统一接收

一个是根据输入条件TermTypeConditionalSupport:

package org.hsweb.ezorm.core;
public interface TermTypeConditionalSupport {
    interface Accepter<T> {
        T accept(String column, String termType, Object value);
    }
    interface SimpleAccepter<T> {
        T accept(String column, Object value);
    }
}

另外一个根据实例化的po bean TermTypeConditionalFromBeanSupport:

package org.hsweb.ezorm.core;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public interface TermTypeConditionalFromBeanSupport {
    Logger logger = LoggerFactory.getLogger("queryForBean");
    Object getBean();
    default Object getValue(String property) {
        if (getBean() == null) {
            return null;
        }
        PropertyUtilsBean propertyUtilsBean = BeanUtilsBean.getInstance().getPropertyUtils();
        try {
            return propertyUtilsBean.getProperty(getBean(), property);
        } catch (Exception e) {
            logger.warn("get bean property {} error", property, e);
        }
        return null;
    }
}

接下来就搞定条件的设置接口:Conditional

对于Java8 Consumer接口 的知识预备,请查看 Predicate和Consumer接口– Java 8中java.util.function包下的接口

对于嵌套条件的设置,请查看org.hsweb.ezorm.core.NestConditional,

源码最后关于Supplier接口和BiConsumer<T, U>接口,不懂的请看Java 8之Stream的强大工具Collector

先把各种条件关键字用方法给设定出来,如,and(),or(),where(),以及最后条件追加,根据条件判断然后再确定追加与否这些情况进行设定等,同样支持直接拼接sql,代码如下:

* Copyright 2016 http://github.com/hs-web
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.hsweb.ezorm.core;
import org.hsweb.ezorm.core.param.TermType;
import org.hswebframwork.utils.StringUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BooleanSupplier;
import java.util.function.Consumer;
import java.util.function.Function;
public interface Conditional<T extends Conditional> extends TermTypeConditionalSupport {
    NestConditional<T> nest();
    NestConditional<T> nest(String column, Object value);
    NestConditional<T> orNest();
    NestConditional<T> orNest(String column, Object value);
    T and();
    T or();
    default T and(Consumer<Conditional> consumer) {
        consumer.accept(this.and());
        return (T) this;
    }
    default T or(Consumer<Conditional> consumer) {
        consumer.accept(this.or());
        return (T) this;
    }
    T and(String column, String termType, Object value);
    T or(String column, String termType, Object value);
    Accepter<T> getAccepter();
    default T where(String column, Object value) {
        return and(column, TermType.eq, value);
    }
    default T where() {
        return (T) this;
    }
    default  T where(Consumer<Conditional> consumer) {
        consumer.accept(this);
        return (T) this;
    }
    default T and(String column, Object value) {
        return and(column, TermType.eq, value);
    }
    default T is(String column, Object value) {
        return accept(column, TermType.eq, value);
    }
    default T or(String column, Object value) {
        return or(column, TermType.eq, value);
    }
    default T like(String column, Object value) {
        return accept(column, TermType.like, value);
    }
    default T like$(String column, Object value) {
        if (value == null)
            return like(column, null);
        return accept(column, TermType.like, StringUtils.concat(value, "%"));
    }
    default T $like(String column, Object value) {
        if (value == null)
            return like(column, null);
        return accept(column, TermType.like, StringUtils.concat("%", value));
    }
    default T $like$(String column, Object value) {
        if (value == null)
            return like(column, null);
        return accept(column, TermType.like, StringUtils.concat("%", value, "%"));
    }
    default T notLike(String column, Object value) {
        return accept(column, TermType.nlike, value);
    }
    default T gt(String column, Object value) {
        return accept(column, TermType.gt, value);
    }
    default T lt(String column, Object value) {
        return accept(column, TermType.lt, value);
    }
    default T gte(String column, Object value) {
        return accept(column, TermType.gte, value);
    }
    default T lte(String column, Object value) {
        return accept(column, TermType.lte, value);
    }
    default T in(String column, Object value) {
        return accept(column, TermType.in, value);
    }
    default T in(String column, Object... values) {
        return accept(column, TermType.in, values);
    }
    default T in(String column, Collection values) {
        return accept(column, TermType.in, values);
    }
    default T notIn(String column, Object value) {
        return accept(column, TermType.nin, value);
    }
    default T isEmpty(String column) {
        return accept(column, TermType.empty, 1);
    }
    default T notEmpty(String column) {
        return accept(column, TermType.nempty, 1);
    }
    default T isNull(String column) {
        return accept(column, TermType.isnull, 1);
    }
    default T notNull(String column) {
        return accept(column, TermType.notnull, 1);
    }
    default T not(String column, Object value) {
        return accept(column, TermType.not, value);
    }
    default T between(String column, Object between, Object and) {
        return accept(column, TermType.btw, Arrays.asList(between, and));
    }
    default T notBetween(String column, Object between, Object and) {
        return accept(column, TermType.nbtw, Arrays.asList(between, and));
    }
    default T accept(String column, String termType, Object value) {
        return getAccepter().accept(column, termType, value);
    }
    /**
     * 直接拼接sql,参数支持预编译
     * 例如
     * <ul>
     * <li>query.sql("name=?","admin")</li>
     * <li>query.sql("name=#{name}",{name:"admin"})</li>
     * <li>query.sql("name=#{[0]}",["admin"])</li>
     * </ul>
     *
     * @param sql    sql字符串
     * @param params 参数
     * @return {@link T}
     */
    T sql(String sql, Object... params);
    default <O> T each(Collection<O> list, BiConsumer<O, Conditional<T>> consumer) {
        if (null != list)
            list.forEach(o -> consumer.accept(o, this));
        return (T) this;
    }
    /**
     * 遍历一个集合,进行条件追加
     * 例如:<br>
     * query.or().each("areaId",[1,2,3],(query)->query::$like$)<br>
     * 将追加sql<br>
     * areaId like '%1%' or areaId like '%2%' or areaId like '%3%'
     *
     * @param column         要追加到的列名
     * @param list           集合
     * @param accepterGetter 追加方式函数
     * @return {@link T}
     * @see Function
     * @see Conditional
     * @see org.hsweb.ezorm.core.TermTypeConditionalSupport.SimpleAccepter
     */
    default T each(String column, Collection list, Function<Conditional<T>, SimpleAccepter<Conditional<T>>> accepterGetter) {
        if (null != list)
            list.forEach(o -> accepterGetter.apply(this).accept(column, o));
        return (T) this;
    }
    default T each(String column, String termType, Collection list, Function<Conditional<T>, Accepter<Conditional<T>>> accepterGetter) {
        if (null != list)
            list.forEach(o -> accepterGetter.apply(this).accept(column, termType, o));
        return (T) this;
    }
    /**
     * 参照 {@link Conditional#each(String, Collection, Function)}
     * 提供了一个valueMapper进行值转换如:
     * <br>
     * query.or().each("areaId",[1,2,3],(query)->query::$like$,(value)->","+value+",")<br>
     * 将追加sql<br>
     * areaId like '%,1,%' or areaId like '%,2,%' or areaId like '%,3,%'
     *
     * @param column         要追加到的列名
     * @param list           集合
     * @param accepterGetter 追加方式函数
     * @param valueMapper    值转换函数 {@link Function}
     * @return {@link T}
     * @see Function
     * @see Conditional
     * @see org.hsweb.ezorm.core.TermTypeConditionalSupport.SimpleAccepter
     */
    default T each(String column, Collection list, Function<Conditional<T>, SimpleAccepter<Conditional<T>>> accepterGetter, Function<Object, Object> valueMapper) {
        if (null != list)
            list.forEach(o -> accepterGetter.apply(this).accept(column, valueMapper.apply(o)));
        return (T) this;
    }
    default T each(String column, String termType, Collection list, Function<Conditional<T>, Accepter<Conditional<T>>> accepterGetter, Function<Object, Object> valueMapper) {
        if (null != list)
            list.forEach(o -> accepterGetter.apply(this).accept(column, termType, valueMapper.apply(o)));
        return (T) this;
    }
    /**
     * 遍历一个Map,进行条件追加
     *
     * @param mapParam map参数
     * @param accepter 追加方式函数
     * @return {@link T}
     * @see Function
     * @see Conditional
     * @see org.hsweb.ezorm.core.TermTypeConditionalSupport.SimpleAccepter
     */
    default T each(Map<String, Object> mapParam, Function<Conditional<T>, SimpleAccepter<Conditional<T>>> accepter) {
        if (null != mapParam)
            mapParam.forEach((k, v) -> accepter.apply(this).accept(k, v));
        return (T) this;
    }
    default T each(Map<String, Object> mapParam, String termType, Function<Conditional<T>, Accepter<Conditional<T>>> accepter) {
        if (null != mapParam)
            mapParam.forEach((k, v) -> accepter.apply(this).accept(k, termType, v));
        return (T) this;
    }
    /**
     * 指定一个前置条件,当条件满足的时候,调用回调进行自定义参数<br>
     * 如: query(age>10,query->query.gt("age",10))
     *
     * @param condition 前置条件
     * @param consumer  回调
     * @return {@link T}
     */
    default T when(boolean condition, Consumer<Conditional<T>> consumer) {
        if (condition) {
            consumer.accept(this);
        }
        return (T) this;
    }
    /**
     * 通过BooleanSupplier获取条件,例如<br>
     * query.when(()->age>10,query->query.gt("age",10));
     *
     * @see Conditional#when(boolean, Consumer)
     * @see BooleanSupplier
     */
    default T when(BooleanSupplier condition, Consumer<Conditional<T>> consumer) {
        return when(condition.getAsBoolean(), consumer);
    }
    /**
     * 指定前置条件,列名,参数值,条件构造函数。当条件满足的时候,执行构造器添加条件.例如<br>
     * query.when(age>10,"age",10,query->query::gt);<br>
     * 等同于<br>
     * if(age>10)query.gt(age,10);<br>
     *
     * @param condition 前置条件
     * @param column    要查询的列名
     * @param value     参数值
     * @param accepter  条件构造函数
     * @return {@link T}
     */
    default T when(boolean condition, String column, Object value, Function<Conditional<T>, SimpleAccepter<Conditional<T>>> accepter) {
        if (condition) {
            accepter.apply(this).accept(column, value);
        }
        return (T) this;
    }
    /**
     * 指定列名,参数值,条件判断函数,条件构造函数进行条件添加。如<br>
     * query.when("age",10,value->value>10,query->query::gt)
     *
     * @param column    列名
     * @param value     值
     * @param condition 条件判断函数
     * @param accepter  条件构造函数
     * @return {@link T}
     * @see Conditional#when(boolean, String, Object, Function)
     */
    default <V> T when(String column, V value, Function<V, Boolean> condition, Function<Conditional<T>, SimpleAccepter<Conditional<T>>> accepter) {
        return when(condition.apply(value), column, value, accepter);
    }
    /**
     * 功能与{@link Conditional#when(boolean, String, Object, Function)} 类似,可自定义termType 如:<br>
     * query.when(true,"age","like",10,query->query::or)
     *
     * @param condition 条件
     * @param column    列名
     * @param termType  条件类型
     * @param value     参数
     * @param accepter  条件构造函数
     * @return {@link T}
     * @see Conditional#when(boolean, String, Object, Function)
     */
    default T when(boolean condition, String column, String termType, Object value, Function<Conditional<T>, Accepter<Conditional<T>>> accepter) {
        if (condition) {
            accepter.apply(this).accept(column, termType, value);
        }
        return (T) this;
    }
    /**
     * 功能与{@link Conditional#when(String, Object, Function, Function)} 类似,可自定义termType 如:<br>
     * query.when("age","like",10,value->value==10,query->query::or)
     *
     * @param condition 条件
     * @param column    列名
     * @param termType  条件类型
     * @param value     参数
     * @param accepter  条件构造函数
     * @return {@link T}
     * @see Conditional#when(boolean, String, Object, Function)
     * @see TermType
     */
    default <V> T when(String column, String termType, V value, Function<V, Boolean> condition, Function<Conditional<T>, Accepter<Conditional<T>>> accepter) {
        return when(condition.apply(value), column, termType, value, accepter);
    }
}

因为之前有设计针对sql的直接封装,那么相应的增加SqlConditionSupport<T>

package org.hsweb.ezorm.core;
import org.hsweb.ezorm.core.param.SqlTerm;
import org.hsweb.ezorm.core.param.Term;
/**
 * @author zhouhao
 */
public abstract class SqlConditionSupport<T> {
    protected Term.Type nowTermType = Term.Type.and;
    protected abstract T addSqlTerm(SqlTerm term);
    public Term.Type getNowTermType() {
        return nowTermType;
    }
    protected T setOr() {
        nowTermType = Term.Type.or;
        return (T) this;
    }
    protected T setAnd() {
        nowTermType = Term.Type.and;
        return (T) this;
    }
    public T sql(String sql, Object... params) {
        SqlTerm sqlTerm = new SqlTerm();
        sqlTerm.setColumn(sql);
        sqlTerm.setValue(params);
        sqlTerm.setType(getNowTermType());
        return addSqlTerm(sqlTerm);
    }
}

2,对删,改,查的设计与实现

对改的接口设计Update:

具体不需要解释了,英文已经很清晰明白了

package org.hsweb.ezorm.core;
import org.hsweb.ezorm.core.param.UpdateParam;
import java.sql.SQLException;
public interface Update<T> extends Conditional<Update<T>>, TriggerSkipSupport<Update<T>> {
    Update<T> set(T data);
    Update<T> set(String property, Object value);
    Update<T> includes(String... fields);
    Update<T> excludes(String... fields);
    Update<T> setParam(UpdateParam param);
    int exec() throws SQLException;
}

实现类:

package org.hsweb.ezorm.rdb.simple;
import org.apache.commons.beanutils.BeanUtils;
import org.hsweb.ezorm.core.*;
import org.hsweb.ezorm.core.param.SqlTerm;
import org.hsweb.ezorm.core.param.UpdateParam;
import org.hsweb.ezorm.rdb.executor.SQL;
import org.hsweb.ezorm.rdb.executor.SqlExecutor;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import org.hsweb.ezorm.rdb.render.SqlRender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
/**
 * Created by zhouhao on 16-6-5.
 */
class SimpleUpdate<T> extends ValidatorAndTriggerSupport<Update<T>> implements Update<T> {
    private static final Logger logger = LoggerFactory.getLogger(Update.class);
    private UpdateParam    updateParam;
    private SimpleTable<T> table;
    private SqlExecutor    sqlExecutor;
    public SimpleUpdate(SimpleTable<T> table, SqlExecutor sqlExecutor) {
        this.table = table;
        this.sqlExecutor = sqlExecutor;
        updateParam = new UpdateParam();
    }
    @Override
    public Update<T> set(T data) {
        updateParam.setData(data);
        return this;
    }
    @Override
    public Update<T> set(String property, Object value) {
        if (updateParam.getData() == null) updateParam.setData(new HashMap<>());
        if (updateParam.getData() instanceof Map) {
            ((Map) updateParam.getData()).put(property, value);
        } else {
            try {
                BeanUtils.setProperty(updateParam.getData(), property, value);
            } catch (Exception e) {
                logger.warn("property error", e);
            }
        }
        return this;
    }
    @Override
    protected Update<T> addSqlTerm(SqlTerm term) {
        updateParam.addTerm(term);
        return this;
    }
    @Override
    public Update<T> includes(String... fields) {
        updateParam.includes(fields);
        return this;
    }
    @Override
    public Update<T> excludes(String... fields) {
        updateParam.excludes(fields);
        return this;
    }
    @Override
    public Update<T> and(String condition, String termType, Object value) {
        updateParam.and(condition, termType, value);
        return this;
    }
    @Override
    public Update<T> or(String condition, String termType, Object value) {
        updateParam.or(condition, termType, value);
        return this;
    }
    private Accepter accepter=this::and;
    @Override
    public Update<T> and() {
        setAnd();
        accepter = this::and;
        return this;
    }
    @Override
    public Update<T> or() {
        setOr();
        accepter = this::or;
        return this;
    }
    @Override
    public Accepter getAccepter() {
        return accepter;
    }
    @Override
    public NestConditional<Update<T>> nest() {
        return new SimpleNestConditional<>(this, updateParam.nest());
    }
    @Override
    public NestConditional<Update<T>> nest(String column, Object value) {
        return new SimpleNestConditional<>(this, updateParam.nest(column, value));
    }
    @Override
    public NestConditional<Update<T>> orNest() {
        return new SimpleNestConditional<>(this, updateParam.orNest());
    }
    @Override
    public NestConditional<Update<T>> orNest(String column, Object value) {
        return new SimpleNestConditional<>(this, updateParam.orNest(column, value));
    }
    @Override
    public Update<T> setParam(UpdateParam param) {
        this.updateParam = param;
        return this;
    }
    @Override
    public int exec() throws SQLException {
        boolean supportBefore = !triggerSkip && table.getMeta().triggerIsSupport(Trigger.update_before);
        boolean supportDone = !triggerSkip && table.getMeta().triggerIsSupport(Trigger.update_done);
        Map<String, Object> context = table.getDatabase().getTriggerContextRoot();
        if (supportBefore || supportDone) {
            context = table.getDatabase().getTriggerContextRoot();
            context.put("table", table);
            context.put("database", table.getDatabase());
            context.put("param"
        }
        if (supportBefore) {
            table.getMeta().on(Trigger.update_before, context);
        }
        SqlRender<UpdateParam> render = table.getMeta().getDatabaseMetaData().getRenderer(SqlRender.TYPE.UPDATE);
        SQL sql = render.render(table.getMeta(), updateParam);
        tryValidate(updateParam.getData(), Validator.Operation.UPDATE);
        int total = sqlExecutor.update(sql);
        if (supportDone) {
            context.put("total", total);
            table.getMeta().on(Trigger.update_done, context);
        }
        return total;
    }
    @Override
    RDBTableMetaData getTableMeta() {
        return table.getMeta();
    }
}

最关键的地方也就在于exec(),

boolean supportBefore = !triggerSkip && table.getMeta().triggerIsSupport(Trigger.update_before);

在触发条件不忽略,然后此table的元数据触发条件支持Trigger.update_before,返回true,调用过程如下图:

&amp;amp;amp;amp;lt;img src="https://pic1.zhimg.com/v2-a28cf7fb814e27d950940a380e72a4e0_b.png" data-rawwidth="956" data-rawheight="558" class="origin_image zh-lightbox-thumb" width="956" data-original="https://pic1.zhimg.com/v2-a28cf7fb814e27d950940a380e72a4e0_r.png"&amp;amp;amp;amp;gt;

同理,supportDone就不再解释了,

Map<String, Object> context = table.getDatabase().getTriggerContextRoot();其实就是产生一个map,具体源码如下:

public Map<String, Object> getTriggerContextRoot() {
        return new HashMap<>();
    }

符合supportBefore || supportDone条件,添加table,database,param信息

当符合supportBefore条件时,table.getMeta().on(Trigger.update_before, context);

&amp;amp;amp;amp;lt;img src="https://pic4.zhimg.com/v2-74cf3fa193ca2f8d57ab1bc1c914deef_b.png" data-rawwidth="1295" data-rawheight="437" class="origin_image zh-lightbox-thumb" width="1295" data-original="https://pic4.zhimg.com/v2-74cf3fa193ca2f8d57ab1bc1c914deef_r.png"&amp;amp;amp;amp;gt;

这里只看到了这一个脚本实现类,就顺带贴下

对后面代码:

SqlRender<UpdateParam> render = table.getMeta().getDatabaseMetaData().getRenderer(SqlRender.TYPE.UPDATE);
SQL sql = render.render(table.getMeta(), updateParam);
tryValidate(updateParam.getData(), Validator.Operation.UPDATE);
int total = sqlExecutor.update(sql);

下图RDBDatabaseMetaData 下面被掩盖的标记代码为public abstract SqlRender getRenderer(SqlRender.TYPE type);

&amp;amp;amp;amp;lt;img src="https://pic1.zhimg.com/v2-fb815df72a5288f26f9e37f3224c7894_b.png" data-rawwidth="1123" data-rawheight="776" class="origin_image zh-lightbox-thumb" width="1123" data-original="https://pic1.zhimg.com/v2-fb815df72a5288f26f9e37f3224c7894_r.png"&amp;amp;amp;amp;gt;

AbstractRDBDatabaseMetaData对RDBDatabaseMetaData进行抽象实现

在getRenderer()内得到相应数据库类型的render,在init()放入相应数据库类型的render

package org.hsweb.ezorm.rdb.render.dialect;
import org.hsweb.ezorm.rdb.meta.RDBDatabaseMetaData;
import org.hsweb.ezorm.rdb.render.SqlRender;
import org.hsweb.ezorm.rdb.render.support.simple.*;
import java.util.HashMap;
import java.util.Map;
public abstract class AbstractRDBDatabaseMetaData extends RDBDatabaseMetaData {
    protected Map<SqlRender.TYPE, SqlRender> renderMap = new HashMap<>();
    protected Dialect dialect;
    public AbstractRDBDatabaseMetaData(Dialect dialect) {
        this.dialect = dialect;
    }
    public void init() {
        putRenderer(SqlRender.TYPE.DELETE, new SimpleDeleteSqlRender(getDialect()));
        putRenderer(SqlRender.TYPE.INSERT, new SimpleInsertSqlRender());
        putRenderer(SqlRender.TYPE.SELECT, new SimpleSelectSqlRender(getDialect()));
        putRenderer(SqlRender.TYPE.UPDATE, new SimpleUpdateSqlRender(getDialect()));
        putRenderer(SqlRender.TYPE.SELECT_TOTAL, new SimpleSelectTotalSqlRender(getDialect()));
    }
    @Override
    public Dialect getDialect() {
        return dialect;
    }
    public SqlRender getRenderer(SqlRender.TYPE type) {
        SqlRender render = renderMap.get(type);
        if (render == null) throw new UnsupportedOperationException(type + " is not support");
        return render;
    }
    public void putRenderer(SqlRender.TYPE type, SqlRender sqlRender) {
        renderMap.put(type, sqlRender);
    }
}

最后再看具体实现类,此处拿MysqlRDBDatabaseMetaData为例

在此MysqlRDBDatabaseMetaData实例进行初始化时,设置MysqL数据库方言并会调用init()方法放入MysqL数据库类型的render

package org.hsweb.ezorm.rdb.render.dialect;
import org.hsweb.ezorm.rdb.render.SqlRender;
import org.hsweb.ezorm.rdb.render.support.mysql.MysqlDeleteSqlRender;
import org.hsweb.ezorm.rdb.render.support.mysql.MysqlMetaAlterRender;
import org.hsweb.ezorm.rdb.render.support.mysql.MysqlMetaCreateRender;
public class MysqlRDBDatabaseMetaData extends AbstractRDBDatabaseMetaData {
    private static final String DEFAULT_NAME = "mysql";
    private String name;
    @Override
    public void init() {
        super.init();
        renderMap.put(SqlRender.TYPE.META_CREATE, new
        renderMap.put(SqlRender.TYPE.DELETE, new MysqlDeleteSqlRender(getDialect()));
        renderMap.put(SqlRender.TYPE.META_ALTER, new MysqlMetaAlterRender(this));
    }
    public MysqlRDBDatabaseMetaData() {
        super(Dialect.MYSQL);
        name = DEFAULT_NAME;
        init();
    }
    @Override
    public String getName() {
        return name;
    }
}

对update sql语句的组合渲染:

首先设计一个其他类型语句共有的语句特性,比如指定了exclude 字段,没有指定include 字段

CommonSqlRender:具体逻辑如下,不仔细解释了

package org.hsweb.ezorm.rdb.render.support.simple;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.Correlation;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import org.hsweb.ezorm.core.param.Param;
import org.hsweb.ezorm.rdb.render.SqlRender;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
public abstract class CommonSqlRender<R extends Param> implements SqlRender<R> {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    public class OperationColumn {
        private String            tableName;
        private RDBColumnMetaData RDBColumnMetaData;
        public OperationColumn(String tableName, RDBColumnMetaData RDBColumnMetaData) {
            this.tableName = tableName;
            this.RDBColumnMetaData = RDBColumnMetaData;
            if (tableName == null) this.tableName = RDBColumnMetaData.getTableMetaData().getAlias();
        }
        public String getTableName() {
            return tableName;
        }
        public RDBColumnMetaData getRDBColumnMetaData() {
            return RDBColumnMetaData;
        }
    }
    public List<OperationColumn> parseOperationField(RDBTableMetaData metaData, R param) {
        Set<String> includes = param.getIncludes(),
                excludes = param.getExcludes();
        boolean includesIsEmpty = includes.isEmpty(),
                excludesIsEmpty = excludes.isEmpty();
        List<OperationColumn> tmp = new ArrayList<>();
        if ((includesIsEmpty && excludesIsEmpty)) {
            metaData.getColumns().forEach(column -> tmp.add(new OperationColumn(null, column)));
            return tmp;
        }
        //指定了exclude,没有指定include
        if (includesIsEmpty && !excludesIsEmpty) {
            boolean hasSelf = false;
            for (String exclude : excludes) {
                if (exclude.contains(".")) {
                  //表.*
                    includes.add(exclude.split("[.]")[0] + ".*");
                } else {
                  //不包含表. 就设置下面的*就好
                    hasSelf = true;
                }
            }
            if (hasSelf) includes.add("*");
            includesIsEmpty = false;
        }
        if (!includesIsEmpty) {
            includes.forEach(include -> {
                if (excludes.contains(include)) return;
                if ("*".equals(include)) {
                    metaData.getColumns().forEach(column -> {
                        if (excludes.contains(column.getAlias()) || excludes.contains(column.getName()))
                            return;
                        tmp.add(new OperationColumn(null, column));
                    });
                    return;
                }
                if (include.contains(".")) {
                    String[] columnInfo = include.split("[.]");
                    RDBTableMetaData table = metaData.getDatabaseMetaData().getTableMetaData(columnInfo[0]);
                    String tname = null;
                    if (null == table) {
                        Correlation correlation = metaData.getCorrelation(columnInfo[0]);
                        if (correlation != null) {
                            table = metaData.getDatabaseMetaData().getTableMetaData(correlation.getTargetTable());
                            tname = correlation.getAlias();
                        }
                    } 
                        tname = table.getAlias();
                    }
                    if (null == table) return;
                    if (columnInfo[1].equals("*"
                        String finalName = tname;
                        table.getColumns().forEach(column -> {
                            if
                                    || excludes.contains(finalName + "." + column.getName())
                                    || excludes.contains(finalName + "." + column.getAlias()))
                                return;
                            tmp.add(new OperationColumn(finalName, column));
                        });
                        return;
                    } else {
                        RDBColumnMetaData column = metaData.findColumn(include);
                        if (null != column) {
                            if (excludes.contains(column.getFullAliasName()) || excludes.contains(column.getFullName()))
                                return;
                            tmp.add(new OperationColumn(tname, column));
                        }
                    }
                } else {
                    RDBColumnMetaData column = metaData.findColumn(include);
                    if (null != column) {
                        if (excludes.contains(column.getAlias()) || excludes.contains(column.getName()))
                            return;
                        tmp.add(new OperationColumn(column.getTableMetaData().getAlias(), column));
                    }
                }
            });
        }
        if (tmp.isEmpty()) throw new UnsupportedOperationException("未找到任何查询字段!");
        return tmp;
    }
}

拼接sql准备:

package org.hsweb.ezorm.rdb.render;
import java.util.LinkedList;
/**
 * Created by 浩 on 2015-11-07 0007.
 */
public class SqlAppender extends LinkedList<String> {
    public SqlAppender() {
    }
    public SqlAppender(String sql) {
        add(sql);
    }
    public SqlAppender add(Object... str) {
        for (Object s : str) {
            this.add(String.valueOf(s));
        }
        return this
    }
    public SqlAppender addEdSpc(Object... str) {
        for (Object s : str) {
            this
        }
        this.add(" ");
        return this;
    }
    /**
     * 接入sql语句,并自动加入空格
     *
     * @param str
     * @return
     */
    public SqlAppender addSpc(Object... str) {
        for (Object s : str) {
            this.add(s);
            this.add(" ");
        }
        return this;
    }
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        this.forEach(builder::append);
        return builder.toString();
    }
}

where语句的共同部分进行抽象首先是Dialect的设定:

接口:

package org.hsweb.ezorm.rdb.render.dialect;
import org.hsweb.ezorm.core.param.Term;
import org.hsweb.ezorm.rdb.executor.SqlExecutor;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.parser.TableMetaParser;
import org.hsweb.ezorm.rdb.render.SqlAppender;
import org.hswebframwork.utils.StringUtils;
import java.sql.JDBCType;
import java.util.regex.Matcher;
import static org.hsweb.ezorm.rdb.executor.AbstractJdbcSqlExecutor.APPEND_PATTERN;
import static org.hsweb.ezorm.rdb.executor.AbstractJdbcSqlExecutor.PREPARED_PATTERN;
public interface Dialect {
    interface TermTypeMapper {
        SqlAppender accept(String wherePrefix, Term term, RDBColumnMetaData column, String tableAlias);
        static TermTypeMapper sql(String sql) {
            return (wherePrefix, term, column, tableAlias) -> new SqlAppender(sql);
        }
        static TermTypeMapper sql(String sql, Object param) {
            return (wherePrefix, term, column, tableAlias) -> {
                Object finalParam = param;
                String template = sql;
                //?方式预编译
                if (template.contains("?")) {
                    int index = 0;
                    while (template.contains("?")) {
                        template = template.replaceFirst("\\?", "#\\{[" + index++ + "]}");
                    }
                } else if (finalParam instanceof Object[]) {
                    Object[] array = ((Object[]) finalParam);
                    if (array.length == 1) {
                        finalParam = array[0];
                    }
                }
                Matcher prepared_matcher = PREPARED_PATTERN.matcher(template);
                Matcher append_matcher = APPEND_PATTERN.matcher(template);
                term.setValue(finalParam);
                while (append_matcher.find()) {
                    String group = append_matcher.group();
                    String reg = StringUtils.concat("\\$\\{", group.replace("$", "\\$").replace("[", "\\[").replace("]", "\\]"), "}");
                    String target = StringUtils.concat("\\$\\{", wherePrefix, group.startsWith("[") ? ".value" : ".value.", group, "}");
                    template = template.replaceFirst(reg, target);
                }
                while (prepared_matcher.find()) {
                    String group = prepared_matcher.group();
                    template = template.replaceFirst(StringUtils.concat("#\\{", group.replace("$", "\\$").replace("[", "\\[").replace("]", "\\]"), "}"),
                            StringUtils.concat("#\\{", wherePrefix, group.startsWith("[") ? ".value" : ".value.", group, "}"));
                }
                return new SqlAppender(template);
            };
        }
    }
    interface DataTypeMapper {
        String getDataType(RDBColumnMetaData columnMetaData);
    }
    interface ColumnMapper {
        String getColumn(RDBColumnMetaData columnMetaData);
    }
    void setTermTypeMapper(String termType, TermTypeMapper mapper);
    void setDataTypeMapper(JDBCType jdbcType, DataTypeMapper mapper);
    void setColumnMapper(String columnType, ColumnMapper mapper);
    String getQuoteStart();
    String getQuoteEnd();
    SqlAppender buildCondition(String wherePrefix, Term term, RDBColumnMetaData RDBColumnMetaData, String tableAlias);
    String buildDataType(RDBColumnMetaData columnMetaData);
    String doPaging(String sql, int pageIndex, int pageSize);
    boolean columnToUpperCase();
    default String buildColumnName(String tableName, String columnName) {
        if (StringUtils.isNullOrEmpty(tableName)) {
            return StringUtils.concat(getQuoteStart(), columnToUpperCase() ? columnName.toUpperCase() : columnName, getQuoteEnd());
        }
        return StringUtils.concat(tableName, ".", getQuoteStart(), columnToUpperCase() ? columnName.toUpperCase() : columnName, getQuoteEnd());
    }
    TableMetaParser getDefaultParser(SqlExecutor sqlExecutor);
    Dialect MYSQL  = new MysqlDialect();
    Dialect ORACLE = new OracleDialect();
    Dialect H2     = new H2Dialect();
    Dialect MSSQL = new MSSQLDialect();
}

默认实现DefaultDialect

其中TableMetaParser默认使用OracleTableMetaParser

package org.hsweb.ezorm.rdb.render.dialect;
import org.hsweb.ezorm.core.param.SqlTerm;
import org.hsweb.ezorm.core.param.Term;
import org.hsweb.ezorm.core.param.TermType;
import org.hsweb.ezorm.rdb.executor.SqlExecutor;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.parser.OracleTableMetaParser;
import org.hsweb.ezorm.rdb.meta.parser.TableMetaParser;
import org.hsweb.ezorm.rdb.render.SqlAppender;
import org.hswebframwork.utils.StringUtils;
import java.sql.JDBCType;
import java.util.*;
/**
 *
 */
public abstract class DefaultDialect implements Dialect {
    protected Map<String, TermTypeMapper> termTypeMappers       = new HashMap<>();
    protected Map<String, DataTypeMapper> dataTypeMappers       = new HashMap<>();
    protected DataTypeMapper              defaultDataTypeMapper = null;
    static final List<JDBCType> numberJdbcType = Arrays.asList(JDBCType.NUMERIC, JDBCType.INTEGER, JDBCType.BIGINT, JDBCType.TINYINT, JDBCType.DOUBLE, JDBCType.FLOAT);
    public DefaultDialect() {
        //默认查询条件支持
        termTypeMappers.put(TermType.eq, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), "=#{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.not, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), "!=#{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.like, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), " LIKE #{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.nlike, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), " NOT LIKE #{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.isnull, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), " IS NULL"));
        termTypeMappers.put(TermType.notnull, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), " IS NOT NULL"));
        termTypeMappers.put(TermType.gt, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), ">#{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.lt, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), "<#{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.gte, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), ">=#{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.lte, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), "<=#{", wherePrefix, ".value}"));
        termTypeMappers.put(TermType.empty, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), "=''"));
        termTypeMappers.put(TermType.nempty, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(buildColumnName(tableAlias, column.getName()), "!=''"));
        termTypeMappers.put(TermType.func, (wherePrefix, term, column, tableAlias) ->
                new SqlAppender().add(term.getValue()));
        termTypeMappers.put(TermType.btw, (wherePrefix, term, column, tableAlias) -> {
            SqlAppender sqlAppender = new SqlAppender();
            List<Object> objects = param2list(term.getValue(), column);
            if (objects.size() == 1)
                objects.add(objects.get(0));
            term.setValue(objects);
            sqlAppender.add(buildColumnName(tableAlias, column.getName()), " ").addSpc("BETWEEN")
                    .add("#{", wherePrefix, ".value[0]}")
                    .add(" AND ", "#{", wherePrefix, ".value[1]}");
            return sqlAppender;
        });
        termTypeMappers.put(TermType.nbtw, (wherePrefix, term, column, tableAlias) ->
        {
            SqlAppender sqlAppender = new SqlAppender();
            List<Object> objects = param2list(term.getValue(), column);
            if (objects.size() == 1
                objects.add(objects.get(0));
            term.setValue(objects);
            sqlAppender.add(buildColumnName(tableAlias, column.getName()), " ").addSpc("NOT BETWEEN")
                    .add("#{", wherePrefix, ".value[0]}")
                    .add(" AND ", "#{", wherePrefix, ".value[1]}");
            return sqlAppender;
        });
        termTypeMappers.put(TermType.in, (wherePrefix, term, column, tableAlias) -> {
            List<Object> values = param2list(term.getValue(), column);
            term.setValue(values);
            SqlAppender appender = new SqlAppender();
            appender.add(tableAlias, ".").addSpc(column.getName()).add("IN(");
            for (int i = 0; i < values.size(); i++) {
                appender.add("#{", wherePrefix, ".value[", i, "]}", ",");
            }
            appender.removeLast();
            appender.add(")");
            return appender;
        });
        termTypeMappers.put(TermType.nin, (wherePrefix, term, column, tableAlias) -> {
            List<Object> values = param2list(term.getValue(), column);
            term.setValue(values);
            SqlAppender appender = new SqlAppender();
            appender.add(tableAlias, ".").addSpc(column.getName()).add("NOT IN(");
            for (int i = 0; i < values.size(); i++) {
                appender.add("#{", wherePrefix, ".value[", i, "]}", ",");
            }
            appender.removeLast();
            appender.add(")");
            return appender;
        });
    }
    @Override
    public SqlAppender buildCondition(String wherePrefix, Term term, RDBColumnMetaData RDBColumnMetaData, String tableAlias) {
        if (term instanceof SqlTerm) {
            TermTypeMapper mapper = TermTypeMapper.sql(term.getColumn(), term.getValue());
            return
        }
        if (term.getValue() instanceof TermTypeMapper) {
            return
        }
        TermTypeMapper mapper = termTypeMappers.get(term.getTermType());
        if (mapper == null) mapper = termTypeMappers.get(TermType.eq);
        return mapper.accept(wherePrefix, term, RDBColumnMetaData, tableAlias);
    }
    protected List<Object> param2list(Object value, RDBColumnMetaData columnMetaData) {
        if (value == null) return new ArrayList<>();
        if (value instanceof List) return ((List) value);
        if (value instanceof Collection) return new ArrayList<>(((Collection) value));
        if (!(value instanceof Collection)) {
            if (value instanceof String) {
                String[] arr = ((String) value).split("[, ;]");
                Object[] objArr = new Object[arr.length];
                for (int i = 0; i < arr.length; i++) {
                    String str = arr[i];
                    Object val = str;
                    //数字类型
                    if (numberJdbcType.contains(columnMetaData.getJdbcType())) {
                        if (StringUtils.isInt(str))
                            val = StringUtils.toInt(str);
                        else if (StringUtils.isDouble(str))
                            val = StringUtils.toDouble(str);
                    }
                    objArr[i] = val;
                }
                return
            } else if (value.getClass().isArray()) {
                return Arrays.asList(((Object[]) value));
            } else {
                return new ArrayList<>(Arrays.asList(value));
            }
        }
        return new ArrayList<>();
    }
    @Override
    public void setTermTypeMapper(String termType, TermTypeMapper mapper) {
        termType = termType.toLowerCase();
        termTypeMappers.put(termType, mapper);
    }
    @Override
    public void setDataTypeMapper(JDBCType jdbcType, DataTypeMapper mapper) {
        dataTypeMappers.put(jdbcType.getName(), mapper);
    }
    @Override
    public void setColumnMapper(String columnType, ColumnMapper mapper) {
        // TODO: 16-10-28
    }
    @Override
    public String buildDataType(RDBColumnMetaData columnMetaData) {
        if (columnMetaData.getJdbcType() == null) return null;
        DataTypeMapper mapper = dataTypeMappers.get(columnMetaData.getJdbcType().getName());
        if (null == mapper) mapper = defaultDataTypeMapper;
        return mapper.getDataType(columnMetaData);
    }
    @Override
    public TableMetaParser getDefaultParser(SqlExecutor sqlExecutor) {
        return new OracleTableMetaParser(sqlExecutor);
    }
}

具体到相应数据库,这里拿MysqlDialect为例:

其实主要还是设置对应的数据类型

package org.hsweb.ezorm.rdb.render.dialect;
import org.hsweb.ezorm.rdb.executor.SqlExecutor;
import org.hsweb.ezorm.rdb.meta.parser.MysqlTableMetaParser;
import org.hsweb.ezorm.rdb.meta.parser.TableMetaParser;
import org.hswebframwork.utils.StringUtils;
import java.sql.JDBCType;
public class MysqlDialect extends DefaultDialect {
    protected MysqlDialect() {
        defaultDataTypeMapper = (meta) -> meta.getJdbcType().getName().toLowerCase();
        setDataTypeMapper(JDBCType.CHAR, (meta) -> StringUtils.concat("char(", meta.getLength(), ")"));
        setDataTypeMapper(JDBCType.VARCHAR, (meta) -> StringUtils.concat("varchar(", meta.getLength(), ")"));
        setDataTypeMapper(JDBCType.TIMESTAMP, (meta) -> "datetime");
        setDataTypeMapper(JDBCType.TIME, (meta) -> "time");
        setDataTypeMapper(JDBCType.DATE, (meta) -> "year");
        setDataTypeMapper(JDBCType.CLOB, (meta) -> "text");
        setDataTypeMapper(JDBCType.LONGVARBINARY, (meta) -> "longblob");
        setDataTypeMapper(JDBCType.LONGVARCHAR, (meta) -> "longtext");
        setDataTypeMapper(JDBCType.BLOB, (meta) -> "blob");
        setDataTypeMapper(JDBCType.BIGINT, (meta) -> "bigint");
        setDataTypeMapper(JDBCType.DOUBLE, (meta) -> "double");
        setDataTypeMapper(JDBCType.INTEGER, (meta) -> "int");
        setDataTypeMapper(JDBCType.NUMERIC, (meta) -> StringUtils.concat("decimal(", meta.getPrecision(), ",", meta.getScale(), ")"));
        setDataTypeMapper(JDBCType.DECIMAL, (meta) -> StringUtils.concat("decimal(", meta.getPrecision(), ",", meta.getScale(), ")"));
        setDataTypeMapper(JDBCType.TINYINT, (meta) -> "tinyint");
        setDataTypeMapper(JDBCType.BIGINT, (meta) -> "bigint");
        setDataTypeMapper(JDBCType.OTHER, (meta) -> "other");
    }
    @Override
    public String getQuoteStart() {
        return "`";
    }
    @Override
    public String getQuoteEnd() {
        return "`";
    }
    @Override
    public String doPaging(String sql, int pageIndex, int pageSize) {
        return new StringBuilder(sql)
                .append(" limit ")
                .append(pageSize * pageIndex)
                .append(",")
                .append(pageSize).toString();
    }
    @Override
    public boolean columnToUpperCase() {
        return false;
    }
    @Override
    public TableMetaParser getDefaultParser(SqlExecutor sqlExecutor) {
        return new MysqlTableMetaParser(sqlExecutor);
    }
}

这里漏说了一个表元素的解析:

先设计个接口

package org.hsweb.ezorm.rdb.meta.parser;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import java.sql.SQLException;
import java.util.List;
/**
 * Created by zhouhao on 16-6-5.
 */
public interface TableMetaParser {
    RDBTableMetaData parse(String name);
    boolean tableExists(String name);
    List<RDBTableMetaData> parseAll() throws SQLException;
}

抽出抽象部分:

package org.hsweb.ezorm.rdb.meta.parser;
import org.hsweb.commons.StringUtils;
import org.hsweb.ezorm.core.ObjectWrapper;
import org.hsweb.ezorm.rdb.executor.SqlExecutor;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import org.hsweb.ezorm.rdb.meta.expand.SimpleMapWrapper;
import org.hsweb.ezorm.rdb.render.dialect.Dialect;
import org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL;
import java.sql.JDBCType;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
public abstract class AbstractTableMetaParser implements TableMetaParser {
    Map<String, JDBCType> jdbcTypeMap = new HashMap<>();
    Map<JDBCType, Class>  javaTypeMap = new HashMap<>();
    protected SqlExecutor sqlExecutor;
    abstract Dialect getDialect();
    public AbstractTableMetaParser(SqlExecutor sqlExecutor) {
        this.sqlExecutor = sqlExecutor;
    }
    abstract String getTableMetaSql(String tname);
    abstract String getTableCommentSql(String tname);
    abstract String getAllTableSql();
    abstract String getTableExistsSql();
    @Override
    public boolean tableExists(String name) {
        try {
            Map<String, Object> param = new HashMap<>();
            param.put("table", name);
            Map<String, Object> res = sqlExecutor.single(new SimpleSQL(getTableExistsSql(), param), new LowerCasePropertySimpleMapWrapper());
            return res.get("total") != null && StringUtils.toInt(res.get("total")) > 0;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public RDBTableMetaData parse(String name) {
        if (!tableExists(name)) return null;
        RDBTableMetaData metaData = new RDBTableMetaData();
        metaData.setName(name);
        metaData.setAlias(name);
        Map<String, Object> param = new HashMap<>();
        param.put("table", name);
        try {
            List<RDBColumnMetaData> metaDatas = sqlExecutor.list(new SimpleSQL(getTableMetaSql(name), param), new RDBColumnMetaDataWrapper());
            metaDatas.forEach(metaData::addColumn);
            Map<String, Object> comment = sqlExecutor.single(new SimpleSQL(getTableCommentSql(name), param), new LowerCasePropertySimpleMapWrapper());
            if (null != comment && comment.get("comment") != null) {
                metaData.setComment(String.valueOf(comment.get("comment")));
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return metaData;
    }
    @Override
    public List<RDBTableMetaData> parseAll() throws SQLException {
        List<Map<String, Object>> tables = sqlExecutor.list(new SimpleSQL(getAllTableSql()), new LowerCasePropertySimpleMapWrapper());
        return tables.stream()
                .map(map -> (String) map.get("name"))
                .filter(Objects::nonNull)
                .map(this::parse).filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
    class LowerCasePropertySimpleMapWrapper extends SimpleMapWrapper {
        @Override
        public void wrapper(Map<String, Object> instance, int index, String attr, Object value) {
            attr = attr.toLowerCase();
            super.wrapper(instance, index, attr, value);
        }
    }
    class RDBColumnMetaDataWrapper implements ObjectWrapper<RDBColumnMetaData> {
        @Override
        public Class<RDBColumnMetaData> getType() {
            return RDBColumnMetaData.class;
        }
        @Override
        public RDBColumnMetaData newInstance() {
            return new RDBColumnMetaData();
        }
        @Override
        public void wrapper(RDBColumnMetaData instance, int index, String attr, Object value) {
            String stringValue;
            if (value instanceof String) {
                stringValue = ((String) value).toLowerCase();
            } else {
                stringValue = value == null ? "" : value.toString();
            }
            if (attr.equalsIgnoreCase("name")) {
                instance.setName(stringValue);
                instance.setProperty("old-name", stringValue);
            } else if (attr.equalsIgnoreCase("comment")) {
                instance.setComment(stringValue);
            } else {
                if (attr.toLowerCase().equals("not-null")) {
                    value = "1".equals(stringValue);
                    instance.setNotNull((boolean) value);
                }
                instance.setProperty(attr.toLowerCase(), value);
            }
        }
        @Override
        public void done(RDBColumnMetaData instance) {
            String data_type = instance.getProperty("data_type").toString().toLowerCase();
            int len = instance.getProperty("data_length").toInt();
            int data_precision = instance.getProperty("data_precision").toInt();
            int data_scale = instance.getProperty("data_scale").toInt();
            if (data_type == null) {
                data_type = "varchar";
            }
            instance.setLength(len);
            instance.setPrecision(data_precision);
            instance.setScale(data_scale);
            JDBCType jdbcType;
            try {
                jdbcType = JDBCType.valueOf(data_type.toUpperCase());
            } catch (Exception e) {
                jdbcType = jdbcTypeMap.get(data_type);
            }
            Class javaType = javaTypeMap.get(jdbcType);
            instance.setJdbcType(jdbcType);
            instance.setJavaType(javaType);
            instance.setDataType(getDialect().buildDataType(instance));
        }
    }
}

具体数据库完成具体部分MysqlTableMetaParser为例:

package org.hsweb.ezorm.rdb.meta.parser;
import org.hsweb.ezorm.rdb.executor.SqlExecutor;
import org.hsweb.ezorm.rdb.render.dialect.Dialect;
import org.hsweb.ezorm.rdb.render.dialect.MysqlDialect;
import java.sql.JDBCType;
/**
 * Created by zhouhao on 16-6-5.
 */
public class MysqlTableMetaParser extends AbstractTableMetaParser {
    static final String TABLE_META_SQL = " select " +
            "column_name as `name`, " +
            "data_type as `data_type`, " +
            "character_maximum_length as `data_length`, " +
            "numeric_precision as `data_precision`, " +
            "numeric_scale as `data_scale`, " +
            "column_comment as `comment`, " +
            "case when is_nullable='YES' then 0 else 1 end as 'not-null' " +
            "from information_schema.columns where table_schema=database() and table_name=#{table}";
    static final String TABLE_COMMENT_SQL = " select " +
            "table_comment as `comment` " +
            "from information_schema.tables where table_name=#{table}";
    static final String ALL_TABLE_SQL = "select table_name as `name` from information_schema.`TABLES` where table_schema=database()";
    static final String TABLE_EXISTS_SQL = "select count(1) as 'total' from information_schema.`TABLES` where table_schema=database() and table_name=#{table}";
    public MysqlTableMetaParser(SqlExecutor sqlExecutor) {
        super(sqlExecutor);
        jdbcTypeMap.put("int", JDBCType.INTEGER);
        jdbcTypeMap.put("year", JDBCType.TIME);
        jdbcTypeMap.put("datetime", JDBCType.TIMESTAMP);
        jdbcTypeMap.put("text", JDBCType.CLOB);
    }
    @Override
    Dialect getDialect() {
        return Dialect.MYSQL;
    }
    @Override
    String  
        return TABLE_META_SQL;
    }
    @Override
    String getTableCommentSql(String tname) 
        return
    }
    @Override
    String getAllTableSql() 
        return
    }
    @Override
    String getTableExistsSql() 
        return
    }
}

其次是SimpleWhereSqlBuilder:

package org.hsweb.ezorm.rdb.render.support.simple;
import org.hsweb.ezorm.core.param.SqlTerm;
import org.hsweb.ezorm.core.param.Term;
import org.hsweb.ezorm.core.param.TermType;
import org.hsweb.ezorm.rdb.meta.Correlation;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import org.hsweb.ezorm.rdb.render.SqlAppender;
import org.hsweb.ezorm.rdb.render.dialect.Dialect;
import org.hswebframwork.utils.StringUtils;
import java.util.List;
import java.util.Set;
public abstract class SimpleWhereSqlBuilder {
    protected String getTableAlias(RDBTableMetaData metaData, String field) {
        if (field.contains("."))
            field = field.split("[.]")[0];
        else return metaData.getAlias();
        Correlation correlation = metaData.getCorrelation(field);
        if (correlation != null) return correlation.getAlias();
        return metaData.getAlias();
    }
    public void buildWhere(RDBTableMetaData metaData, String prefix,
                           List<Term> terms, SqlAppender appender,
                           Set<String> needSelectTable) {
        if (terms == null || terms.isEmpty()) return;
        int index = -1;
        String prefixTmp = StringUtils.concat(prefix, StringUtils.isNullOrEmpty(prefix) ? "" : ".");
        for (Term term : terms) {
            index++;
            boolean nullTerm = StringUtils.isNullOrEmpty(term.getColumn());
            RDBColumnMetaData column = metaData.findColumn(term.getColumn());
            //不是空条件 也不是可选字段
            if (!nullTerm && column == null && term.getTermType() != TermType.func && !(term instanceof SqlTerm)) continue;
            //不是空条件,值为空
            if (!nullTerm && StringUtils.isNullOrEmpty(term.getValue())) continue;
            //是空条件,但是无嵌套
            if (nullTerm && term.getTerms().isEmpty()) continue;
            String tableAlias = null;
            if (column != null) {
                tableAlias = getTableAlias(metaData, term.getColumn());
                needSelectTable.add(tableAlias);
                //转换参数的值
                term.setValue(transformationValue(column, term.getValue()));
            }
            //用于sql预编译的参数名
            prefix = StringUtils.concat(prefixTmp, "terms[", index, "]");
            //添加类型,and 或者 or
            appender.add(StringUtils.concat(" ", term.getType().toString().toUpperCase(), " "));
            if (!term.getTerms().isEmpty()) {
                //构建嵌套的条件
                SqlAppender nest = new SqlAppender();
                buildWhere(metaData, prefix, term.getTerms(), nest, needSelectTable);
                //如果嵌套结果为空,
                if (nest.isEmpty()) {
                    appender.removeLast();//删除最后一个(and 或者 or)
                    continue;
                }
                if (nullTerm) {
                    //删除 第一个(and 或者 or)
                    nest.removeFirst();
                }
                appender.add("(");
                if (!nullTerm)
                    appender.add(getDialect().buildCondition(prefix, term, column, tableAlias));
                appender.addAll(nest);
                appender.add(")");
            } else {
                if (!nullTerm)
                    appender.add(getDialect().buildCondition(prefix, term, column, tableAlias));
            }
        }
    }
    protected Object transformationValue(RDBColumnMetaData column, Object value) {
        if (value != null && column.getValueConverter() != null) {
            value = column.getValueConverter().getData(value);
        }
        if (value != null && column.getOptionConverter() != null) {
            Object tmp = column.getOptionConverter().converterData(value);
            if (null != tmp) value = tmp;
        }
//        JDBCType type = column.getJdbcType();
//
//        if (type == null) return value;
//        switch (type) {
//            case INTEGER:
//            case NUMERIC:
//                if (StringUtils.isInt(type)) return StringUtils.toInt(value);
//                if (StringUtils.isDouble(type)) return StringUtils.toDouble(value);
//                break;
//            case TIMESTAMP:
//            case TIME:
//            case DATE:
//                if (!(value instanceof Date)) {
//                    String strValue = String.valueOf(value);
//                    Date date = DateTimeUtils.formatUnknownString2Date(strValue);
//                    if (date != null) return date;
//                }
//                break;
//        }
        return value;
    }
    public abstract Dialect getDialect();
}

拼接出的sql封装:

关联查询sql:

package org.hsweb.ezorm.rdb.executor;
/**
 * Created by 浩 on 2015-11-06 0006.
 */
public class BindSQL {
    private SQL sql;
    private String toField;
    public SQL getSql() {
        return sql;
    }
    public void setSql(SQL sql) {
        this.sql = sql;
    }
    public String getToField() {
        return toField;
    }
    public void setToField(String toField) {
        this.toField = toField;
    }
}

定义SQL封装接口:

package org.hsweb.ezorm.rdb.executor;
import java.util.List;
public interface SQL {
    /**
     * 获取sql语句模板
     *
     * @return sql语句模板
     */
    String getSql();
    /**
     * 获取预编译参数
     *
     * @return
     */
    Object getParams();
    /**
     * 获取关联查询的sql
     *
     * @return
     */
    List<BindSQL> getBinds();
    int size();
}

具体实现:

package org.hsweb.ezorm.rdb.render.support.simple;
import org.hsweb.ezorm.rdb.executor.BindSQL;
import org.hsweb.ezorm.rdb.executor.SQL;
import java.util.HashMap;
import java.util.List;
/**
 * Created by zhouhao on 16-6-4.
 */
public class SimpleSQL implements SQL {
    private String sql;
    private Object param;
    private List<BindSQL> bindSQLs;
    public SimpleSQL(String sql, Object param) {
        this.sql = sql;
        this.param = param;
    }
    public SimpleSQL(String sql) {
        this.sql = sql;
        this.param = new HashMap<>();
    }
    @Override
    public String getSql() {
        return sql;
    }
    @Override
    public Object getParams() {
        return param;
    }
    @Override
    public List<BindSQL> getBinds() {
        return bindSQLs;
    }
    public void setBindSQLs(List<BindSQL> bindSQLs) {
        this.bindSQLs = bindSQLs;
    }
    @Override
    public int size() {
        return bindSQLs == null ? 1 : bindSQLs.size() + 1;
    }
    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append(sql).append("\n").append(param);
        return builder.toString();
    }
}

回到SimpleUpdateSqlRender实现:

package org.hsweb.ezorm.rdb.render.support.simple;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.hsweb.ezorm.core.param.Term;
import org.hsweb.ezorm.core.param.UpdateParam;
import org.hsweb.ezorm.rdb.executor.SQL;
import org.hsweb.ezorm.rdb.meta.RDBColumnMetaData;
import org.hsweb.ezorm.rdb.meta.RDBTableMetaData;
import org.hsweb.ezorm.rdb.render.SqlAppender;
import org.hsweb.ezorm.rdb.render.dialect.Dialect;
import java.util.*;
import java.util.stream.Collectors;
/**
 * Created by zhouhao on 16-6-4.
 */
public class SimpleUpdateSqlRender extends CommonSqlRender<UpdateParam> {
    class SimpleUpdateSqlRenderProcess extends SimpleWhereSqlBuilder {
        private RDBTableMetaData      metaData;
        private UpdateParam           param;
        private List<OperationColumn> updateField;
        private SqlAppender whereSql       = new SqlAppender();
        private Set<String> conditionTable = new LinkedHashSet<>();
        PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils();
        public SimpleUpdateSqlRenderProcess(RDBTableMetaData metaData, UpdateParam param) {
            this.metaData = metaData;
            this.param = param.clone();
          //先得到条件
            List<Term> terms = param.getTerms();
          //对包含条件进行过滤转换得到一个list
            terms = terms.stream().filter(term -> term.getColumn() == null || !term.getColumn().contains(".")).collect(Collectors.toList());
            param.setTerms(terms);
            //解析要操作的字段
            this.updateField = parseOperationField(metaData, param);
            //解析查询条件
            buildWhere(metaData, "", param.getTerms(), whereSql, conditionTable);
            if (!whereSql.isEmpty()) whereSql.removeFirst();
        }
        public SQL process() {
            SqlAppender appender = new SqlAppender();
            appender.add("UPDATE ", metaData.getName(), " ", metaData.getAlias(), " SET ");
            byte[] bytes = new byte[1];
            Map<String, Object> valueProxy = new HashMap<>();
            updateField.forEach(operationColumn -> {
                RDBColumnMetaData column = operationColumn.getRDBColumnMetaData();
                if (column.getProperty("read-only").isTrue()) return;
                try {
                    String dataProperty = column.getAlias();
                    Object value = null;
                    try {
                        value = propertyUtils.getProperty(param.getData(), dataProperty);
                    } catch (Exception e) {
                    }
                    if (value == null && !column.getAlias().equals(column.getName())) {
                        dataProperty = column.getName();
                        try {
                            value = propertyUtils.getProperty(param.getData(), dataProperty);
                        } catch (Exception e) {
                        }
                    }
                    if (value == null) {
                        if (logger.isInfoEnabled())
                            logger.info("跳过修改列:[{}], 属性[{}]为null!", column.getName(), column.getAlias());
                        return;
                    }
                    if (column.getValueConverter() != null) {
                        Object new_value = column.getValueConverter().getData(value);
                        if (column.getOptionConverter() != null) {
                            new_value = column.getOptionConverter().converterData(new_value);
                        }
                        if (value != new_value && !value.equals(new_value)) {
                            // propertyUtils.setProperty(param.getData(), dataProperty, new_value);
                            value = new_value;
                        }
                    }
                    valueProxy.put(dataProperty, value);
                    appender.add(dialect.buildColumnName(null, column.getName()), "=")
                            .addAll(getParamString("data.".concat(dataProperty), column));
                    appender.add(",");
                    bytes[0]++;
                } catch (Exception e) {
                    if (logger.isInfoEnabled())
                        logger.info("跳过修改列:[{}], 可能属性[{}]不存在!", column.getName(), column.getAlias());
                }
            });
            if (bytes[0] == 0) throw new IndexOutOfBoundsException("没有列被修改!");
            appender.removeLast();
            if (whereSql.isEmpty()) {
                throw new UnsupportedOperationException("禁止执行未设置任何条件的修改操作!");
            }
            appender.add(" WHERE ", "").addAll(whereSql);
            String sql = appender.toString();
            param.setData(valueProxy);
            SimpleSQL simpleSQL = new SimpleSQL(sql, param);
            return simpleSQL;
        }
        @Override
        public Dialect getDialect() {
            return dialect;
        }
    }
    protected SqlAppender getParamString(String paramName, RDBColumnMetaData rdbColumnMetaData) {
        return new SqlAppender().add("#{", paramName, "}");
    }
    @Override
    public SQL render(RDBTableMetaData metaData, UpdateParam param) {
        return new SimpleUpdateSqlRenderProcess(metaData, param).process();
    }
    public SimpleUpdateSqlRender(Dialect dialect) {
        this.dialect = dialect;
    }
    private Dialect dialect;
    public Dialect getDialect() {
        return dialect;
    }
    public void setDialect(Dialect dialect) {
        this.dialect = dialect;
    }
}

终于得到 了sql,最后,验证之后执行sql语句:设定执行器接口SqlExecutor:

/*
 * Copyright 2016 http://github.com/hs-web
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.hsweb.ezorm.rdb.executor;
import org.hsweb.ezorm.core.ObjectWrapper;
import org.hsweb.ezorm.rdb.meta.expand.SimpleMapWrapper;
import org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
 * SQL执行器,用于执行sql
 *
 * @author zhouhao
 * @since 1.0
 */
public interface SqlExecutor {
    SimpleMapWrapper mapWrapper = new SimpleMapWrapper();
    /**
     * 传入SQL对象和对象包装器执行查询,将查询结果通过对象包装器进行包装后返回
     *
     * @param sql     sql对象 参照{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @param wrapper 执行结果对象包装器 参照{@link org.hsweb.ezorm.rdb.meta.expand.SimpleMapWrapper}
     * @param <T>     查询结果类型泛型
     * @return 查询结果
     * @throws SQLException 执行查询异常
     */
    <T> List<T> list(SQL sql, ObjectWrapper<T> wrapper) throws SQLException;
    /**
     * 传入SQL对象和对象包装器执行查询,将查询结果通过对象包装器进行包装后返回
     * 只返回单个结果,如果sql结果存在多个值,则返回首个值
     *
     * @param sql     sql对象 参照{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @param wrapper 对象包装其
     * @param <T>     查询结果类型泛型
     * @return 查询结果
     * @throws SQLException 执行查询异常
     */
    <T> T single(SQL sql, ObjectWrapper<T> wrapper) throws SQLException;
    /**
     * 执行sql
     *
     * @param sql sql对象 参照{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @throws SQLException 执行异常
     */
    void exec(SQL sql) throws SQLException;
    /**
     * 执行update
     *
     * @param sql sql对象 参照{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @return 执行sql后影响的行数
     * @throws SQLException 执行异常
     */
    int update(SQL sql) throws SQLException;
    /**
     * 执行delete
     *
     * @param sql sql对象 参照{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @return 执行sql后影响的行数
     * @throws SQLException 执行异常
     */
    int delete(SQL sql) throws SQLException;
    /**
     * 执行insert
     *
     * @param sql sql对象 参照{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @return 执行sql后影响的行数
     * @throws SQLException 执行异常
     */
    int insert(SQL sql) throws SQLException;
    boolean tableExists(String tableName) throws SQLException;
    default List<Map<String, Object>> list(SQL sql) throws SQLException {
        return list(sql, mapWrapper);
    }
    default List<Map<String, Object>> list(String sql, Object params) throws SQLException {
        return list(new SimpleSQL(sql, params));
    }
    default List<Map<String, Object>> list(String sql) throws SQLException {
        return list(new SimpleSQL(sql));
    }
    default Map<String, Object> single(SQL sql) throws SQLException {
        return single(sql, mapWrapper);
    }
    default Map<String, Object> single(String sql, Object params) throws SQLException {
        return single(new SimpleSQL(sql, params));
    }
    default Map<String, Object> single(String sql) throws SQLException {
        return single(new SimpleSQL(sql));
    }
    default int insert(String sql, Object params) throws SQLException {
        return insert(new SimpleSQL(sql, params));
    }
    default int update(String sql, Object params) throws SQLException {
        return update(new SimpleSQL(sql, params));
    }
    default int update(String sql) throws SQLException {
        return update(new SimpleSQL(sql));
    }
    default int delete(String sql, Object params) throws SQLException {
        return delete(new SimpleSQL(sql, params));
    }
    default int delete(String sql) throws SQLException {
        return delete(new SimpleSQL(sql));
    }
    default void exec(String sql) throws SQLException {
        exec(new SimpleSQL(sql));
    }
}

JDBC 通用sql执行器

/*
 * Copyright 2016 http://github.com/hs-web
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.hsweb.ezorm.rdb.executor;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.hsweb.ezorm.core.ObjectWrapper;
import org.hsweb.ezorm.core.param.Term;
import org.hswebframwork.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.sql.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * JDBC 通用sql执行器,用于执行sql.支持参数化预编译
 *
 * @author zhouhao
 * @since 1.0
 */
public abstract class AbstractJdbcSqlExecutor implements SqlExecutor {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    /**
     * 获取jdbc链接,由子类实现
     *
     * @return jdbc 链接
     */
    public abstract Connection getConnection();
    /**
     * 直接拼接sql的编译表达式: ${}
     *
     * @since 1.0
     */
    public static final Pattern APPEND_PATTERN = Pattern.compile("(?<=\\$\\{)(.+?)(?=\\})");
    /**
     * 进行参数预编译的表达式:#{}
     *
     * @since 1.0
     */
    public static final Pattern PREPARED_PATTERN = Pattern.compile("(?<=#\\{)(.+?)(?=\\})");
    /**
     * 对象属性操作工具
     *
     * @see PropertyUtilsBean
     */
    protected PropertyUtilsBean propertyUtils = BeanUtilsBean.getInstance().getPropertyUtils();
    protected Object getSqlParamValue(Object param, String paramName) {
        try {
            Object obj = propertyUtils.getProperty(param, paramName);
            if (obj instanceof Term)
                obj = ((Term) obj).getValue();
            return obj;
        } catch (Exception e) {
            logger.warn("获取sql参数失败", e);
        }
        return null;
    }
    /**
     * 将sql模板编译为sql信息
     * 模板语法:${}代表直接拼接sql,#{}使用预编译
     * 如: 模板参数为:{name:"张三",age:10},sql为:select * from user where name=#{name} and age=${age}
     * 将被编译为:select * from user where name=? and age=10。 参数列表:["张三"]
     *
     * @param sql sql模板 ,参考{@link org.hsweb.ezorm.rdb.render.support.simple.SimpleSQL}
     * @return sql 编译好的信息
     */
    public SQLInfo compileSql(SQL sql) {
        String sqlTemplate = sql.getSql();
        try {
            SQLInfo sqlInfo = new SQLInfo();
            Object param = sql.getParams();
            Matcher prepared_matcher = PREPARED_PATTERN.matcher(sqlTemplate);
            Matcher append_matcher = APPEND_PATTERN.matcher(sqlTemplate);
            List<Object> params = new LinkedList<>();
            //直接拼接sql
            while (append_matcher.find()) {
                String group = append_matcher.group();
                Object obj = getSqlParamValue(param, group);
                sqlTemplate = sqlTemplate.replaceFirst(StringUtils.concat("\\$\\{", escapeExprSpecialWord(group), "\\}"), String.valueOf(obj));
            }
            //参数预编译sql
            while (prepared_matcher.find()) {
                String group = prepared_matcher.group();
                sqlTemplate = sqlTemplate.replaceFirst(StringUtils.concat("#\\{", escapeExprSpecialWord(group), "\\}"), "?");
                Object obj = getSqlParamValue(param, group);
                params.add(obj);
            }
            sqlInfo.setSql(sqlTemplate);
            sqlInfo.setParam(params.toArray());
            return sqlInfo;
        } catch (Exception e) {
            logger.error("compile sql  {}  error", sqlTemplate, e);
            throw e;
        }
    }
    /**
     * 释放连接,在执行完sql后,将释放此链接
     */
    public abstract void releaseConnection(Connection connection) throws SQLException;
    @Override
    public <T> List<T> list(SQL sql, ObjectWrapper<T> wrapper) throws SQLException {
        if (sql instanceof EmptySQL) return new ArrayList<>();
        //将sql模板编译为可执行的sql
        SQLInfo info = compileSql(sql);
        printSql(info);//打印sql信息
        Connection connection = getConnection();
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        List<T> datas = new ArrayList<>();
        try {
            //预编译SQL
            statement = connection.prepareStatement(info.getSql());
            this.preparedParam(statement, info);
            //执行sql
            resultSet = statement.executeQuery();
            ResultSetMetaData metaData = resultSet.getMetaData();
            int count = metaData.getColumnCount();
            //获取到执行sql后返回的列信息
            List<String> headers = new ArrayList<>();
            for (int i = 1; i <= count; i++) {
                headers.add(metaData.getColumnLabel(i));
            }
            wrapper.setUp(headers);
            int index = 0;
            while (resultSet.next()) {
                //调用包装器,将查询结果包装为对象
                T data = wrapper.newInstance();
                for (int i = 0; i < headers.size(); i++) {
                    Object value = resultSet.getObject(i + 1);
                    wrapper.wrapper(data, index, headers.get(i), value);
                }
                index++;
                wrapper.done(data);
                datas.add(data);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("<==      total: {}", index);
            }
        } finally {
            closeResultSet(resultSet);
            closeStatement(statement);
            //重置JDBC链接
            releaseConnection(connection);
        }
        return datas;
    }
    protected void closeResultSet(ResultSet resultSet) {
        try {
            if (null != resultSet)
                resultSet.close();
        } catch (SQLException e) {
            logger.error("close ResultSet error", e);
        }
    }
    protected void closeStatement(Statement statement) {
        try {
            if (null != statement)
                statement.close();
        } catch (SQLException e) {
            logger.error("close ResultSet error", e);
        }
    }
    @Override
    public <T> T single(SQL sql, ObjectWrapper<T> wrapper) throws SQLException {
        if (sql instanceof EmptySQL) return null;
        SQLInfo info = compileSql(sql);
        printSql(info);
        Connection connection = getConnection();
        PreparedStatement statement = null;
        ResultSet resultSet = null;
        T data = null;
        try {
            statement = connection.prepareStatement(info.getSql());
            //预编译参数
            this.preparedParam(statement, info);
            resultSet = statement.executeQuery();
            ResultSetMetaData metaData = resultSet.getMetaData();
            int count = metaData.getColumnCount();
            List<String> headers = new ArrayList<>();
            for (int i = 1; i <= count; i++) {
                headers.add(metaData.getColumnLabel(i));
            }
            wrapper.setUp(headers);
            int index = 0;
            if (resultSet.next()) {
                data = wrapper.newInstance();
                for (int i = 0; i < headers.size(); i++) {
                    Object value = resultSet.getObject(i + 1);
                    wrapper.wrapper(data, index, headers.get(i), value);
                }
                index++;
                wrapper.done(data);
            }
            if (logger.isDebugEnabled()) {
                logger.debug("<==      total: {}", index);
            }
        } finally {
            closeResultSet(resultSet);
            closeStatement(statement);
            releaseConnection(connection);
        }
        return data;
    }
    @Override
    public void exec(SQL sql) throws SQLException {
        if (sql instanceof EmptySQL) return;
        SQLInfo info = compileSql(sql);
        printSql(info);
        Connection connection = getConnection();
        PreparedStatement statement = null;
        try {
            statement = connection.prepareStatement(info.getSql());
            //预编译参数
            this.preparedParam(statement, info);
            statement.execute();
            if (sql.getBinds() != null) {
                for (BindSQL bindSQL : sql.getBinds()) {
                    exec(bindSQL.getSql());
                }
            }
        } finally {
            closeStatement(statement);
            releaseConnection(connection);
        }
    }
    @Override
    public int update(SQL sql) throws SQLException {
        if (sql instanceof EmptySQL) return 0;
        SQLInfo info = compileSql(sql);
        printSql(info);
        Connection connection = getConnection();
        int i = 0;
        try {
            PreparedStatement statement = connection.prepareStatement(info.getSql());
            this.preparedParam(statement, info);
            i = statement.executeUpdate();
            if (logger.isDebugEnabled())
                logger.debug("<==    updated: {} rows", i);
            closeStatement(statement);
        } finally {
            releaseConnection(connection);
        }
        return i;
    }
    @Override
    public int delete(SQL sql) throws SQLException {
        if (sql instanceof EmptySQL) return 0;
        SQLInfo info = compileSql(sql);
        printSql(info);
        Connection connection = getConnection();
        int i = 0;
        try {
            PreparedStatement statement = connection.prepareStatement(info.getSql());
            this.preparedParam(statement, info);
            i = statement.executeUpdate();
            if (sql.getBinds() != null) {
                for (BindSQL bindSQL : sql.getBinds()) {
                    i += delete(bindSQL.getSql());
                }
                return i;
            }
            if (logger.isDebugEnabled())
                logger.debug("<==     delete: {} rows", i);
            closeStatement(statement);
        } finally {
            releaseConnection(connection);
        }
        return i;
    }
    @Override
    public int insert(SQL sql) throws SQLException {
        return update(sql);
    }
    @Override
    public boolean tableExists(String tname) throws SQLException {
        Connection connection = getConnection();
        try {
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet resultSet = metaData
                    .getTables(connection.getCatalog(), null, tname.toUpperCase(), null);
            if (resultSet.next()) return true;
            else {
                resultSet = metaData
                        .getTables(connection.getCatalog(), null, tname.toLowerCase(), null);
            }
            if (resultSet.next()) return true;
        } finally {
            releaseConnection(connection);
        }
        return false;
    }
    /**
     * 预编译参数
     *
     * @param statement
     * @param info
     * @throws Exception
     */
    protected void preparedParam(PreparedStatement statement, SQLInfo info) throws SQLException {
        int index = 1;
        //预编译参数
        for (Object object : info.getParam()) {
            if (object instanceof Date)
                statement.setTimestamp(index++, new java.sql.Timestamp(((Date) object).getTime()));
            else if (object instanceof byte[]) {
                statement.setBlob(index++, new ByteArrayInputStream((byte[]) object));
            } else
                statement.setObject(index++, object);
        }
    }
    protected void printSql(SQLInfo info) {
        if (logger.isDebugEnabled()) {
            logger.debug("==>  Preparing: {}", info.getSql());
            if (info.getParam() != null && info.getParam().length > 0) {
                logger.debug("==> Parameters: {}", info.paramsString());
                String sim = info.getSql();
                Object[] param = info.getParam();
                for (int i = 0; i < param.length; i++) {
                    Object obj = param[i];
                    try {
                        sim = sim.replaceFirst("\\?", obj instanceof Number ? String.valueOf(obj) : "'".concat(escapeExprSpecialWord(String.valueOf(obj))).concat("'"));
                    } catch (Exception e) {
                    }
                }
                logger.debug("==>  Simulated: {}", sim);
            }
        }
    }
    public static String escapeExprSpecialWord(String keyword) {
        if (!StringUtils.isNullOrEmpty(keyword)) {
            String[] fbsArr = {"\\", "$", "(", ")", "*", "+", ".", "[", "]", "?", "^", "{", "}", "|"};
            for (String key : fbsArr) {
                if (keyword.contains(key)) {
                    keyword = keyword.replace(key, "\\" + key);
                }
            }
        }
        return keyword;
    }
    public static class SQLInfo {
        /**
         * sql语句
         */
        private String sql;
        /**
         * 参数列表
         */
        private Object[] param;
        /**
         * 参数字符串
         */
        private String paramString;
        public String getSql() {
            return sql;
        }
        public void setSql(String sql) {
            this.sql = sql;
        }
        public Object[] getParam() {
            return param;
        }
        public void setParam(Object[] param) {
            this.param = param;
        }
        public String paramsString() {
            if (getParam() == null
                return "";
            if (paramString == null
                StringBuilder builder = new StringBuilder();
                int i = 0;
                for (Object param : getParam()) {
                    if (i++ != 0
                        builder.append(","
                    builder.append(String.valueOf(param));
                    builder.append(
                    builder.append(param == null ? 
                    builder.append(")");
                }
                paramString = builder.toString();
            }
            return paramString;
        }
    }
}

至此,关于改终于分析完毕



原文链接:hsweb的系列学习——hsweb-easy-orm分析