首次写博客,不喜勿喷。
升级mybatis版本到3.3.1以上, 升级版本可能会出现问题,比如mapper.xml中集合和字符串做比较会出现异常,如以下xml片段:
<if test="underPersons != '' underPersons != null">
and user.id in
<foreach collection="underPersons" item="userid">
#{userid}
foreach>
if>
调用方法出现错误提示:mybatis invalid comparison: java.util.arraylist and java.lang.string
這个方案方便快捷,但前提是mapper.xml写的内容规范
修改mybatis源码,原理暂时没有时间写,先给方案吧,方案如下:
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
List
package com.calm.erp.pageutil;
import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Properties;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@Intercepts({ @Signature(method = "prepare", type = StatementHandler.class, args = { Connection.class }) })
public class PageInterceptor implements Interceptor {
private static Logger LOGGER = LoggerFactory.getLogger(PageInterceptor.class);
private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
/**
* 拦截后要执行的方法
*/
public Object intercept(Invocation invocation) throws Throwable {
StatementHandler statementHandler = (StatementHandler) invocation
.getTarget();
MetaObject metaStatementHandler = MetaObject.forObject(
statementHandler, DEFAULT_OBJECT_FACTORY,
DEFAULT_OBJECT_WRAPPER_FACTORY);
MappedStatement mappedStatement = (MappedStatement) metaStatementHandler
.getValue("delegate.mappedStatement");
//针对批量插入不返回主键问题做修改,修改mappedStatement的keyGenerator为自定义的keyGenerator
if( ArrayUtils.isNotEmpty(mappedStatement.getKeyProperties()) && SqlCommandType.INSERT.equals(mappedStatement.getSqlCommandType())){
//重点就在这 利用java反射修改mappedStatement的keyGenerator,修改为我们自定义的Jdbc3KeyGenerator
ReflectUtil.setFieldOjectValue(mappedStatement, "keyGenerator", new Jdbc3KeyGenerator());
}
return invocation.proceed();
}
/**
* 利用反射进行操作的一个工具类
*
*/
private static class ReflectUtil {
/**
* 利用反射获取指定对象里面的指定属性
*
* @param obj
* 目标对象
* @param fieldName
* 目标属性
* @return 目标字段
*/
private static Field getField(Object obj, String fieldName) {
Field field = null;
for (Class> clazz = obj.getClass(); clazz != Object.class; clazz = clazz
.getSuperclass()) {
try {
field = clazz.getDeclaredField(fieldName);
break;
} catch (NoSuchFieldException e) {
// 这里不用做处理,子类没有该字段可能对应的父类有,都没有就返回null。
}
}
return field;
}
/**
* 利用反射设置指定对象的指定属性为指定的值 值为object对象
*
* @param obj
* 目标对象
* @param fieldName
* 目标属性
* @param fieldValue
* 目标值
*/
public static void setFieldOjectValue(Object obj, String fieldName,
Object fieldValue) {
Field field = ReflectUtil.getField(obj, fieldName);
if (field != null) {
try {
field.setAccessible(true);
field.set(obj, fieldValue);
} catch (IllegalArgumentException | IllegalAccessException e) {
LOGGER.error("" ,e);
}
}
}
}
}
<plugins>
<plugin interceptor="com.calm.erp.pageutil.PageInterceptor" />
plugins>
<insert id="batchAddCommercial" parameterType="java.util.List" useGeneratedKeys="true" keyProperty="id">
insert into erp_crm_commercial
(dept_id,commercial_name,sales_status,
commercial_address,memo,source,source_first,status,update_time,updator_id,updator_name,create_time,creator_id,
creator_name,regist_time,business_duty,sales_id,divert_user_id,commercial_intention,city_id,city_name,province_id,
province_name,dist_id,dist_name,advisory_thing,fault_type,assigned_state,business_type,assigned_way) values
<foreach collection="list" index="index" item="item" separator=",">
( #{item.deptId},#{item.commercialName},#{item.salesStatus},#{item.commercialAddress},#{item.memo},#{item.source},#{item.sourceFirst},0,now(),#{item.updatorId},#{item.updatorName},
now(),#{item.creatorId},#{item.creatorName},#{item.registTime},#{item.businessDuty},#{item.salesId},#{item.divertUserId},#{item.commercialIntention},#{item.cityId},#{item.cityName},#{item.provinceId},
#{item.provinceName},#{item.distId},#{item.distName},#{item.advisoryThing},#{item.faultType},#{item.assignedState},#{item.businessType},#{item.assignedWay})
foreach>
insert>
其实第二种方式有一个非常简单的办法,只是不怎么优雅,也说说吧,写一个和源码一模一样的类,包路径也和源码保持一致,只需要修改processAfter方法,和上面的一样,java会优先使用我们自己写的类