补充文档注释
parent
bd08be5928
commit
6b5bcf0b5c
|
@ -16,49 +16,78 @@
|
|||
|
||||
package xyz.zhouxy.jdbc;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.OptionalDouble;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.OptionalLong;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import com.google.common.annotations.Beta;
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.AbstractMapWrapper;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.plusone.commons.util.OptionalTools;
|
||||
import xyz.zhouxy.plusone.commons.util.StringTools;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* DbRecord
|
||||
*
|
||||
* <p>
|
||||
* 封装 Map<String, Object>,表示一条 DB 记录
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Beta
|
||||
public class DbRecord extends AbstractMapWrapper<String, Object, DbRecord> {
|
||||
|
||||
public DbRecord() {
|
||||
super(new HashMap<>(), k -> Preconditions.checkArgument(StringTools.isNotBlank(k), "Key must has text."), null);
|
||||
super(new HashMap<>(),
|
||||
k -> AssertTools.checkArgument(StringTools.isNotBlank(k), "Key must has text."),
|
||||
null);
|
||||
}
|
||||
|
||||
public DbRecord(Map<String, Object> map) {
|
||||
super(map, k -> Preconditions.checkArgument(StringTools.isNotBlank(k), "Key must has text."), null);
|
||||
super(map,
|
||||
k -> AssertTools.checkArgument(StringTools.isNotBlank(k), "Key must has text."),
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值强转为 {@link String},并放在 {@link Optional} 中。
|
||||
* 如果 {@code key} 存在,而值不存在,则返回 {@link Optional#empty()}。
|
||||
*/
|
||||
public Optional<String> getValueAsString(String key) {
|
||||
return this.getAndConvert(key);
|
||||
}
|
||||
|
||||
public <T> List<T> getValueAsList(String key) {
|
||||
return this.<Collection<T>>getAndConvert(key)
|
||||
.map(l -> (l instanceof List) ? (List<T>) l : new ArrayList<>(l))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
|
||||
public <T> Set<T> getValueAsSet(String key) {
|
||||
return this.<Collection<T>>getAndConvert(key)
|
||||
.map(l -> (l instanceof Set) ? (Set<T>) l : new HashSet<>(l))
|
||||
.orElse(Collections.emptySet());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值强转为 {@code int},并放在 {@link OptionalInt} 中。
|
||||
* 如果 {@code key} 存在,而值不存在,则返回 {@link OptionalInt#empty()}。
|
||||
*/
|
||||
@Nonnull
|
||||
public OptionalInt getValueAsInt(String key) {
|
||||
return OptionalTools.toOptionalInt(this.getAndConvert(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值强转为 {@code long},并放在 {@link OptionalLong} 中。
|
||||
* 如果 {@code key} 存在,而值不存在,则返回 {@link OptionalLong#empty()}。
|
||||
*/
|
||||
@Nonnull
|
||||
public OptionalLong getValueAsLong(String key) {
|
||||
return OptionalTools.toOptionalLong(this.getAndConvert(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 将值强转为 {@code double},并放在 {@link OptionalDouble} 中。
|
||||
* 如果 {@code key} 存在,而值不存在,则返回 {@link OptionalDouble#empty()}。
|
||||
*/
|
||||
@Nonnull
|
||||
public OptionalDouble getValueAsDouble(String key) {
|
||||
return OptionalTools.toOptionalDouble(this.getAndConvert(key));
|
||||
}
|
||||
|
|
|
@ -35,9 +35,28 @@ import javax.annotation.Nullable;
|
|||
|
||||
import com.google.common.base.CaseFormat;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.annotation.StaticFactoryMethod;
|
||||
|
||||
/**
|
||||
* DefaultBeanRowMapper
|
||||
*
|
||||
* <p>
|
||||
* 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* <b>NOTE: 使用反射获取类型信息,也是使用反射调用无参构造器和 {@code setter} 方法。
|
||||
* 实际使用中还是建议针对目标类型自定义 {@link RowMapper}。</b>
|
||||
* </p>
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
||||
|
||||
/** Bean 的无参构造器 */
|
||||
private final Constructor<T> constructor;
|
||||
|
||||
/** 列名到属性的映射 */
|
||||
private final Map<String, PropertyDescriptor> colPropertyMap;
|
||||
|
||||
private DefaultBeanRowMapper(Constructor<T> constructor, Map<String, PropertyDescriptor> colPropertyMap) {
|
||||
|
@ -45,10 +64,29 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
|||
this.colPropertyMap = colPropertyMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 DefaultBeanRowMapper
|
||||
*
|
||||
* @param <T> Bean 类型
|
||||
* @param beanType Bean 类型
|
||||
* @return DefaultBeanRowMapper 对象
|
||||
* @throws SQLException 创建 DefaultBeanRowMapper 出现错误的异常时抛出
|
||||
*/
|
||||
@StaticFactoryMethod(DefaultBeanRowMapper.class)
|
||||
public static <T> DefaultBeanRowMapper<T> of(Class<T> beanType) throws SQLException {
|
||||
return of(beanType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个 DefaultBeanRowMapper
|
||||
*
|
||||
* @param <T> Bean 类型
|
||||
* @param beanType Bean 类型
|
||||
* @param propertyColMap Bean 字段与列名的映射关系。key 是字段,value 是列名。
|
||||
* @return DefaultBeanRowMapper 对象
|
||||
* @throws SQLException 创建 DefaultBeanRowMapper 出现错误的异常时抛出
|
||||
*/
|
||||
@StaticFactoryMethod(DefaultBeanRowMapper.class)
|
||||
public static <T> DefaultBeanRowMapper<T> of(Class<T> beanType, @Nullable Map<String, String> propertyColMap)
|
||||
throws SQLException {
|
||||
try {
|
||||
|
@ -60,6 +98,7 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
|||
BeanInfo beanInfo = Introspector.getBeanInfo(beanType);
|
||||
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
||||
|
||||
// Bean 的属性名为小驼峰,对应的列名为下划线
|
||||
Function<? super PropertyDescriptor, String> keyMapper;
|
||||
if (propertyColMap == null || propertyColMap.isEmpty()) {
|
||||
keyMapper = p -> CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, p.getName());
|
||||
|
@ -84,13 +123,17 @@ public class DefaultBeanRowMapper<T> implements RowMapper<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/** {@inheritDoc} */
|
||||
@Override
|
||||
public T mapRow(ResultSet rs, int rowNumber) throws SQLException {
|
||||
try {
|
||||
// 调用无参构造器创建实例
|
||||
T newInstance = this.constructor.newInstance();
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
// 遍历结果的每一列
|
||||
for (int i = 1; i <= metaData.getColumnCount(); i++) {
|
||||
String colName = metaData.getColumnName(i);
|
||||
// 获取查询结果列名对应的属性,调用 setter
|
||||
PropertyDescriptor propertyDescriptor = this.colPropertyMap.get(colName);
|
||||
if (propertyDescriptor != null) {
|
||||
Method setter = propertyDescriptor.getWriteMethod();
|
||||
|
|
|
@ -27,12 +27,21 @@ import java.util.OptionalLong;
|
|||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
|
||||
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
|
||||
import xyz.zhouxy.plusone.commons.util.ArrayTools;
|
||||
import xyz.zhouxy.plusone.commons.util.AssertTools;
|
||||
import xyz.zhouxy.plusone.commons.util.OptionalTools;
|
||||
|
||||
/**
|
||||
* ParamBuilder
|
||||
*
|
||||
* <p>
|
||||
* JDBC 参数构造器,将数据转换为 {@code Object[]} 类型,以传给 {@link PreparedStatement}
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
public class ParamBuilder {
|
||||
public static final Object[] EMPTY_OBJECT_ARRAY = {};
|
||||
|
||||
|
@ -60,8 +69,8 @@ public class ParamBuilder {
|
|||
}
|
||||
|
||||
public static <T> List<Object[]> buildBatchParams(final Collection<T> c, final Function<T, Object[]> func) {
|
||||
Preconditions.checkNotNull(c, "The collection can not be null.");
|
||||
Preconditions.checkNotNull(func, "The func can not be null.");
|
||||
AssertTools.checkNotNull(c, "The collection can not be null.");
|
||||
AssertTools.checkNotNull(func, "The func can not be null.");
|
||||
if (CollectionTools.isEmpty(c)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,21 @@ package xyz.zhouxy.jdbc;
|
|||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* ResultHandler
|
||||
*
|
||||
* <p>
|
||||
* 处理 {@link ResultSet}
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ResultHandler<T> {
|
||||
|
||||
/**
|
||||
* 将 {@link ResultSet} 转换为指定类型的对象
|
||||
*/
|
||||
T handle(ResultSet resultSet) throws SQLException;
|
||||
}
|
||||
|
|
|
@ -22,10 +22,21 @@ import java.sql.SQLException;
|
|||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* RowMapper
|
||||
*
|
||||
* <p>
|
||||
* {@link ResultSet} 中每一行数据的处理逻辑。
|
||||
* </p>
|
||||
*
|
||||
* @author <a href="http://zhouxy.xyz:3000/ZhouXY108">ZhouXY</a>
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RowMapper<T> {
|
||||
T mapRow(ResultSet rs, int rowNumber) throws SQLException;
|
||||
|
||||
/** 每一行数据转换为 {@link HashMap} */
|
||||
public static final RowMapper<Map<String, Object>> HASH_MAP_MAPPER = (rs, rowNumber) -> {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
ResultSetMetaData metaData = rs.getMetaData();
|
||||
|
@ -37,13 +48,16 @@ public interface RowMapper<T> {
|
|||
return result;
|
||||
};
|
||||
|
||||
/** 每一行数据转换为 {@link DbRecord} */
|
||||
public static final RowMapper<DbRecord> RECORD_MAPPER =
|
||||
(rs, rowNumber) -> new DbRecord(HASH_MAP_MAPPER.mapRow(rs, rowNumber));
|
||||
|
||||
/** 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 */
|
||||
public static <T> RowMapper<T> beanRowMapper(Class<T> beanType) throws SQLException {
|
||||
return DefaultBeanRowMapper.of(beanType);
|
||||
}
|
||||
|
||||
/** 默认实现的将 {@link ResultSet} 转换为 Java Bean 的 {@link RowMapper}。 */
|
||||
public static <T> RowMapper<T> beanRowMapper(Class<T> beanType, Map<String, String> propertyColMap)
|
||||
throws SQLException {
|
||||
return DefaultBeanRowMapper.of(beanType, propertyColMap);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue