- 主要代碼如下所示:
package com.aoke.oa.search.plugins;
import com.baomidou.mybatisplus.core.toolkit.PluginUtils;
import com.baomidou.mybatisplus.core.toolkit.SystemClock;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlFormatter;
import lombok.extern.slf4j.Slf4j;
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.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
@Slf4j
@Intercepts({
@Signature(type = StatementHandler.class, method = "query", args = {Statement.class, ResultHandler.class}),
@Signature(type = StatementHandler.class, method = "update", args = Statement.class),
@Signature(type = StatementHandler.class, method = "batch", args = Statement.class)
})
@ConditionalOnProperty(value = "oa.search.log.sql.enabled", havingValue = "true", matchIfMissing = true)
@Component
public class SqlLogInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
long timing = 0L;
Object result = null;
try {
long start = SystemClock.now();
result = invocation.proceed();
timing = SystemClock.now() - start;
} finally {
Object target = PluginUtils.realTarget(invocation.getTarget());
MetaObject metaObject = SystemMetaObject.forObject(target);
MappedStatement ms = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
Configuration configuration = ms.getConfiguration();
List<Object> params = getRuntimeParams(configuration, boundSql);
String runTimeSql = getRuntimeSql(boundSql, params);
SqlFormatter sqlFormatter = new SqlFormatter();
String formatterSql = sqlFormatter.format(runTimeSql);
log.info("\n============== Sql Start ==============" +
"\nExecute Time:{} ms - ID:{}" +
"\nExecute SQL :{}" +
"\n============== Sql End ==============",
timing, ms.getId(), formatterSql);
}
return result;
}
private String getRuntimeSql(BoundSql boundSql, List<Object> params) {
String sql = boundSql.getSql();
for (Object object : params) {
sql = sql.replaceFirst("\\?", getParameterValue(object));
}
return sql;
}
private static List<Object> getRuntimeParams(Configuration configuration, BoundSql boundSql) {
List<Object> params = new ArrayList<Object>();
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings.size() > 0 && parameterObject != null) {
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
params.add(parameterObject);
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
for (ParameterMapping parameterMapping : parameterMappings) {
String propertyName = parameterMapping.getProperty();
if (metaObject.hasGetter(propertyName)) {
Object obj = metaObject.getValue(propertyName);
params.add(obj);
} else if (boundSql.hasAdditionalParameter(propertyName)) {
Object obj = boundSql.getAdditionalParameter(propertyName);
params.add(obj);
}
}
}
}
return params;
}
private static String getParameterValue(Object obj) {
String value = "";
if (obj instanceof String) {
value = "'" + obj + "'";
} else if (obj instanceof Date) {
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
value = "'" + formatter.format((Date) obj) + "'";
} else if (obj != null) {
value = obj.toString();
}
value = value.replace("$", "\\$");
return value;
}
@Override
public Object plugin(Object target) {
if (target instanceof StatementHandler) {
return Plugin.wrap(target, this);
}
return target;
}
@Override
public void setProperties(Properties properties) {
}
}
- 格式化SQL的代碼如下所示:
import java.util.*;
public class SqlFormatter {
private static final String WHITESPACE = " \n\r\f\t";
private static final Set<String> BEGIN_CLAUSES = new HashSet<>();
private static final Set<String> END_CLAUSES = new HashSet<>();
private static final Set<String> LOGICAL = new HashSet<>();
private static final Set<String> QUANTIFIERS = new HashSet<>();
private static final Set<String> DML = new HashSet<>();
private static final Set<String> MISC = new HashSet<>();
private static final String INDENT_STRING = " ";
private static final String INITIAL = System.lineSeparator() + INDENT_STRING;
static {
BEGIN_CLAUSES.add("left");
BEGIN_CLAUSES.add("right");
BEGIN_CLAUSES.add("inner");
BEGIN_CLAUSES.add("outer");
BEGIN_CLAUSES.add("group");
BEGIN_CLAUSES.add("order");
END_CLAUSES.add("where");
END_CLAUSES.add("set");
END_CLAUSES.add("having");
END_CLAUSES.add("from");
END_CLAUSES.add("by");
END_CLAUSES.add("join");
END_CLAUSES.add("into");
END_CLAUSES.add("union");
LOGICAL.add("and");
LOGICAL.add("or");
LOGICAL.add("when");
LOGICAL.add("else");
LOGICAL.add("end");
QUANTIFIERS.add("in");
QUANTIFIERS.add("all");
QUANTIFIERS.add("exists");
QUANTIFIERS.add("some");
QUANTIFIERS.add("any");
DML.add("insert");
DML.add("update");
DML.add("delete");
MISC.add("select");
MISC.add("on");
}
public String format(String source) {
return new FormatProcess(source).perform();
}
private static class FormatProcess {
boolean beginLine = true;
boolean afterBeginBeforeEnd;
boolean afterByOrSetOrFromOrSelect;
boolean afterValues;
boolean afterOn;
boolean afterBetween;
boolean afterInsert;
int inFunction;
int parensSinceSelect;
StringBuilder result = new StringBuilder();
StringTokenizer tokens;
int indent = 1;
private LinkedList<Integer> parenCounts = new LinkedList<>();
private LinkedList<Boolean> afterByOrFromOrSelects = new LinkedList<>();
String lastToken;
String token;
String lcToken;
FormatProcess(String sql) {
tokens = new StringTokenizer(
sql,
"()+*/-=<>'`\"[]," + WHITESPACE,
true
);
}
private static boolean isFunctionName(String tok) {
if (tok == null || tok.length() == 0) {
return false;
}
final char begin = tok.charAt(0);
final boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin;
return isIdentifier &&
!LOGICAL.contains(tok) &&
!END_CLAUSES.contains(tok) &&
!QUANTIFIERS.contains(tok) &&
!DML.contains(tok) &&
!MISC.contains(tok);
}
private void commaAfterOn() {
out();
indent--;
newline();
afterOn = false;
afterByOrSetOrFromOrSelect = true;
}
private void commaAfterByOrFromOrSelect() {
out();
newline();
}
private void logical() {
if ("end".equals(lcToken)) {
indent--;
}
newline();
out();
beginLine = false;
}
private void on() {
indent++;
afterOn = true;
newline();
out();
beginLine = false;
}
private void misc() {
out();
if ("between".equals(lcToken)) {
afterBetween = true;
}
if (afterInsert) {
newline();
afterInsert = false;
} else {
beginLine = false;
if ("case".equals(lcToken)) {
indent++;
}
}
}
String perform() {
result.append(INITIAL);
while (tokens.hasMoreTokens()) {
token = tokens.nextToken();
lcToken = token.toLowerCase(Locale.ROOT);
if ("'".equals(token)) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while (!"'".equals(t) && tokens.hasMoreTokens());
} else if ("\"".equals(token)) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while (!"\"".equals(t) && tokens.hasMoreTokens());
}
else if ("[".equals(token)) {
String t;
do {
t = tokens.nextToken();
token += t;
}
while (!"]".equals(t) && tokens.hasMoreTokens());
}
if (afterByOrSetOrFromOrSelect && ",".equals(token)) {
commaAfterByOrFromOrSelect();
} else if (afterOn && ",".equals(token)) {
commaAfterOn();
} else if ("(".equals(token)) {
openParen();
} else if (")".equals(token)) {
closeParen();
} else if (BEGIN_CLAUSES.contains(lcToken)) {
beginNewClause();
} else if (END_CLAUSES.contains(lcToken)) {
endNewClause();
} else if ("select".equals(lcToken)) {
select();
} else if (DML.contains(lcToken)) {
updateOrInsertOrDelete();
} else if ("values".equals(lcToken)) {
values();
} else if ("on".equals(lcToken)) {
on();
} else if (afterBetween && lcToken.equals("and")) {
misc();
afterBetween = false;
} else if (LOGICAL.contains(lcToken)) {
logical();
} else if (isWhitespace(token)) {
white();
} else {
misc();
}
if (!isWhitespace(token)) {
lastToken = lcToken;
}
}
return result.toString();
}
private void updateOrInsertOrDelete() {
out();
indent++;
beginLine = false;
if ("update".equals(lcToken)) {
newline();
}
if ("insert".equals(lcToken)) {
afterInsert = true;
}
}
private void select() {
out();
indent++;
newline();
parenCounts.addLast(parensSinceSelect);
afterByOrFromOrSelects.addLast(afterByOrSetOrFromOrSelect);
parensSinceSelect = 0;
afterByOrSetOrFromOrSelect = true;
}
private void out() {
result.append(token);
}
private void endNewClause() {
if (!afterBeginBeforeEnd) {
indent--;
if (afterOn) {
indent--;
afterOn = false;
}
newline();
}
out();
if (!"union".equals(lcToken)) {
indent++;
}
newline();
afterBeginBeforeEnd = false;
afterByOrSetOrFromOrSelect = "by".equals(lcToken)
|| "set".equals(lcToken)
|| "from".equals(lcToken);
}
private void beginNewClause() {
if (!afterBeginBeforeEnd) {
if (afterOn) {
indent--;
afterOn = false;
}
indent--;
newline();
}
out();
beginLine = false;
afterBeginBeforeEnd = true;
}
private void values() {
indent--;
newline();
out();
indent++;
newline();
afterValues = true;
}
private void closeParen() {
parensSinceSelect--;
if (parensSinceSelect < 0) {
indent--;
parensSinceSelect = parenCounts.removeLast();
afterByOrSetOrFromOrSelect = afterByOrFromOrSelects.removeLast();
}
if (inFunction > 0) {
inFunction--;
out();
} else {
if (!afterByOrSetOrFromOrSelect) {
indent--;
newline();
}
out();
}
beginLine = false;
}
private void openParen() {
if (isFunctionName(lastToken) || inFunction > 0) {
inFunction++;
}
beginLine = false;
if (inFunction > 0) {
out();
} else {
out();
if (!afterByOrSetOrFromOrSelect) {
indent++;
newline();
beginLine = true;
}
}
parensSinceSelect++;
}
private void white() {
if (!beginLine) {
result.append(" ");
}
}
private static boolean isWhitespace(String token) {
return WHITESPACE.contains(token);
}
private void newline() {
result.append(System.lineSeparator());
for (int i = 0; i < indent; i++) {
result.append(INDENT_STRING);
}
beginLine = true;
}
}
}