1.准备环境:
- java8
- MyBatis-Plus(使用的原因是为了方便生成dao、service和直接使用自带的方法)
pom文件(包含一部分项目其他地方用的包)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.deroser.mybatis-plus-test</groupId>
<artifactId>mybatis-plus-test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mybatis-plus-test</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.3.1</version>
</dependency>
<!-- 添加 模板引擎 依赖 -->
<dependency>
<groupId>org.apache.velocity</groupId>
<artifactId>velocity-engine-core</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>8.0.22</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>3.4.1</version>
</dependency>
<!--时间解析-->
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.7</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
<compilerArguments>
<verbose />
<!-- <bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar;${java.home}/lib/jsse.jar</bootclasspath>-->
</compilerArguments>
</configuration>
</plugin>
</plugins>
</build>
</project>
yml文件只配置了dataSource
2.编写config类
import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import com.deroser.mybatisplustest.mybatisplustest.Interceptor.TestInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
@Configuration
@MapperScan("com.deroser.mybatisplustest.mybatisplustest.mapper")
public class MyConfig extends WebMvcConfigurerAdapter {
/**
* myBatis-Plus的分页插件
*/
@Bean
public PaginationInterceptor paginationInterceptor(){
return new PaginationInterceptor();
}
/**
* 接下来要写的拦截器
*/
@Bean
public MybatisInterceptor mybatisInterceptor(){return new MybatisInterceptor();}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(testInterceptor()).addPathPatterns("/**");
}
}
import com.deroser.mybatisplustest.mybatisplustest.config.util.SQLFormatter;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
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.session.Configuration;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import java.io.Serializable;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
@Intercepts({@Signature(
type = Executor.class,
method = "update",
args = {MappedStatement.class,Object.class}
)})
// 这个拦截器只处理修改(update)的sql
public class MybatisInterceptor implements Interceptor, Serializable {
@Override
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStatement = (MappedStatement)invocation.getArgs()[0];
Object paramter = null;
if (invocation.getArgs().length > 1){
paramter = invocation.getArgs()[1];
}
String sqlId = mappedStatement.getId();
BoundSql boundSql = mappedStatement.getBoundSql(paramter);
Configuration configuration = mappedStatement.getConfiguration();
try {
String sql = getSql(configuration,boundSql,sqlId);
System.out.println("sql打印测试:"+sql);
}catch (Exception var15){
System.out.println(var15.getMessage());
}
return invocation.proceed();
}
private String getSql(Configuration configuration, BoundSql boundSql, String sqlId) {
String sql = bindingSQL(configuration,boundSql);
StringBuilder str = new StringBuilder(100);
str.append(SQLFormatter.format(sql));
return str.toString();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target,this);
}
@Override
public void setProperties(Properties properties) {
}
private static String bindingSQL(Configuration configuration,BoundSql boundSql){
Object parameterObject = boundSql.getParameterObject();
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
String sql = boundSql.getSql();
try {
if (parameterMappings.size() > 0 && parameterObject != null){
TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
System.out.println(parameterObject.getClass());
if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())){
sql = replaceSqlRegex(sql,parameterObject);
}else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
Iterator var7 = parameterMappings.iterator();
while (var7.hasNext()){
ParameterMapping parameterMapping = (ParameterMapping) var7.next();
String propertyName = parameterMapping.getProperty();
Object obj;
if (metaObject.hasGetter(propertyName)){
obj = metaObject.getValue(propertyName);
sql = replaceSqlRegex(sql,obj);
}else if (boundSql.hasAdditionalParameter(propertyName)){
obj = boundSql.getAdditionalParameter(propertyName);
sql = replaceSqlRegex(sql,obj);
}
}
}
}
}catch (Exception var11){
throw var11 instanceof RuntimeException ? (RuntimeException)var11 : new RuntimeException(var11);
}
sql = SQLFormatter.format(sql);
return sql;
}
private static String replaceSqlRegex(String sql, Object obj){
String parameterValue = getParameterValue(obj);
sql = sql.replaceFirst("\\?",parameterValue == null ? null: Matcher.quoteReplacement(parameterValue));
return sql;
}
private static String getParameterValue(Object obj) {
if (obj == null){
return null;
}else {
String value = null;
if (obj instanceof String){
value = "'"+ obj.toString()+ "'";
}else if (obj instanceof Date){
value = "'"+ formatDateTime((Date)obj,"yyyy-MM-dd HH:mm:ss")+"'";
}else if (obj!=null){
value = obj.toString();
}else {
value = "";
}
return value;
}
}
private static String formatDateTime(Date time, String format) {
if (time == null){
return null;
}else {
DateTimeFormatter dateFormat = null;
if (StringUtils.isNotEmpty(format)){
dateFormat = DateTimeFormat.forPattern(format);
}else {
dateFormat = DateTimeFormat.forPattern("yyyy-MM-dd");
}
return (new DateTime(time)).toString(dateFormat);
}
}
}
package com.deroser.mybatisplustest.mybatisplustest.config.util;
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 Set<String> SQL_KEY_CASE = new HashSet<>();
String indentString = " ";
String initial = "\n ";
boolean beginLine = true;
boolean afterBeginBeforeEnd = false;
boolean afterByOrSetOrFromOrSelect = false;
boolean afterValues = false;
boolean afterOn = false;
boolean afterBetween = false;
boolean afterInsert = false;
int inFunction = 0;
int parensSinceSelect = 0;
private LinkedList<Integer> parenCounts = new LinkedList<>();
private LinkedList<Boolean> afterByOrFromOrSelects = new LinkedList<>();
int indent = 1;
StringBuffer result = new StringBuffer();
StringTokenizer tokens;
String lastToken;
String token;
String lcToken;
public SQLFormatter(String sql) {
this.tokens = new StringTokenizer(sql, "()+*/-=<>'`\"[], \n\r\f\t", true);
}
public SQLFormatter setIndentString(String indent) {
this.indentString = indent;
return this;
}
public SQLFormatter setInitialString(String initial) {
this.initial = initial;
return this;
}
public String format() {
this.result.append(this.initial);
while (this.tokens.hasMoreTokens()) {
this.token = this.tokens.nextToken();
this.lcToken = this.token.toLowerCase();
String t;
if ("'".equals(this.token)) {
do {
t = this.tokens.nextToken();
this.token = this.token + t;
} while (!"'".equals(t) && this.tokens.hasMoreTokens());
} else if ("\"".equals(this.token)) {
do {
t = this.tokens.nextToken();
this.token = this.token + t;
} while (!"\"".equals(t));
}
if (this.afterByOrSetOrFromOrSelect && ",".equals(this.token)) {
this.commAfterByOrFromOrSelect();
} else if (this.afterOn && ",".equals(this.token)) {
this.commaAfterOn();
} else if ("(".equals(this.token)) {
this.openParen();
} else if (")".equals(this.token)) {
this.closeParen();
} else if (BEGIN_CLAUSES.contains(this.lcToken)) {
this.beginNewClause();
} else if (END_CLAUSES.contains(this.lcToken)) {
this.endNewClause();
} else if ("includes".equals(this.lcToken)) {
this.select();
} else if (DML.contains(this.lcToken)) {
this.updateOrInsertOrDelete();
} else if ("values".equals(this.lcToken)) {
this.on();
} else if (this.afterBetween && this.lcToken.equals("and")) {
this.misc();
this.afterBetween = false;
} else if (LOGICAL.contains(this.token)) {
this.logical();
} else if (isWhitespace(this.token)) {
this.white();
} else {
this.misc();
}
if (!isWhitespace(this.token)) {
this.lastToken = this.lcToken;
}
}
return this.result.toString();
}
private void commAfterByOrFromOrSelect() {
this.out();
this.newline();
}
private void commaAfterOn() {
this.out();
--this.indent;
this.newline();
this.afterOn = false;
this.afterByOrSetOrFromOrSelect = true;
}
private void logical() {
if ("end".equals(this.lcToken)) {
--this.indent;
}
this.out();
this.beginLine = false;
}
private void on() {
++this.indent;
this.afterOn = true;
this.out();
this.beginLine = false;
}
private void misc() {
this.out();
if ("between".equals(this.lcToken)) {
this.afterBetween = true;
}
if (this.afterInsert) {
this.newline();
this.afterInsert = false;
} else {
this.beginLine = false;
if ("case".equals(this.lcToken)) {
++this.indent;
}
}
}
private void white() {
if (!this.beginLine) {
this.result.append(" ");
}
}
private void updateOrInsertOrDelete() {
this.out();
++this.indent;
this.beginLine = false;
if ("updateByPk".equals(this.lcToken)) {
this.newline();
}
if ("insert".equals(this.lcToken)) {
this.afterInsert = true;
}
}
private void select() {
this.out();
++this.indent;
this.newline();
this.parenCounts.addLast(this.parensSinceSelect);
this.afterByOrFromOrSelects.addLast(this.afterByOrSetOrFromOrSelect);
this.parensSinceSelect = 0;
this.afterByOrSetOrFromOrSelect = true;
}
private void out() {
if (SQL_KEY_CASE.contains(this.token.toLowerCase())) {
this.token = this.token.toUpperCase();
}
this.result.append(this.token);
}
private void endNewClause() {
if (!this.afterBeginBeforeEnd) {
--this.indent;
if (this.afterOn) {
--this.indent;
this.afterOn = false;
}
this.newline();
}
this.out();
if (!"union".equals(this.lcToken)) {
++this.indent;
}
this.result.append(" ");
this.afterBeginBeforeEnd = false;
this.afterByOrSetOrFromOrSelect = "by".equals(this.lcToken) || "set".equals(this.lcToken) || "from".equals(this.lcToken);
}
private void values() {
--this.indent;
this.newline();
this.out();
++this.indent;
this.newline();
this.afterValues = true;
}
private void beginNewClause() {
if (!this.afterBeginBeforeEnd) {
if (this.afterOn) {
--this.indent;
this.afterOn = false;
}
--this.indent;
this.newline();
}
this.out();
this.beginLine = false;
this.afterBeginBeforeEnd = true;
}
private void closeParen() {
--this.parensSinceSelect;
if (this.parensSinceSelect < 0) {
--this.indent;
this.parensSinceSelect = (Integer) this.parenCounts.removeLast();
this.afterByOrSetOrFromOrSelect = (Boolean) this.afterByOrFromOrSelects.removeLast();
}
if (this.inFunction > 0) {
--this.inFunction;
this.out();
} else {
if (!this.afterByOrSetOrFromOrSelect) {
--this.indent;
this.newline();
}
this.out();
}
this.beginLine = false;
}
private void openParen() {
if (isFunctionName(this.lastToken) || this.inFunction > 0) {
++this.inFunction;
}
this.beginLine = false;
if (this.inFunction > 0) {
this.out();
} else {
this.out();
if (!this.afterByOrSetOrFromOrSelect) {
++this.indent;
this.newline();
this.beginLine = true;
}
}
++this.parensSinceSelect;
}
public static String format(String sql) {
try {
return (new SQLFormatter(sql)).format();
} catch (Throwable var2) {
return sql;
}
}
private static boolean isFunctionName(String tok) {
char begin = tok.charAt(0);
boolean isIdentifier = Character.isJavaIdentifierPart(begin) || '"' == begin;
return isIdentifier && !LOGICAL.contains(tok) && !END_CLAUSES.contains(tok) && !QUANTIFIERS.contains(tok) && !DML.contains(tok) && !MISC.contains(tok);
}
private static boolean isWhitespace(String token) {
return " \n\r\f\t".contains(token);
}
private void newline() {
this.result.append("\n");
for (int i = 0; i < this.indent; i++) {
this.result.append(this.indentString);
}
this.beginLine = true;
}
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("join");
END_CLAUSES.add("from");
END_CLAUSES.add("by");
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("updateByPk");
DML.add("delete");
DML.add("includes");
DML.add("on");
SQL_KEY_CASE.addAll(Arrays.asList("includes", "insert", "updateByPk", "delete", "on", "left", "right", "inner", "outer", "group", "order", "where", "set", "having", "join", "from", "by", "into", "union", "and", "or", "when", "else", "end", "in", "all", "exists", "if", "some", "any", "distinct", "count", "sum", "as", "asc", "desc", "between", "alter", "table", "else", "elseif", "index", "ignore", "limit", "like", "offset"));
}
}
2.写好这些就可以了,接下来随便写个修改的接口
import com.deroser.mybatisplustest.mybatisplustest.model.User;
import com.deroser.mybatisplustest.mybatisplustest.service.UserService;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* <p>
* 前端控制器
* </p>
*
* @author deroser
* @since 2021-05-11
*/
@RestController
@RequestMapping("/mybatisplustest/user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping(value = "/updateUser",method = RequestMethod.POST)
public boolean getUser(@RequestBody User user){
return userService.saveOrUpdate(user);
}
}
运行项目后调用接口,效果如下
PS:实际上可以通过如下方式(yml配置)直接打印sql日志:
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
如果用的是mybatis-config.xml可如下配置:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
</configuration>
但是因为我所在的公司项目用的是自己的框架,不可修改,里面只是打印了查询的sql,而因为日志已经写的五花八门的,再配置这个东西就显得有些鸡肋,只能用这种方法针对update做了处理