这边文章介绍了一个jdbc中通用的插入值映射工具。
/**
*
*/
package com.cmc.tools.jdbc;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
import com.google.common.collect.Maps;
/**
* @desc 通用抽象参数设置器
* 可以将model里的参数设置到预编译SQL中去>
* @author cmc
* @email [email protected]
* @date 2019年8月21日 上午9:37:50
*/
public class AdbCommonInsertSetter<T> implements BatchPreparedStatementSetter{
private List<T> list ; //要插入的数据
private Map<String, String> replaceMap ; //需要改名的字段map
private String [] excludes ; //需要排除的字段
public AdbCommonInsertSetter(List<T> list) {
this.list=list;
}
public AdbCommonInsertSetter(List<T> list, String... excludes) {
this.list=list;
this.excludes=excludes;
}
public AdbCommonInsertSetter(List<T> list, Map<String, String> replaceMap) {
this.list = list;
this.replaceMap = replaceMap;
}
public AdbCommonInsertSetter(List<T> list, Map<String, String> replaceMap, String... excludes) {
this.list = list;
this.replaceMap = replaceMap;
this.excludes = excludes;
}
@Override
public void setValues(PreparedStatement ps, int i) throws SQLException {
T model = list.get(i) ;
Map<String,String> paramMap = getParamMap(model, excludes) ;
int index = 1 ;
for(String name : paramMap.keySet()) {
String type = paramMap.get(name) ;
switch(type) {
case "java.lang.String" : {
ps.setString(index, getParamValue(name, model) == null ? null : getParamValue(name, model));
}break ;
case "byte" : {
ps.setByte(index, getParamValue(name, model) == null ? null : Byte.parseByte(getParamValue(name, model)));
}break ;
case "short" : {
ps.setShort(index, getParamValue(name, model) == null ? null : Short.parseShort(getParamValue(name, model)));
}break ;
case "int" : {
ps.setInt(index, getParamValue(name, model) == null ? null : Integer.parseInt(getParamValue(name, model)));
}break ;
case "long" : {
ps.setLong(index, getParamValue(name, model) == null ? null : Long.parseLong(getParamValue(name, model)));
}break ;
case "float" : {
ps.setFloat(index, getParamValue(name, model) == null ? null : Float.parseFloat(getParamValue(name, model)));
}break ;
case "double" : {
ps.setDouble(index, getParamValue(name, model) == null ? null : Double.parseDouble(getParamValue(name, model)));
}break ;
case "char" : {
ps.setString(index, getParamValue(name, model) == null ? null : getParamValue(name, model));
}break ;
case "boolean" : {
ps.setBoolean(index, getParamValue(name, model) == null ? null : Boolean.parseBoolean(getParamValue(name, model)));
}break ;
case "java.time.LocalDateTime" : {
ps.setTimestamp(index, getParamValue(name, model) == null ? null : Timestamp.valueOf(LocalDateTime.parse(getParamValue(name, model))));
}break ;
case "java.time.LocalDate" : {
ps.setTimestamp(index, getParamValue(name, model) == null ? null : Timestamp.valueOf(LocalDate.parse(getParamValue(name, model)).atStartOfDay()));
}break ;
//其他类型一律按String处理
default : {
ps.setString(index, getParamValue(name, model) == null ? null : getParamValue(name, model));
}
}
index ++ ;
}
}
/**
* 功能: 反射获取所有参数类型和参数名(参数类型-参数名)
* @param model 要传入数据的模型
* @param exclude 需要排除的字段
* 有一些字段模型里边有但是数据库里没有(例如发票里的rechargeTradeId字段),可以使用这个参数把这些参数排除
* @return
*/
private Map<String , String> getParamMap(T model, String [] excludes) {
Map<String, String> map = Maps.newHashMap() ;
Field[] fields = model.getClass().getDeclaredFields() ;
for(Field field : fields) {
String name = field.getName() ;
//判断是否跳过该字段
if(excludes != null && isExclude(excludes, name)) {
continue ;
}
//若map中有替换的参数名,则替换
if(replaceMap != null && replaceMap.get(name) != null) {
map.put(replaceMap.get(name), field.getGenericType().getTypeName()) ;
}else {
map.put(name, field.getGenericType().getTypeName()) ;
}
}
//方法名按首字母排序
Map<String, String> sortedMap = Maps.newLinkedHashMap() ;
map.entrySet()
.stream()
.sorted(Map.Entry.<String,String>comparingByKey())
.forEachOrdered(e -> sortedMap.put(e.getKey(), e.getValue()));
return sortedMap ;
}
/**
* 功能: 根据参数名获取参数值
* @param fieldName 要获取的参数名
* @param model 要获取参数值的运行时模型
* @return
*/
private String getParamValue(String fieldName, T model) {
String value = null ;
//如果之前有替换参数名,取值的时候需要把参数名替换回去,否则取不到数
fieldName = getOriginalName(fieldName) ;
try {
Field field = model.getClass().getDeclaredField(fieldName) ;
String methodName = "" ;
//特殊处理boolean类型
if(field.getType().getName().equals("boolean")) {
methodName = "is" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1) ;
}else {
methodName = "get" + Character.toUpperCase(fieldName.charAt(0)) + fieldName.substring(1) ;
}
Method method = model.getClass().getMethod(methodName) ;
value = method.invoke(model) == null ? null : method.invoke(model).toString() ;
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchFieldException e) {
e.printStackTrace();
}
return value ;
}
/**
* 功能: 判断是否排除该字段
* @param excludes
* @param name
* @return
*/
private static boolean isExclude(String[] excludes, String name) {
for(String exclude : excludes) {
if(name.equals(exclude))
return true ;
}
return false;
}
@Override
public int getBatchSize() {
return list.size();
}
/**
* 功能: 获取替换之前原始参数名
* @param name 替换后参数名
* @return 替换之前参数名
*/
public String getOriginalName(String name) {
if(replaceMap == null)
return name ;
for(Entry<String, String> entry : replaceMap.entrySet()) {
if(entry.getValue().equals(name)) {
name = entry.getKey() ;
return name ;
}
}
return name ;
}
}