![JAR search and dependency download from the Maven repository](/logo.png)
org.zodiac.mybatisplus.interceptor.MyBatisPreparedBeanMapperInterceptor Maven / Gradle / Ivy
package org.zodiac.mybatisplus.interceptor;
import java.util.Iterator;
import java.util.Objects;
import java.util.Properties;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
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.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.zodiac.commons.logging.SmartSlf4jLogger;
import org.zodiac.commons.logging.SmartSlf4jLoggerFactory;
import org.zodiac.commons.remote.bridge.RpcContextHolderBridges;
import org.zodiac.commons.remote.bridge.RpcContextIamSecurityBridges;
import org.zodiac.commons.support.PageHolder;
import org.zodiac.commons.util.BeanUtil;
import org.zodiac.commons.util.IdGenerator;
import org.zodiac.mybatis.constants.MyBatisConstants;
import org.zodiac.mybatisplus.base.BaseEntity;
import org.zodiac.mybatisplus.base.BaseEntityInternalUtil;
import org.zodiac.sdk.toolkit.util.lang.NumUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
/**
* General {@link BaseEntity} property functions handle interceptors in a unified
* way, for example, generating IDs for insertion methods (supports local or
* remote generators)
*
*
* In mybatis, there are four types that can be intercepted (in the order of
* interception type):
*
* Executor:Method of intercepting actuator
* ParameterHandler:Processing of interception parameters
* ResultHandler:Processing of interception result set
* StatementHandler:Processing of intercepting SQL syntax construction
*
* @see https://www.jianshu.com/p/0a72bb1f6a21
* @see https://cloud.tencent.com/developer/article/1170370
*/
@Intercepts({ @Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }),
@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class, RowBounds.class,
ResultHandler.class }) })
public class MyBatisPreparedBeanMapperInterceptor implements Interceptor {
protected final SmartSlf4jLogger log = SmartSlf4jLoggerFactory.getLogger(getClass());
private IdGenerator idGenerator;
public MyBatisPreparedBeanMapperInterceptor(IdGenerator idGenerator) {
this.idGenerator = idGenerator;
}
@Override
public Object plugin(Object target) {
if (target instanceof Executor) {
return Plugin.wrap(target, this);
} else {
return target;
}
}
@Override
public void setProperties(Properties properties) {
}
@Override
public Object intercept(Invocation invoc) throws Throwable {
if (Objects.isNull(invoc.getArgs())) {
return invoc.proceed();
}
MappedStatement statement = (MappedStatement) invoc.getArgs()[0];
SqlCommandType command = statement.getSqlCommandType();
/*Prepared properties.*/
preProcess(invoc, command);
/*Invoke mapper process*/
final Object result = invoc.proceed();
/*Post properties.*/
return postProcess(invoc, command, result);
}
/**
* Pre query properties set. (if necessary).
*
* @param invoc Invocation
*/
protected void preQuery(Invocation invoc) {
/*
* Note: In order to be compatible with the distributed microservice
* architecture, it is not the best solution to convert the bean time
* returned by Dao layer here. Because Dao layer may not be able to
* obtain the I18N language of the current user, it is finally decided
* to migrate to the web layer.
*/
if (Objects.isNull(PageHelper.getLocalPage())) {
/*Not paging*/
/*Obtain page from rpc context.*/
PageHolder.Page> page = PageHolder.InternalUtil.current(false);
if (Objects.nonNull(page)) {
log.debug("Begin current paging of: {}", page);
PageHelper.startPage(page.getPageNum(), page.getPageSize(), page.isCount());
}
}
}
/**
* Pre updation properties set.(if necessary).
*
* @param invoc invocation
*/
protected void preUpdate(Invocation invoc) {
for (int i = 1; i < invoc.getArgs().length; i++) {
Object arg = invoc.getArgs()[i];
if (BaseEntity.class.isAssignableFrom(arg.getClass())) {
BaseEntity bean = (BaseEntity) arg;
if (isUpdateSettable(bean)) {
bean.preUpdate();
bean.setUpdateUser(getCurrentPrincipalId());
}
break;
}
}
}
/**
* Pre insertion properties set.(if necessary).
*
* @param invoc Invocation
*/
@SuppressWarnings("rawtypes")
protected void preInsert(Invocation invoc) {
/*Sets insert properties*/
for (int i = 1; i < invoc.getArgs().length; i++) {
Object arg = invoc.getArgs()[i];
if (BaseEntity.class.isAssignableFrom(arg.getClass())) {
doPreInsert(invoc, (BaseEntity) arg);
} else if (Iterable.class.isAssignableFrom(arg.getClass())) {/*e.g: UserDao#insertBatch(List)*/
Iterator it = ((Iterable) arg).iterator();
while (it.hasNext()) {
Object value = it.next();
if (BaseEntity.class.isAssignableFrom(value.getClass())) {
doPreInsert(invoc, (BaseEntity) arg);
}
}
}
}
}
protected void doPreInsert(Invocation invoc, BaseEntity bean) {
/*Assign sets primary key ID.*/
if (!Objects.isNull(bean) && Objects.isNull(bean.getId())) {
bean.setId(idGenerator.nextId(bean));
log.debug("Dynamic assigned primary key ID for: {}, method: {}", bean.getId(), invoc.getMethod());
}
if (isInsertSettable(bean)) {
bean.preInsert();
Long currentPrincipalId = getCurrentPrincipalId();
bean.setCreateUser(Objects.isNull(currentPrincipalId) ? MyBatisConstants.UNKNOWN_USER_ID : currentPrincipalId);
bean.setUpdateUser(bean.getCreateUser());
}
}
/**
* Post query properties set. (if necessary)
*
* @param invoc Invocation
* @param result pre-processed result
* @return processed result
*/
protected Object postQuery(Invocation invoc, Object result) {
if (Objects.isNull(result)) {
return null;
}
/*Update executed paging info to rpc server context.*/
if (result instanceof Page) {
com.github.pagehelper.Page> helperPage = (com.github.pagehelper.Page>) result;
PageHolder.Page> currentPage = PageHolder.InternalUtil.current(false);
if (Objects.nonNull(currentPage)) {
BeanUtil.copyProperties(helperPage, currentPage);
/*
Rebind executed page information to rpc server context.
Ensure that the information that has been paged can be obtained on the consumer service side.
*/
PageHolder.InternalUtil.bind(true, currentPage);
/*Update current executed paging info.*/
PageHolder.InternalUtil.update();
log.debug("End current paging of: {}", currentPage);
}
}
return result;
}
/**
* Post updation properties set.(if necessary)
*
* @param invoc Invocation
* @param result pre-processed result
* @return processed result
*/
protected Object postUpdate(Invocation invoc, Object result) {
return result;
}
/**
* Post insertion properties set.(if necessary)
*
* @param invoc Invocation
* @param result pre-processed result
* @return processed result
*/
protected Object postInsert(Invocation invoc, Object result) {
if (Objects.isNull(result)) {
return null;
}
/*Sets the primary key value generated by inserted SQL to return to the caller.*/
for (int i = 1; i < invoc.getArgs().length; i++) {
Object arg = invoc.getArgs()[i];
if (BaseEntity.class.isAssignableFrom(arg.getClass())) {
BaseEntity bean = (BaseEntity) arg;
if (RpcContextHolderBridges.hasRpcContextHolderClass()) { /*Distributed(cluster)?*/
RpcContextHolderBridges.invokeSet(true, BaseEntityInternalUtil.CURRENT_BEANID_KEY, bean.getId());
}
}
}
return result;
}
/**
* Check whether parameter properties need to be set when insertion.
*
* @param bean BaseEntity
* @return inserting fields is settable
*/
protected boolean isInsertSettable(BaseEntity bean) {
return Objects.isNull(bean.getCreateTime()) || Objects.isNull(bean.getCreateUser());
}
/**
* Check whether parameter properties need to be set when updating.
*
* @param bean BaseEntity
* @return updating fields is settable
*/
protected boolean isUpdateSettable(BaseEntity bean) {
return Objects.isNull(bean.getUpdateTime()) || Objects.isNull(bean.getUpdateUser());
}
/**
* Gets current login principalId.
*
* @return principal ID
*/
protected Long getCurrentPrincipalId() {
if (RpcContextIamSecurityBridges.hasRpcContextIamSecurityUtilsClass()) {
try {
/*TODO remove parse, direct use string principalId.*/
return NumUtil.toLongObjectOrNull(RpcContextIamSecurityBridges.currentIamPrincipalId());
} catch (Exception e) {
log.warn("Cannot get currentIamPrincipalId. - {}", e.getMessage());
}
} else {
log.warn("Saving unable to set currentIamPrincipalId! Please check if 'xcloud-iam-common' dependency exists!");
}
return MyBatisConstants.UNKNOWN_USER_ID;
}
private void preProcess(Invocation invoc, SqlCommandType command) {
switch (command) {
case SELECT:
preQuery(invoc);
break;
case UPDATE:
preUpdate(invoc);
break;
case INSERT:
preInsert(invoc);
break;
default:
}
}
private Object postProcess(Invocation invoc, SqlCommandType command, Object result) {
switch (command) {
case SELECT:
return postQuery(invoc, result);
case UPDATE:
return postUpdate(invoc, result);
case INSERT:
return postInsert(invoc, result);
default:
return result;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy