├── image
├── img.png
├── 2020-03-25_09-28-47.jpg
├── 2023-04-28_08-33-52.gif
└── pluginIcon.svg
├── gradle.properties
├── mybatis-idea-plugin
├── libs
│ └── mybatis-agent-1.0.30-all.jar
├── src
│ └── main
│ │ ├── resources
│ │ ├── icons
│ │ │ ├── mybatis.png
│ │ │ └── pluginIcon.svg
│ │ └── META-INF
│ │ │ ├── plugin.xml
│ │ │ └── pluginIcon.svg
│ │ └── java
│ │ └── com
│ │ └── plugins
│ │ └── mybaitslog
│ │ ├── icons
│ │ └── Icons.java
│ │ ├── console
│ │ ├── SqlVO.java
│ │ ├── ConsoleActionGroup.java
│ │ ├── MyBatisLogToolWindow.java
│ │ ├── ConsolePanel.java
│ │ ├── PrintlnUtil.java
│ │ └── BasicFormatter.java
│ │ ├── VersionControl.java
│ │ ├── gui
│ │ ├── compone
│ │ │ ├── MyTableModel.java
│ │ │ └── MyColorButton.java
│ │ ├── FilterSetting.java
│ │ └── FilterSetting.form
│ │ ├── integration
│ │ ├── MyConsoleDependentFilterProvider.java
│ │ ├── MyConsoleFolding.java
│ │ └── MyBatisLogFilter.java
│ │ ├── PerRunGradle.java
│ │ ├── unix
│ │ └── UnixServer.java
│ │ ├── PluginUtil.java
│ │ ├── PerRun.java
│ │ └── Config.java
└── build.gradle
├── settings.gradle
├── mybatis-agent
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── plugins
│ │ └── mybaitslog
│ │ ├── IClassFileTransformer.java
│ │ ├── preAgent.java
│ │ ├── transformer.java
│ │ └── monitor
│ │ ├── DynamicSqlSourceMonitor.java
│ │ └── RawSqlSourceMonitor.java
└── build.gradle
├── mybatis-test
├── src
│ └── test
│ │ ├── java
│ │ └── com
│ │ │ └── linkkou
│ │ │ └── mybatislog
│ │ │ ├── orm
│ │ │ ├── dao
│ │ │ │ ├── UserMapper.java
│ │ │ │ └── EmployeesDao.java
│ │ │ ├── entity
│ │ │ │ └── Pageable.java
│ │ │ └── domain
│ │ │ │ ├── EmployeesTable.java
│ │ │ │ └── Employees.java
│ │ │ ├── mybatis
│ │ │ ├── boot
│ │ │ │ ├── config
│ │ │ │ │ ├── EnableDataSource.java
│ │ │ │ │ └── EnableDataSourceImpl.java
│ │ │ │ ├── App.java
│ │ │ │ └── plugins
│ │ │ │ │ └── QueryPaginatorInterceptor.java
│ │ │ └── Index.java
│ │ │ └── mybatisplus
│ │ │ ├── boot
│ │ │ ├── config
│ │ │ │ ├── EnableDataSource.java
│ │ │ │ └── EnableDataSourceImpl.java
│ │ │ └── App.java
│ │ │ └── Index.java
│ │ └── resources
│ │ ├── application.properties
│ │ └── mapper
│ │ └── EmployeesMapper.xml
├── .gitignore
└── build.gradle
├── mybatis-plugin
├── src
│ └── main
│ │ └── java
│ │ └── com
│ │ └── linkkou
│ │ └── mybatis
│ │ └── log
│ │ ├── SqlVO.java
│ │ ├── SubInterceptorChain.java
│ │ ├── PrintlnLog.java
│ │ ├── LogInterceptor.java
│ │ └── IPreparedStatement.java
└── build.gradle
├── .gitignore
├── gradlew.bat
├── README.md
└── gradlew
/image/img.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/HEAD/image/img.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_271.jdk/Contents/Home
2 |
--------------------------------------------------------------------------------
/image/2020-03-25_09-28-47.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/HEAD/image/2020-03-25_09-28-47.jpg
--------------------------------------------------------------------------------
/image/2023-04-28_08-33-52.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/HEAD/image/2023-04-28_08-33-52.gif
--------------------------------------------------------------------------------
/mybatis-idea-plugin/libs/mybatis-agent-1.0.30-all.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/HEAD/mybatis-idea-plugin/libs/mybatis-agent-1.0.30-all.jar
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/resources/icons/mybatis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/HEAD/mybatis-idea-plugin/src/main/resources/icons/mybatis.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'plugins-intellij-assistant-mybatislog'
2 | include 'mybatis-agent'
3 | include 'mybatis-idea-plugin'
4 | include 'mybatis-plugin'
5 | include 'mybatis-test'
6 |
7 |
--------------------------------------------------------------------------------
/mybatis-agent/src/main/java/com/plugins/mybaitslog/IClassFileTransformer.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | /**
4 | * A IClassFileTransformer Interface
5 | *
6 | * @author lk
7 | * @version 1.0
8 | *
date: 2023/3/29 21:50
9 | */
10 | public interface IClassFileTransformer {
11 | void transform(String val);
12 | }
13 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/icons/Icons.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.icons;
2 |
3 | import com.intellij.openapi.util.IconLoader;
4 |
5 | import javax.swing.*;
6 |
7 | /**
8 | * 图标文件
9 | *
10 | * @author lk
11 | * @version 1.0
12 | * @date 2020/8/23 17:14
13 | */
14 | public final class Icons {
15 | public static final Icon MyBatisIcon = IconLoader.getIcon("/icons/pluginIcon.svg", Icons.class);
16 | }
17 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/orm/dao/UserMapper.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.orm.dao;
2 |
3 | import com.baomidou.mybatisplus.core.mapper.BaseMapper;
4 | import com.linkkou.mybatislog.orm.domain.EmployeesTable;
5 | import org.apache.ibatis.annotations.Mapper;
6 | import org.springframework.stereotype.Repository;
7 |
8 | @Repository
9 | @Mapper
10 | public interface UserMapper extends BaseMapper {
11 |
12 | }
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/orm/entity/Pageable.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.orm.entity;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | /**
7 | * A Pageable Class
8 | *
9 | * @author lk
10 | * @version 1.0
11 | * date: 2023/5/10 09:47
12 | */
13 | @Data
14 | @Accessors(chain = true)
15 | public class Pageable {
16 |
17 | private int offset;
18 |
19 | private int pageSize;
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/mybatis-plugin/src/main/java/com/linkkou/mybatis/log/SqlVO.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatis.log;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | /**
7 | * A SqlVO Class
8 | *
9 | * @author lk
10 | * @version 1.0
11 | * @date 2022/8/29 19:11
12 | */
13 | @Data
14 | @Accessors(chain = true)
15 | public class SqlVO {
16 |
17 | private String id;
18 |
19 | private String originalSql;
20 |
21 | private String completeSql;
22 |
23 | private String parameter;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/console/SqlVO.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.console;
2 |
3 | import lombok.Data;
4 | import lombok.experimental.Accessors;
5 |
6 | /**
7 | * A SqlVO Class
8 | *
9 | * @author lk
10 | * @version 1.0
11 | * @date 2022/8/29 19:11
12 | */
13 | @Data
14 | @Accessors(chain = true)
15 | public class SqlVO {
16 |
17 | private String id;
18 |
19 | private String originalSql;
20 |
21 | private String completeSql;
22 |
23 | private String parameter;
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8080
2 | server.context-path=/
3 | spring.application.name=auth
4 | spring.mvc.servlet.load-on-startup=1
5 | spring.http.multipart.max-file-size=50Mb
6 | spring.http.multipart.max-request-size=70Mb
7 | spring.mvc.throw-exception-if-no-handler-found=true
8 | datasource.url=jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&zeroDateTimeBehavior=convertToNull&useOldAliasMetadataBehavior=true&autoReconnect=true&failOverReadOnly=false
9 | datasource.username=root
10 | datasource.password=123456
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatis/boot/config/EnableDataSource.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatis.boot.config;
2 |
3 | import org.springframework.context.annotation.Import;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * 数据源注解
12 | *
13 | * @author deppon
14 | * @version 1.0
15 | * @date 2020/9/10 19:05
16 | */
17 | @Target({ElementType.TYPE})
18 | @Retention(RetentionPolicy.RUNTIME)
19 | @Import({EnableDataSourceImpl.class})
20 | public @interface EnableDataSource {
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatisplus/boot/config/EnableDataSource.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatisplus.boot.config;
2 |
3 | import org.springframework.context.annotation.Import;
4 |
5 | import java.lang.annotation.ElementType;
6 | import java.lang.annotation.Retention;
7 | import java.lang.annotation.RetentionPolicy;
8 | import java.lang.annotation.Target;
9 |
10 | /**
11 | * 数据源注解
12 | *
13 | * @author deppon
14 | * @version 1.0
15 | * @date 2020/9/10 19:05
16 | */
17 | @Target({ElementType.TYPE})
18 | @Retention(RetentionPolicy.RUNTIME)
19 | @Import({EnableDataSourceImpl.class})
20 | public @interface EnableDataSource {
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/mybatis-test/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/VersionControl.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | import com.intellij.openapi.application.ApplicationInfo;
4 | import com.intellij.ui.content.ContentFactory;
5 |
6 | import java.lang.reflect.Method;
7 |
8 | /**
9 | * A versionControl Class
10 | *
11 | * @author lk
12 | * @version 1.0
13 | * @date 2022/8/30 10:53
14 | */
15 | public class VersionControl {
16 |
17 | private static final int _2022DOT1 = 221;
18 |
19 | private static final int BaselineVersion = ApplicationInfo.getInstance().getBuild().getBaselineVersion();
20 |
21 | public static ContentFactory getContentFactory() {
22 | return ContentFactory.SERVICE.getInstance();
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatisplus/boot/App.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatisplus.boot;
2 |
3 | import com.linkkou.mybatislog.mybatisplus.boot.config.EnableDataSource;
4 | import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 |
8 | /**
9 | * 引导
10 | *
11 | * @author deppon
12 | * @version 1.0
13 | * @date 2020/9/10 19:05
14 | */
15 | @SpringBootApplication(exclude = {MybatisAutoConfiguration.class})
16 | @EnableDataSource
17 | public class App {
18 |
19 | public static void main(String[] args) {
20 | SpringApplication.run(App.class, args);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatis/boot/App.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatis.boot;
2 |
3 | import com.linkkou.mybatislog.mybatis.boot.config.EnableDataSource;
4 | import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
5 | import org.springframework.boot.SpringApplication;
6 | import org.springframework.boot.autoconfigure.SpringBootApplication;
7 | import org.springframework.context.annotation.ComponentScan;
8 |
9 | /**
10 | * 引导
11 | *
12 | * @author deppon
13 | * @version 1.0
14 | * @date 2020/9/10 19:05
15 | */
16 | @SpringBootApplication(exclude = {MybatisAutoConfiguration.class})
17 | @ComponentScan({"com.linkkou.mybatislog"})
18 | @EnableDataSource
19 | public class App {
20 |
21 | public static void main(String[] args) {
22 | SpringApplication.run(App.class, args);
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/mybatis-agent/src/main/java/com/plugins/mybaitslog/preAgent.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 |
4 | import com.plugins.mybaitslog.monitor.DynamicSqlSourceMonitor;
5 | import org.javatuples.Pair;
6 |
7 | import java.lang.instrument.Instrumentation;
8 | import java.lang.instrument.UnmodifiableClassException;
9 |
10 | public class preAgent {
11 |
12 |
13 | //JVM 首先尝试在代理类上调用以下方法
14 | public static void premain(String agentArgs, Instrumentation inst) {
15 | final Pair with = Pair.with("Start: ", "MyBatis Log EasyPlus");
16 | System.out.println(with.getValue0() + with.getValue1());
17 | final transformer transformer = new transformer(inst);
18 | transformer.transform(agentArgs);
19 | }
20 |
21 | //如果代理类没有成功,那么 JVM 将尝试调用该方法
22 | public static void premain(String agentArgs) {
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/orm/domain/EmployeesTable.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.orm.domain;
2 |
3 | import com.baomidou.mybatisplus.annotation.TableName;
4 | import lombok.Data;
5 | import lombok.experimental.Accessors;
6 |
7 | import java.io.Serializable;
8 | import java.util.Date;
9 |
10 | /**
11 | * (Employees)实体类
12 | *
13 | * @author makejava
14 | * @since 2023-05-10 09:34:51
15 | */
16 | @Data
17 | @Accessors(chain = true)
18 | @TableName("employees")
19 | public class EmployeesTable implements Serializable {
20 | private static final long serialVersionUID = -97648538279091943L;
21 |
22 | private Integer empNo;
23 |
24 | private Date birthDate;
25 |
26 | private String firstName;
27 |
28 | private String lastName;
29 |
30 | private String gender;
31 |
32 | private Date hireDate;
33 |
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/gui/compone/MyTableModel.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.gui.compone;
2 |
3 | import javax.swing.table.DefaultTableModel;
4 |
5 | /**
6 | * A MyTableModel Class
7 | *
8 | * @author lk
9 | * @version 1.0
10 | * date: 2023/4/6 10:05
11 | */
12 | public class MyTableModel extends DefaultTableModel {
13 |
14 |
15 | public MyTableModel() {
16 | super(new String[]{"Performer", "Enable"}, 0);
17 | }
18 |
19 | @Override
20 | public Class> getColumnClass(int columnIndex) {
21 | Class clazz = String.class;
22 | switch (columnIndex) {
23 | case 0:
24 | clazz = String.class;
25 | break;
26 | case 1:
27 | clazz = Boolean.class;
28 | break;
29 | }
30 | return clazz;
31 | }
32 |
33 | @Override
34 | public boolean isCellEditable(int row, int column) {
35 | return column == 1;
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/console/ConsoleActionGroup.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.console;
2 |
3 | import com.intellij.icons.AllIcons;
4 | import com.intellij.openapi.actionSystem.AnAction;
5 | import com.intellij.openapi.actionSystem.AnActionEvent;
6 | import com.intellij.openapi.project.DumbAware;
7 |
8 | /**
9 | * 左侧工具栏
10 | *
11 | * @author lk
12 | * @version 1.0
13 | * @date 2020/4/10 22:00
14 | */
15 | public class ConsoleActionGroup {
16 |
17 | private static Runnable myFilterAction;
18 |
19 | public static void withFilter(Runnable filter) {
20 | ConsoleActionGroup.myFilterAction = filter;
21 | }
22 |
23 | /**
24 | * 过滤按钮
25 | */
26 | public static class FilterAction extends AnAction implements DumbAware {
27 |
28 |
29 | public FilterAction() {
30 | super("Filter", "Filter", AllIcons.General.Filter);
31 | }
32 |
33 | @Override
34 | public void actionPerformed(AnActionEvent e) {
35 | ConsoleActionGroup.myFilterAction.run();
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/integration/MyConsoleDependentFilterProvider.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.integration;
2 |
3 | import com.intellij.execution.filters.ConsoleDependentFilterProvider;
4 | import com.intellij.execution.filters.Filter;
5 | import com.intellij.execution.ui.ConsoleView;
6 | import com.intellij.openapi.project.Project;
7 | import com.intellij.psi.search.GlobalSearchScope;
8 | import org.jetbrains.annotations.NotNull;
9 |
10 | /**
11 | * A MyConsoleActionsPostProcessor Class
12 | *
13 | * @author lk
14 | * @version 1.0
15 | * date: 2023/3/30 16:10
16 | */
17 | public class MyConsoleDependentFilterProvider extends ConsoleDependentFilterProvider {
18 |
19 | @Override
20 | public Filter @NotNull [] getDefaultFilters(@NotNull Project project) {
21 | return super.getDefaultFilters(project);
22 | }
23 |
24 | @Override
25 | public Filter @NotNull [] getDefaultFilters(@NotNull ConsoleView consoleView, @NotNull Project project, @NotNull GlobalSearchScope globalSearchScope) {
26 | Filter filter = new MyBatisLogFilter(project);
27 | return new Filter[]{filter};
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/mybatis-agent/src/main/java/com/plugins/mybaitslog/transformer.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | import com.plugins.mybaitslog.monitor.DynamicSqlSourceMonitor;
4 | import com.plugins.mybaitslog.monitor.RawSqlSourceMonitor;
5 |
6 | import java.lang.instrument.*;
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * A transformer Class
12 | *
13 | * @author lk
14 | * @version 1.0
15 | * date: 2023/3/28 17:36
16 | */
17 | public class transformer implements IClassFileTransformer {
18 |
19 | Instrumentation inst;
20 |
21 | byte[] newclassfileBuffer;
22 | Class> newclassBeingRedefined;
23 |
24 | List classFileTransformers = new ArrayList() {{
25 | add(new DynamicSqlSourceMonitor());
26 | add(new RawSqlSourceMonitor());
27 | }};
28 |
29 | public transformer(Instrumentation inst) {
30 | this.inst = inst;
31 | }
32 |
33 | @Override
34 | public void transform(String val) {
35 | for (IClassFileTransformer classFileTransformer : classFileTransformers) {
36 | classFileTransformer.transform(val);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/mybatis-plugin/src/main/java/com/linkkou/mybatis/log/SubInterceptorChain.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatis.log;
2 |
3 | import org.apache.ibatis.plugin.Interceptor;
4 | import org.apache.ibatis.plugin.InterceptorChain;
5 |
6 | import java.util.Collections;
7 | import java.util.List;
8 |
9 | /**
10 | * A SubInterceptorChain Class
11 | *
12 | * @author lk
13 | * @version 1.0
14 | * date: 2023/3/29 12:40
15 | */
16 | public class SubInterceptorChain extends InterceptorChain {
17 |
18 | public synchronized static void Check(final List interceptors, String val) {
19 | boolean addLogInterceptor = true;
20 | int index = 0;
21 | int size = interceptors.size();
22 | for (Interceptor interceptor : interceptors) {
23 | if (LogInterceptor.class.getName().equals(interceptor.getClass().getName())) {
24 | addLogInterceptor = false;
25 | break;
26 | }
27 | index += 1;
28 | }
29 | //保证插件作为最后执行
30 | if (addLogInterceptor) {
31 | interceptors.add(0, new LogInterceptor(val));
32 | } else {
33 | if (index != 0) {
34 | // 交换位置
35 | Collections.swap(interceptors, 0, index);
36 | }
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/console/MyBatisLogToolWindow.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.console;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.intellij.openapi.wm.ToolWindow;
5 | import com.intellij.openapi.wm.ToolWindowFactory;
6 | import com.intellij.ui.content.Content;
7 | import com.intellij.ui.content.ContentFactory;
8 | import com.plugins.mybaitslog.VersionControl;
9 | import com.plugins.mybaitslog.icons.Icons;
10 | import com.plugins.mybaitslog.unix.UnixServer;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import javax.swing.*;
14 |
15 |
16 | /**
17 | * 标签窗口实现
18 | *
19 | * @author lk
20 | * @version 1.0
21 | * @date 2020/4/10 21:46
22 | */
23 | public class MyBatisLogToolWindow implements ToolWindowFactory {
24 |
25 | @Override
26 | public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
27 | UnixServer.boot(project);
28 | ConsolePanel consolePanel = new ConsolePanel();
29 | final JComponent jComponent = consolePanel.getConsolePanel(project);
30 | final ContentFactory contentFactory = VersionControl.getContentFactory();
31 | Content content = contentFactory.createContent(jComponent, "", false);
32 | toolWindow.setIcon(Icons.MyBatisIcon);
33 | toolWindow.getContentManager().addContent(content);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/mybatis-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url "https://www.jetbrains.com/intellij-repository/releases/" }
4 | maven { url 'https://maven.aliyun.com/repository/public/' }
5 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
6 | maven { url "https://plugins.gradle.org/m2/" }
7 | mavenCentral()
8 | google()
9 | gradlePluginPortal()
10 | mavenLocal()
11 | }
12 | }
13 |
14 | plugins {
15 | id 'java'
16 | id 'io.freefair.lombok' version "8.0.1"
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | maven { url "https://www.jetbrains.com/intellij-repository/releases/" }
22 | maven { url 'https://maven.aliyun.com/repository/public/' }
23 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
24 | maven { url "https://plugins.gradle.org/m2/" }
25 | mavenCentral()
26 | google()
27 | gradlePluginPortal()
28 | mavenLocal()
29 | }
30 | }
31 |
32 | group 'com.plugins.mybatislog.plugin'
33 | version '1.0.10'
34 |
35 | java {
36 | sourceCompatibility = "8"
37 | targetCompatibility = "8"
38 | }
39 |
40 |
41 | dependencies {
42 | implementation 'org.javatuples:javatuples:1.2'
43 | implementation 'com.google.code.gson:gson:2.9.1'
44 | compileOnly 'org.mybatis:mybatis:3.5.10'
45 | compileOnly 'org.projectlombok:lombok:1.18.26'
46 | annotationProcessor 'org.projectlombok:lombok:1.18.26'
47 | }
48 |
49 | test {
50 | useJUnitPlatform()
51 | }
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/gui/compone/MyColorButton.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.gui.compone;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 | import java.awt.event.ActionEvent;
6 |
7 | import com.intellij.openapi.util.SystemInfo;
8 |
9 | public class MyColorButton extends JButton {
10 |
11 | private Color myColor = Color.WHITE;
12 |
13 | public MyColorButton() {
14 | setMargin(new Insets(0, 0, 0, 0));
15 | setFocusable(false);
16 | setDefaultCapable(false);
17 | setFocusable(false);
18 | if (SystemInfo.isMac) {
19 | putClientProperty("JButton.buttonType", "square");
20 | }
21 | }
22 |
23 | public MyColorButton( Color myColor) {
24 | super();
25 | this.myColor = myColor;
26 | }
27 |
28 |
29 | @Override
30 | public void paint(Graphics g) {
31 | final Color color = g.getColor();
32 | int width = getWidth();
33 | int height = getHeight();
34 | if (myColor != null) {
35 | g.setColor(myColor);
36 | g.fillRect(0, 0, width, height);
37 | g.setColor(color);
38 | }
39 | }
40 |
41 | public void setColor(Color myColor) {
42 | this.myColor = myColor;
43 | }
44 |
45 |
46 | @Override
47 | public Dimension getMinimumSize() {
48 | return getPreferredSize();
49 | }
50 |
51 | @Override
52 | public Dimension getMaximumSize() {
53 | return getPreferredSize();
54 | }
55 |
56 | @Override
57 | public Dimension getPreferredSize() {
58 | return new Dimension(12, 12);
59 | }
60 | }
--------------------------------------------------------------------------------
/mybatis-test/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | id 'io.freefair.lombok' version "8.0.1"
4 | }
5 |
6 | group = 'com.linkkou.mybatis.log'
7 | version = '1.0.0'
8 |
9 | repositories {
10 | mavenCentral()
11 | }
12 |
13 | dependencies {
14 | testImplementation project(path: ':mybatis-plugin')
15 | testImplementation project(path: ':mybatis-agent')
16 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
17 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
18 | compileOnly 'org.projectlombok:lombok:1.18.26'
19 | annotationProcessor 'org.projectlombok:lombok:1.18.26'
20 | testImplementation 'com.alibaba:druid:1.2.17'
21 | testImplementation('org.springframework.boot:spring-boot-starter:2.7.3') {
22 | exclude group: 'org.springframework.boot', module: 'spring-boot-starter-logging'
23 | }
24 | testImplementation 'org.springframework.boot:spring-boot-starter-web:2.7.3'
25 | testImplementation('org.springframework.boot:spring-boot-starter-test:2.7.3') {
26 | exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
27 | }
28 | testImplementation 'org.springframework.boot:spring-boot-starter-aop:2.7.3'
29 | testImplementation 'org.springframework:spring-jdbc:5.3.22'
30 | testImplementation 'com.baomidou:mybatis-plus-boot-starter:3.5.3.1'
31 | testImplementation 'mysql:mysql-connector-java:8.0.30'
32 | testImplementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2'
33 | }
34 |
35 | test {
36 | useJUnitPlatform()
37 | jvmArgs(
38 | '--add-opens', 'java.base/java.lang=ALL-UNNAMED',
39 | '--add-opens', 'java.base/java.util=ALL-UNNAMED'
40 | )
41 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | gradle
3 | build/
4 | !gradle/wrapper/gradle-wrapper.jar
5 | !**/src/main/**/build/
6 | !**/src/test/**/build/
7 |
8 | ### IntelliJ IDEA ###
9 | .idea
10 | .idea/modules.xml
11 | .idea/jarRepositories.xml
12 | .idea/compiler.xml
13 | .idea/libraries/
14 | *.iws
15 | *.iml
16 | *.ipr
17 | out/
18 | idea-sandbox
19 | !**/src/main/**/out/
20 | !**/src/test/**/out/
21 |
22 | ### Eclipse ###
23 | .apt_generated
24 | .classpath
25 | .factorypath
26 | .project
27 | .settings
28 | .springBeans
29 | .sts4-cache
30 | bin/
31 | !**/src/main/**/bin/
32 | !**/src/test/**/bin/
33 |
34 | ### NetBeans ###
35 | /nbproject/private/
36 | /nbbuild/
37 | /dist/
38 | /nbdist/
39 | /.nb-gradle/
40 |
41 | ### VS Code ###
42 | .vscode/
43 |
44 | ### Mac OS ###
45 | .DS_Store### Java template
46 | # Compiled class file
47 | *.class
48 | .DS_Store
49 |
50 | # Log file
51 | *.log
52 |
53 | # BlueJ files
54 | *.ctxt
55 |
56 | # Mobile Tools for Java (J2ME)
57 | .mtj.tmp/
58 |
59 | # Package Files #
60 | *.jar
61 | *.war
62 | *.nar
63 | *.ear
64 | *.zip
65 | *.tar.gz
66 | *.rar
67 |
68 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
69 | hs_err_pid*
70 | replay_pid*
71 |
72 | ### Gradle template
73 | .gradle
74 | **/build/
75 | !src/**/build/
76 |
77 | # Ignore Gradle GUI config
78 | gradle-app.setting
79 |
80 | # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
81 | !gradle-wrapper.jar
82 |
83 | # Avoid ignore Gradle wrappper properties
84 | !gradle-wrapper.properties
85 |
86 | # Cache of project
87 | .gradletasknamecache
88 |
89 | # Eclipse Gradle plugin generated files
90 | # Eclipse Core
91 | .project
92 | # JDT-specific (Eclipse Java Development Tools)
93 | .classpath
94 |
95 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/orm/domain/Employees.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.orm.domain;
2 |
3 | import java.util.Date;
4 | import java.io.Serializable;
5 |
6 | /**
7 | * (Employees)实体类
8 | *
9 | * @author makejava
10 | * @since 2023-05-10 09:34:51
11 | */
12 | public class Employees implements Serializable {
13 | private static final long serialVersionUID = -97648538279091943L;
14 |
15 | private Integer empNo;
16 |
17 | private Date birthDate;
18 |
19 | private String firstName;
20 |
21 | private String lastName;
22 |
23 | private String gender;
24 |
25 | private Date hireDate;
26 |
27 |
28 | public Integer getEmpNo() {
29 | return empNo;
30 | }
31 |
32 | public void setEmpNo(Integer empNo) {
33 | this.empNo = empNo;
34 | }
35 |
36 | public Date getBirthDate() {
37 | return birthDate;
38 | }
39 |
40 | public void setBirthDate(Date birthDate) {
41 | this.birthDate = birthDate;
42 | }
43 |
44 | public String getFirstName() {
45 | return firstName;
46 | }
47 |
48 | public void setFirstName(String firstName) {
49 | this.firstName = firstName;
50 | }
51 |
52 | public String getLastName() {
53 | return lastName;
54 | }
55 |
56 | public void setLastName(String lastName) {
57 | this.lastName = lastName;
58 | }
59 |
60 | public String getGender() {
61 | return gender;
62 | }
63 |
64 | public void setGender(String gender) {
65 | this.gender = gender;
66 | }
67 |
68 | public Date getHireDate() {
69 | return hireDate;
70 | }
71 |
72 | public void setHireDate(Date hireDate) {
73 | this.hireDate = hireDate;
74 | }
75 |
76 | }
77 |
78 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/integration/MyConsoleFolding.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.integration;
2 |
3 | import com.intellij.execution.ConsoleFolding;
4 | import com.intellij.openapi.project.Project;
5 | import com.plugins.mybaitslog.Config;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 |
9 | import java.util.List;
10 |
11 | import static com.plugins.mybaitslog.Config.*;
12 |
13 | /**
14 | * A MyConsoleFolding Class
15 | *
16 | * @author lk
17 | * @version 1.0
18 | * date: 2023/3/30 17:56
19 | */
20 | public class MyConsoleFolding extends ConsoleFolding {
21 |
22 | private boolean IS_SQL_START_LINE = false;
23 |
24 | @Override
25 | public boolean shouldFoldLine(@NotNull Project project, @NotNull String line) {
26 | if (line.contains(KEY_NAME) || line.contains(KEY_ERROR_NAME)) {
27 | return true;
28 | }
29 | //region 折叠
30 | if (Idea.getWhetherfold()) {
31 | if (line.contains(SQL_START_LINE)) {
32 | this.IS_SQL_START_LINE = true;
33 | return false;
34 | }
35 | if (IS_SQL_START_LINE && line.contains(SQL_END_LINE)) {
36 | this.IS_SQL_START_LINE = false;
37 | return true;
38 | }
39 | //后续修正
40 | if (IS_SQL_START_LINE) {
41 | if (Idea.getFormatSql()) {
42 | return true;
43 | } else {
44 | return line.contains(SQL_MIDDLE_LINE);
45 | }
46 | }
47 | }
48 | //endregion
49 | return false;
50 | }
51 |
52 | @Override
53 | public @Nullable String getPlaceholderText(@NotNull Project project, @NotNull List lines) {
54 | return "< SQLStructure >";
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/mybatis-agent/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url "https://www.jetbrains.com/intellij-repository/releases/" }
4 | maven { url 'https://maven.aliyun.com/repository/public/' }
5 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
6 | maven { url "https://plugins.gradle.org/m2/" }
7 | mavenCentral()
8 | google()
9 | gradlePluginPortal()
10 | mavenLocal()
11 | }
12 | }
13 |
14 | plugins {
15 | id 'java'
16 | id 'com.github.johnrengelman.shadow' version '8.1.1'
17 | }
18 |
19 | allprojects {
20 | repositories {
21 | maven { url "https://www.jetbrains.com/intellij-repository/releases/" }
22 | maven { url 'https://maven.aliyun.com/repository/public/' }
23 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
24 | maven { url "https://plugins.gradle.org/m2/" }
25 | mavenCentral()
26 | google()
27 | gradlePluginPortal()
28 | mavenLocal()
29 | }
30 | }
31 |
32 |
33 | group 'com.plugins.mybatislog.agent'
34 | version '1.0.30'
35 |
36 | java {
37 | sourceCompatibility = "1.8"
38 | targetCompatibility = "1.8"
39 | }
40 |
41 |
42 | dependencies {
43 | implementation 'org.javatuples:javatuples:1.2'
44 | implementation 'org.javassist:javassist:3.29.2-GA'
45 | implementation 'com.google.code.gson:gson:2.9.1'
46 | implementation project(path: ':mybatis-plugin')
47 | // compile project(":probe-agent") 另一种引入工程的方式
48 | //implementation fileTree(dir: 'libs', includes: ['*jar'])
49 | }
50 |
51 | test {
52 | useJUnitPlatform()
53 | }
54 |
55 | shadowJar {
56 | manifest {
57 | attributes(
58 | 'Premain-Class': 'com.plugins.mybaitslog.preAgent',
59 | 'Can-Retransform-Classes': 'true',
60 | 'Can-Redefine-Classes': 'true',
61 | 'Can-Set-Native-Method-Prefix': 'true'
62 | )
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/integration/MyBatisLogFilter.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.integration;
2 |
3 | import com.intellij.execution.ui.ConsoleViewContentType;
4 | import com.intellij.openapi.editor.markup.TextAttributes;
5 | import com.intellij.openapi.project.Project;
6 | import com.intellij.execution.filters.Filter;
7 | import com.plugins.mybaitslog.Config;
8 | import com.plugins.mybaitslog.console.PrintlnUtil;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 | import com.intellij.openapi.diagnostic.Logger;
12 |
13 | import java.awt.*;
14 |
15 | import static com.plugins.mybaitslog.Config.KEY_ERROR_NAME;
16 | import static com.plugins.mybaitslog.Config.KEY_NAME;
17 |
18 |
19 | /**
20 | * A MyBatisLogFilter Class
21 | *
22 | * @author lk
23 | * @version 1.0
24 | * date: 2023/3/30 16:20
25 | */
26 | public class MyBatisLogFilter implements Filter {
27 | private static final Logger LOG = Logger.getInstance(MyBatisLogFilter.class);
28 |
29 | private final Project project;
30 |
31 | public MyBatisLogFilter(Project project) {
32 | this.project = project;
33 | }
34 |
35 | @Override
36 | public @Nullable Result applyFilter(@NotNull String s, int entireLength) {
37 | //计算偏移
38 | int offset = entireLength;
39 | if (s != null) {
40 | offset = entireLength - s.length();
41 | }
42 | if (s.contains(KEY_NAME)) {
43 | final TextAttributes textAttributes = new TextAttributes();
44 | textAttributes.setForegroundColor(Color.BLACK);
45 | PrintlnUtil.prints(project, s);
46 | return new Result(offset, entireLength, null, textAttributes);
47 | }
48 | if (s.contains(KEY_ERROR_NAME)) {
49 | PrintlnUtil.println(project, Config.KEY_ERROR_NAME + s +"\n", ConsoleViewContentType.ERROR_OUTPUT);
50 | }
51 | return null;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/mybatis-agent/src/main/java/com/plugins/mybaitslog/monitor/DynamicSqlSourceMonitor.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.monitor;
2 |
3 | import com.linkkou.mybatis.log.LogInterceptor;
4 | import com.plugins.mybaitslog.IClassFileTransformer;
5 | import javassist.ClassClassPath;
6 | import javassist.ClassPool;
7 | import javassist.CtClass;
8 | import javassist.CtMethod;
9 |
10 | /**
11 | * A DynamicSqlSourceMonitor Class
12 | *
13 | * @author lk
14 | * @version 1.0
15 | * date: 2023/3/28 16:51
16 | */
17 | public class DynamicSqlSourceMonitor implements IClassFileTransformer {
18 |
19 | public final String injectedClassName = "org.apache.ibatis.plugin.InterceptorChain";
20 |
21 | @Override
22 | public void transform(String val) {
23 | ClassPool classPool = ClassPool.getDefault();
24 | CtClass ctClass = null;
25 | classPool.insertClassPath(new ClassClassPath(this.getClass()));
26 | boolean isMybitas = true;
27 | //获取类
28 | try {
29 | ctClass = classPool.get(injectedClassName);
30 | if (null == ctClass) {
31 | return;
32 | }
33 | } catch (Exception e) {
34 | System.out.println("==> SQLStructureError: " + e.toString());
35 | isMybitas = false;
36 | }
37 | if (isMybitas) {
38 | try {
39 | //删除类
40 | final CtMethod pluginAll = ctClass.getDeclaredMethod("pluginAll");
41 | String strings = "\"" + val + "\"";
42 | pluginAll.insertBefore("{com.linkkou.mybatis.log.SubInterceptorChain.Check($0.interceptors," + strings + ");}");
43 | //写入
44 | //ctClass.writeFile();
45 | //加载该类的字节码(不能少)
46 | ctClass.toClass(LogInterceptor.class.getClassLoader(), LogInterceptor.class.getProtectionDomain());
47 | ctClass.detach();
48 | } catch (Exception e) {
49 | e.printStackTrace();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/mybatis-plugin/src/main/java/com/linkkou/mybatis/log/PrintlnLog.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatis.log;
2 |
3 | import com.google.gson.internal.JavaVersion;
4 |
5 | import java.net.StandardProtocolFamily;
6 | import java.net.UnixDomainSocketAddress;
7 | import java.nio.ByteBuffer;
8 | import java.nio.channels.SocketChannel;
9 | import java.nio.file.Path;
10 | import java.util.concurrent.locks.Lock;
11 | import java.util.concurrent.locks.ReentrantLock;
12 |
13 | /**
14 | * A RmiLog Class
15 | *
16 | * @author lk
17 | * @version 1.0
18 | * date: 2023/5/12 19:28
19 | */
20 | public class PrintlnLog {
21 |
22 | private static SocketChannel socketChannel;
23 | private static boolean connect = false;
24 |
25 | private static SocketChannel client(String id) {
26 | return null;
27 | //目前无法支持到1.8
28 | /*if (null == id) {
29 | return null;
30 | }
31 | if (socketChannel != null && connect) {
32 | return socketChannel;
33 | }
34 | Lock lock = new ReentrantLock(); //注意这个地方
35 | lock.lock();
36 | try {
37 | Path socketPath = Path.of(System.getProperty("java.io.tmpdir")).resolve(id + ".socket");
38 | socketChannel = SocketChannel.open(StandardProtocolFamily.UNIX);
39 | UnixDomainSocketAddress of = UnixDomainSocketAddress.of(socketPath);
40 | connect = socketChannel.connect(of);
41 | } catch (Exception e) {
42 | e.printStackTrace();
43 | } finally {
44 | lock.unlock();
45 | }
46 | return socketChannel;*/
47 | }
48 |
49 | public static void log(String log, String id) {
50 | final SocketChannel client = client(id);
51 | if (!connect) {
52 | System.out.println(log);
53 | } else {
54 | try {
55 | ByteBuffer buf = ByteBuffer.allocate(log.length());
56 | buf.clear();
57 | buf.put(log.getBytes());
58 | buf.flip();
59 | while (buf.hasRemaining()) {
60 | client.write(buf);
61 | }
62 | } catch (Exception e) {
63 | e.printStackTrace();
64 | }
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/mybatis-agent/src/main/java/com/plugins/mybaitslog/monitor/RawSqlSourceMonitor.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.monitor;
2 |
3 | import com.linkkou.mybatis.log.LogInterceptor;
4 | import com.plugins.mybaitslog.IClassFileTransformer;
5 | import javassist.*;
6 |
7 | /**
8 | * A RawSqlSourceMonitor Class
9 | *
10 | * @author lk
11 | * @version 1.0
12 | * date: 2023/3/28 16:52
13 | */
14 | public class RawSqlSourceMonitor implements IClassFileTransformer {
15 | public final String injectedClassName = "org.apache.ibatis.scripting.defaults.RawSqlSource";
16 |
17 | @Override
18 | public void transform(String val) {
19 | ClassPool classPool = ClassPool.getDefault();
20 | CtClass ctClass = null;
21 | classPool.insertClassPath(new ClassClassPath(this.getClass()));
22 | boolean isMybitas = true;
23 | try {
24 | //获取类
25 | ctClass = classPool.get(injectedClassName);
26 | if (null == ctClass) {
27 | return;
28 | }
29 | } catch (Exception e) {
30 | System.out.println("==> SQLStructureError: " + e.toString());
31 | isMybitas = false;
32 | }
33 | if (isMybitas) {
34 | try {
35 | //添加新的字段
36 | CtField ctField = new CtField(classPool.getCtClass("java.lang.String"), "_rootSqlNode_", ctClass);
37 | ctField.setModifiers(Modifier.PUBLIC);
38 | ctField.setModifiers(Modifier.FINAL);
39 | ctClass.addField(ctField);
40 | //获取构造
41 | final CtConstructor declaredConstructor = ctClass.getDeclaredConstructor(new CtClass[]{classPool.getCtClass("org.apache.ibatis.session.Configuration"), classPool.getCtClass("java.lang.String"), classPool.getCtClass("java.lang.Class")});
42 | declaredConstructor.insertAfter("{$0._rootSqlNode_ = $2;}");
43 | //写入
44 | //ctClass.writeFile();
45 | //加载该类的字节码(不能少)
46 | ctClass.toClass(LogInterceptor.class.getClassLoader(), LogInterceptor.class.getProtectionDomain());
47 | ctClass.detach();
48 | } catch (Exception e) {
49 | e.printStackTrace();
50 | }
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/orm/dao/EmployeesDao.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.orm.dao;
2 |
3 | import com.baomidou.mybatisplus.core.metadata.IPage;
4 | import com.linkkou.mybatislog.orm.domain.Employees;
5 | import com.linkkou.mybatislog.orm.entity.Pageable;
6 | import org.apache.ibatis.annotations.Param;
7 | import org.springframework.stereotype.Repository;
8 |
9 | import java.time.LocalDate;
10 | import java.util.List;
11 |
12 | /**
13 | * (Employees)表数据库访问层
14 | *
15 | * @author makejava
16 | * @since 2023-05-10 09:34:49
17 | */
18 | @Repository
19 | public interface EmployeesDao {
20 |
21 | /**
22 | * 通过ID查询单条数据
23 | *
24 | * @return 实例对象
25 | */
26 | Employees queryById(@Param("id") Integer id);
27 |
28 | /**
29 | * 查询指定行数据
30 | *
31 | * @param employees 查询条件
32 | * @param pageable 分页对象
33 | * @return 对象列表
34 | */
35 | List queryAllByLimit(Employees employees, @Param("pageable") Pageable pageable);
36 |
37 | /**
38 | * 统计总行数
39 | *
40 | * @param employees 查询条件
41 | * @return 总行数
42 | */
43 | long count(Employees employees);
44 |
45 | /**
46 | * 新增数据
47 | *
48 | * @param employees 实例对象
49 | * @return 影响行数
50 | */
51 | int insert(Employees employees);
52 |
53 | /**
54 | * 批量新增数据(MyBatis原生foreach方法)
55 | *
56 | * @param entities List 实例对象列表
57 | * @return 影响行数
58 | */
59 | int insertBatch(@Param("entities") List entities);
60 |
61 | /**
62 | * 批量新增或按主键更新数据(MyBatis原生foreach方法)
63 | *
64 | * @param entities List 实例对象列表
65 | * @return 影响行数
66 | * @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
67 | */
68 | int insertOrUpdateBatch(@Param("entities") List entities);
69 |
70 | /**
71 | * 修改数据
72 | *
73 | * @param employees 实例对象
74 | * @return 影响行数
75 | */
76 | int update(Employees employees);
77 |
78 | /**
79 | * 多条件查询
80 | * @param employees 实例对象
81 | * @return 对象列表
82 | */
83 | List queryByMultiple(Employees employees);
84 |
85 | /**
86 | * SQL注入
87 | *
88 | * @return 实例对象
89 | */
90 | Employees queryByInject(@Param("inject") String inject);
91 | Employees queryByInjectD(@Param("inject") String inject);
92 |
93 | Employees queryByInjectLocalDate(@Param("inject") LocalDate inject);
94 |
95 | /**
96 | * JSON
97 | * @param inject
98 | * @return
99 | */
100 | Employees queryByInjectJson(@Param("inject") String inject);
101 |
102 | }
103 |
104 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatisplus/Index.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatisplus;
2 |
3 |
4 | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
5 | import com.baomidou.mybatisplus.core.toolkit.Wrappers;
6 | import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
7 | import com.linkkou.mybatislog.mybatisplus.boot.App;
8 | import com.linkkou.mybatislog.orm.dao.EmployeesDao;
9 | import com.linkkou.mybatislog.orm.dao.UserMapper;
10 | import com.linkkou.mybatislog.orm.domain.Employees;
11 | import com.linkkou.mybatislog.orm.domain.EmployeesTable;
12 | import com.plugins.mybaitslog.transformer;
13 | import org.junit.jupiter.api.Test;
14 | import org.springframework.beans.factory.annotation.Autowired;
15 | import org.springframework.boot.test.context.SpringBootTest;
16 |
17 | import java.util.Date;
18 | import java.util.List;
19 |
20 | /**
21 | * A main Class
22 | *
23 | * @author lk
24 | * @version 1.0
25 | * date: 2023/5/9 12:11
26 | */
27 | @SpringBootTest(classes = App.class)
28 | public class Index {
29 |
30 | @Autowired
31 | private UserMapper userMapper;
32 |
33 | static {
34 | //注入
35 | final transformer transformer = new transformer(null);
36 | transformer.transform("test");
37 | }
38 |
39 | @Test
40 | public void queryById() {
41 | final List employeesTables = userMapper.selectList(null);
42 | System.out.println(employeesTables);
43 | }
44 |
45 | @Test
46 | public void doTest2() {
47 | userMapper.selectCount(Wrappers.lambdaQuery()
48 | .eq(EmployeesTable::getEmpNo, 12));
49 | }
50 |
51 |
52 | @Test
53 | public void doTest3() {
54 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(new EmployeesTable());
55 | queryWrapper.eq(EmployeesTable::getEmpNo, 12);
56 | queryWrapper.eq(EmployeesTable::getEmpNo, 12);
57 | userMapper.selectList(queryWrapper);
58 | }
59 |
60 | @Test
61 | public void doTest4() {
62 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(new EmployeesTable());
63 | queryWrapper.eq(EmployeesTable::getLastName, "12");
64 | queryWrapper.eq(EmployeesTable::getLastName, "12");
65 | userMapper.selectList(queryWrapper);
66 | }
67 |
68 | @Test
69 | public void doTest5() {
70 | LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper(new EmployeesTable());
71 | queryWrapper.eq(EmployeesTable::getHireDate, new Date());
72 | queryWrapper.eq(EmployeesTable::getHireDate, new Date());
73 | userMapper.selectList(queryWrapper);
74 | }
75 |
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | repositories {
3 | maven { url "https://www.jetbrains.com/intellij-repository/releases/" }
4 | maven { url 'https://maven.aliyun.com/repository/public/' }
5 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
6 | maven { url "https://plugins.gradle.org/m2/" }
7 | mavenCentral()
8 | google()
9 | gradlePluginPortal()
10 | mavenLocal()
11 | }
12 | }
13 |
14 | plugins {
15 | id 'java'
16 | id 'org.jetbrains.intellij' version '1.13.3'
17 | // Gradle Changelog Plugin
18 | id 'org.jetbrains.changelog' version "1.3.1"
19 | // Gradle Qodana Plugin
20 | id 'org.jetbrains.qodana' version "0.1.13"
21 | id 'io.freefair.lombok' version "8.0.1"
22 | }
23 |
24 | allprojects {
25 | repositories {
26 | maven { url "https://www.jetbrains.com/intellij-repository/releases/" }
27 | maven { url 'https://maven.aliyun.com/repository/public/' }
28 | maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
29 | maven { url "https://plugins.gradle.org/m2/" }
30 | mavenCentral()
31 | google()
32 | gradlePluginPortal()
33 | mavenLocal()
34 | }
35 | }
36 |
37 | group 'com.plugins.mybaitslog.idea.plugin'
38 | version '5.0.8.2'
39 |
40 | dependencies {
41 | implementation project(path: ':mybatis-plugin')
42 | //implementation project(path: ':mybatis-agent')
43 | compileOnly 'org.jetbrains:annotations:24.0.1'
44 | implementation 'com.google.code.gson:gson:2.9.1'
45 | compileOnly 'org.projectlombok:lombok:1.18.26'
46 | annotationProcessor 'org.projectlombok:lombok:1.18.26'
47 | //compile project(":probe-agent") 另一种引入工程的方式
48 | implementation fileTree(dir: 'libs', includes: ['*jar'])
49 | }
50 |
51 | /*测试关闭*/
52 | java {
53 | sourceCompatibility = "8"
54 | targetCompatibility = "8"
55 | }
56 |
57 | /*https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html#intellij-platform-based-products-of-recent-ide-versions*/
58 | /*https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#configuration-intellij-extension*/
59 | intellij {
60 | pluginName = 'MybatisLog'
61 | // 开发环境运行时使用的版本,不同的版本编译会采用默认支持java版本编译
62 | version = '2022.3.2'
63 | //沙箱目录位置,用于保存IDEA的设置,默认在build文件下面,防止clean,放在根目录下。
64 | sandboxDir = "${rootProject.rootDir}/idea-sandbox"
65 | type = 'IU'
66 | // 依赖的插件
67 | plugins = ['java', 'gradle']
68 | //Disables updating since-build attribute in plugin.xml
69 | updateSinceUntilBuild = false
70 | downloadSources = false
71 | //localPath = '/Applications/IntelliJ IDEA.app/Contents'
72 | //localPath = '/Applications/WebStorm.app/Contents'
73 | }
74 |
75 | runIde {
76 | jvmArgs = [
77 | "-javaagent:/Applications/jetbra/fineagent.jar=jetbrains",
78 | "--add-opens=java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED",
79 | "--add-opens=java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED"]
80 | }
81 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/PerRunGradle.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | import com.intellij.openapi.externalSystem.model.ExternalSystemException;
4 | import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskId;
5 | import com.intellij.openapi.externalSystem.model.task.ExternalSystemTaskNotificationListener;
6 | import org.jetbrains.annotations.NotNull;
7 | import org.jetbrains.annotations.Nullable;
8 | import org.jetbrains.plugins.gradle.service.task.GradleTaskManager;
9 | import org.jetbrains.plugins.gradle.service.task.GradleTaskManagerExtension;
10 | import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import java.util.Map;
15 |
16 | public class PerRunGradle implements GradleTaskManagerExtension {
17 |
18 | private static final String TASKNAME = "org.jetbrains.plugins.gradle";
19 |
20 | @Override
21 | public boolean executeTasks(@NotNull ExternalSystemTaskId id, @NotNull List taskNames, @NotNull String projectPath, @Nullable GradleExecutionSettings settings, @Nullable String jvmParametersSetup, @NotNull ExternalSystemTaskNotificationListener listener) throws ExternalSystemException {
22 | if (Config.Idea.getStartup()) {
23 | final Map perRunMap = Config.Idea.getPerRunMap();
24 | if (perRunMap.get(TASKNAME)) {
25 | final List jvmArguments = settings.getJvmArguments();
26 | String agentCoreJarPath = PluginUtil.getAgentCoreJarPath();
27 | String agentParameter = "-javaagent:\"" + agentCoreJarPath + "\"";
28 | if (null != agentCoreJarPath) {
29 | final long count = jvmArguments.stream().filter(agentParameter::equals).count();
30 | if (count <= 0) {
31 | settings.withVmOptions(agentParameter);
32 | }
33 | //todo 暂未解决如何获取JDK版本问题,暂时先添加。
34 | final ArrayList addOpens = Config.Idea.getAddOpens();
35 | for (String opens : addOpens) {
36 | boolean add = false;
37 | for (String jvmArgument : jvmArguments) {
38 | if (opens.equals(jvmArgument)) {
39 | add = true;
40 | break;
41 | }
42 | }
43 | if (!add) {
44 | settings.withVmOptions(opens);
45 | }
46 | }
47 | }
48 | }
49 | }
50 | return GradleTaskManagerExtension.super.executeTasks(id, taskNames, projectPath, settings, jvmParametersSetup, listener);
51 | }
52 |
53 | @Override
54 | public boolean cancelTask(@NotNull ExternalSystemTaskId externalSystemTaskId, @NotNull ExternalSystemTaskNotificationListener externalSystemTaskNotificationListener) throws ExternalSystemException {
55 | return false;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%"=="" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%"=="" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if %ERRORLEVEL% equ 0 goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if %ERRORLEVEL% equ 0 goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | set EXIT_CODE=%ERRORLEVEL%
84 | if %EXIT_CODE% equ 0 set EXIT_CODE=1
85 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
86 | exit /b %EXIT_CODE%
87 |
88 | :mainEnd
89 | if "%OS%"=="Windows_NT" endlocal
90 |
91 | :omega
92 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/unix/UnixServer.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.unix;
2 |
3 | import com.intellij.openapi.project.Project;
4 | import com.plugins.mybaitslog.Config;
5 | import com.plugins.mybaitslog.console.PrintlnUtil;
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.net.StandardProtocolFamily;
9 | import java.net.UnixDomainSocketAddress;
10 | import java.nio.ByteBuffer;
11 | import java.nio.channels.ServerSocketChannel;
12 | import java.nio.channels.SocketChannel;
13 | import java.nio.file.Files;
14 | import java.nio.file.Path;
15 | import java.util.Map;
16 | import java.util.UUID;
17 | import java.util.concurrent.ConcurrentHashMap;
18 |
19 | /**
20 | * A RmiServer Class
21 | *
22 | * @author lk
23 | * @version 1.0
24 | * date: 2023/5/12 19:20
25 | */
26 | public class UnixServer {
27 |
28 | public static Map RMISERVERID = new ConcurrentHashMap();
29 |
30 | public static String getId(@NotNull Project project) {
31 | return RMISERVERID.get(project);
32 | }
33 |
34 | public static void boot(@NotNull Project project) {
35 | String id = UUID.randomUUID().toString().replace("-", "");
36 | RMISERVERID.put(project, id);
37 | //无法支持到1.8后续再想办法
38 | /*
39 | final boolean runRmi = Config.Idea.getRunRmi();
40 | if (runRmi) {
41 | new Thread(new Runnable() {
42 | @Override
43 | public void run() {
44 | try {
45 | String id = UUID.randomUUID().toString().replace("-", "");
46 | RMISERVERID.put(project, id);
47 | Path socketPath = Path
48 | .of(System.getProperty("java.io.tmpdir"))
49 | .resolve(id + ".socket");
50 | Files.deleteIfExists(socketPath);
51 | ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(StandardProtocolFamily.UNIX);
52 | UnixDomainSocketAddress of = UnixDomainSocketAddress.of(socketPath);
53 | serverSocketChannel.bind(of);
54 | while (true) {
55 | SocketChannel socketChannel = serverSocketChannel.accept();
56 | ByteBuffer buf = ByteBuffer.allocate(1024);
57 | int bytesRead = socketChannel.read(buf);
58 | while (bytesRead > 0) {
59 | buf.flip();
60 | StringBuffer stringBuffer = new StringBuffer();
61 | while (buf.hasRemaining()) {
62 | stringBuffer.append((char) buf.get());
63 | }
64 | buf.clear();
65 | PrintlnUtil.prints(project, stringBuffer.toString());
66 | bytesRead = socketChannel.read(buf);
67 | }
68 | }
69 | } catch (Exception e) {
70 | e.printStackTrace();
71 | }
72 | }
73 | }).start();
74 | }*/
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatis/Index.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatis;
2 |
3 |
4 | import com.linkkou.mybatislog.mybatis.boot.App;
5 | import com.linkkou.mybatislog.orm.dao.EmployeesDao;
6 | import com.linkkou.mybatislog.orm.domain.Employees;
7 | import com.plugins.mybaitslog.transformer;
8 | import org.junit.jupiter.api.Test;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.boot.test.context.SpringBootTest;
11 |
12 | import java.time.LocalDate;
13 | import java.util.List;
14 | import java.util.concurrent.CountDownLatch;
15 |
16 | /**
17 | * A main Class
18 | *
19 | * @author lk
20 | * @version 1.0
21 | * date: 2023/5/9 12:11
22 | */
23 | @SpringBootTest(classes = App.class)
24 | public class Index {
25 |
26 | @Autowired
27 | private EmployeesDao employeesDao;
28 |
29 | static {
30 | //注入
31 | final transformer transformer = new transformer(null);
32 | transformer.transform("test");
33 | }
34 |
35 | @Test
36 | public void queryById() {
37 | final Employees employees = employeesDao.queryById(12);
38 | System.out.println(employees);
39 | }
40 |
41 | @Test
42 | public void queryByJson() {
43 | final Employees employees = employeesDao.queryByInjectJson("12");
44 | System.out.println(employees);
45 | }
46 |
47 | @Test
48 | public void queryByMultiple() {
49 | final Employees employees = new Employees();
50 | employees.setEmpNo(12);
51 | employees.setLastName("");
52 | final List query = employeesDao.queryByMultiple(employees);
53 | System.out.println(employees);
54 | }
55 |
56 | @Test
57 | public void queryByInject() {
58 | final Employees employees = employeesDao.queryByInject("'cs' or '1=1'");
59 | System.out.println(employees);
60 | }
61 |
62 | @Test
63 | public void queryByInjectD() {
64 | final Employees employees = employeesDao.queryByInjectD("111");
65 | System.out.println(employees);
66 | }
67 |
68 | @Test
69 | public void queryByInjectE() {
70 | final Employees employees = employeesDao.queryByInjectD("[httpServerRequest[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@67b80766]]");
71 | System.out.println(employees);
72 | }
73 |
74 |
75 | @Test
76 | public void queryByInjectLocalDate() {
77 | final LocalDate now = LocalDate.now();
78 | final Employees employees = employeesDao.queryByInjectLocalDate(now);
79 | System.out.println(employees);
80 | }
81 |
82 | @Test
83 | public void queryByInjectThread() throws InterruptedException {
84 | CountDownLatch countDownLatch = new CountDownLatch(1);
85 | int i = 5;
86 | for (int i1 = 0; i1 < i; i1++) {
87 | Thread t = new Thread(new Runnable() {
88 | @Override
89 | public void run() {
90 | while (true) {
91 | final Employees employees = new Employees();
92 | employees.setEmpNo(12);
93 | employees.setLastName("");
94 | final List query = employeesDao.queryByMultiple(employees);
95 | }
96 | }
97 | });
98 | t.start();
99 | }
100 | countDownLatch.await();
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatis/boot/config/EnableDataSourceImpl.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatis.boot.config;
2 |
3 | import com.alibaba.druid.pool.DruidDataSource;
4 | import com.linkkou.mybatislog.mybatis.boot.plugins.QueryPaginatorInterceptor;
5 | import org.apache.ibatis.session.SqlSessionFactory;
6 | import org.mybatis.spring.SqlSessionFactoryBean;
7 | import org.mybatis.spring.SqlSessionTemplate;
8 | import org.mybatis.spring.annotation.MapperScan;
9 | import org.springframework.beans.factory.annotation.Qualifier;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.context.annotation.Bean;
12 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
13 | import org.springframework.jdbc.datasource.DataSourceTransactionManager;
14 |
15 | import javax.sql.DataSource;
16 | import java.sql.SQLException;
17 |
18 | /**
19 | * 数据源配置
20 | *
21 | * @author deppon
22 | * @version 1.0
23 | * @date 2020/9/10 19:05
24 | */
25 | @MapperScan(basePackages = {"com.linkkou.mybatislog.orm.**.dao"}, sqlSessionTemplateRef = EnableDataSourceImpl.MAPPER_SCANNER_CONFIGURER)
26 | public class EnableDataSourceImpl {
27 |
28 | public static final String MAPPER_LOCATION = "classpath*:/**/*Mapper.xml";
29 | public static final String DATASOURCE_NAME = "dataSourceAuth";
30 | public static final String TX_AUTHM_ANAGER = "txAuthManager";
31 | public static final String MAPPER_SCANNER_CONFIGURER = "mapperScannerConfigurerAuth";
32 | public static final String SQLSESSIONFACTORY_NAME = "sqlSessionFactoryAuth";
33 |
34 | @Bean(DATASOURCE_NAME)
35 | public DataSource buildDataSource(@Value("${datasource.url}") String url, @Value("${datasource.username}") String username, @Value("${datasource.password}") String password) throws SQLException {
36 | DruidDataSource dataSource = new DruidDataSource();
37 | dataSource.setUrl(url);
38 | dataSource.setMinIdle(20);
39 | dataSource.setMaxActive(20);
40 | dataSource.setMaxWait(6000);
41 | dataSource.setTimeBetweenEvictionRunsMillis(60000);
42 | dataSource.setMinEvictableIdleTimeMillis(300000);
43 | dataSource.setTestWhileIdle(true);
44 | dataSource.setTestOnBorrow(false);
45 | dataSource.setPoolPreparedStatements(true);
46 | dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
47 | dataSource.setFilters("stat");
48 | dataSource.setUsername(username);
49 | dataSource.setPassword(password);
50 | return dataSource;
51 | }
52 |
53 | @Bean(SQLSESSIONFACTORY_NAME)
54 | public SqlSessionFactory buildSqlSessionFactory(@Qualifier(DATASOURCE_NAME) DataSource dataSource) throws Exception {
55 | SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
56 | sqlSessionFactoryBean.setDataSource(dataSource);
57 | //sqlSessionFactoryBean.setPlugins(new QueryPaginatorInterceptor());
58 | sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
59 | return sqlSessionFactoryBean.getObject();
60 | }
61 |
62 | @Bean(TX_AUTHM_ANAGER)
63 | public DataSourceTransactionManager worldTransactionManager(@Qualifier(DATASOURCE_NAME) DataSource dataSource) {
64 | return new DataSourceTransactionManager(dataSource);
65 | }
66 |
67 |
68 | @Bean(MAPPER_SCANNER_CONFIGURER)
69 | public SqlSessionTemplate worldSqlSessionTemplate(@Qualifier(SQLSESSIONFACTORY_NAME) SqlSessionFactory sqlSessionFactory) throws Exception {
70 | return new SqlSessionTemplate(sqlSessionFactory);
71 | }
72 |
73 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [](https://github.com/Link-Kou/intellij-mybaitslog) Mybatislog
2 |
3 | 
4 | 
5 | 
6 |
7 | ### Mybatislog能做什么?
8 |
9 | > Mybatislog是基于IntelliJ 开发的插件项目,用来格式化输出Mybatis的Sql。
10 |
11 | 
12 |
13 | 
14 |
15 |
16 | ### 在线安装(搜索)
17 |
18 | IDEA --> Setting --> Plugins --> 搜索 MyBatis Log EasyPlus
19 |
20 | 
21 |
22 |
23 | ### 捐赠 | Donate
24 |
25 | > 虽然日常时间很忙碌,也为了碎银几两而发愁,但是希望借此慰藉心中早已经开始缥缈的诗与远方。
26 | > 欢迎Fork,欢迎继续扩展
27 |
28 |
29 | ## ★★超级无敌丝滑★★
30 | > 版本V5.支持所有数据库的所有SQL都能均能正常格式化输出
31 | > 版本V5.插件支持IDEA版本2020.1以上
32 | > 版本V5.JKD8以上
33 | > 版本V5.插件支持Mybatis版本3.2.0以上,3.2.0已经是2013发布的。所以更低版本将不在支持
34 | > 版本V5.插件对MybatisPlus等插件也进行了测试,目前大多数功能已支持
35 |
36 | ## ★★已知问题★★
37 | > 不支持Gradle,正在想办法中。如有路过大神知道如何解决还请度化本项目一下。
38 | > 不支持自定义实现SqlSource,有解决办法测试不理想,在继续想办法中。
39 |
40 | ### Sponsors
41 |
42 |
49 |
50 | #### 2023.08.20 -> 最后一个支持《IDEA 2021.1》的版本,感谢各位社区伙伴的测试反馈,现已修复若干个已知问题,装备下一个版本大迭代
51 |
52 | #### 2023.05.28 -> 对额外的扩展插件进行支持
53 |
54 | #### 2023.05.22 -> 《IDEA 2021.1 以上》感谢各位社区伙伴的测试反馈,现已修复若干个已知问题
55 |
56 | #### 2023.05.11 -> 《IDEA 2021.1 以上》★★★优化了对mybatis-plus的支持,添加了对参数自动解析能力,现已修复若干个已知问题★★★
57 |
58 | #### 2023.04.19 -> 《IDEA 2021.1 以上》感谢各位社区伙伴的测试反馈,现已修复若干个已知问题
59 |
60 | #### 2023.04.10 -> 《IDEA 2019.3 以上》感谢各位社区伙伴的测试反馈,现已修复若干个输出格式化的问题
61 |
62 | #### 2023.03.30 -> 《IDEA 2019.3 以上》★★★超级重大更新,从版本V5将实现丝滑体验;多IDEA版本支持★★★
63 |
64 | #### 2022.12.01 -> V4不断探索
65 |
66 | #### 2022.08.16 -> ★★★重大更新,从版本V3开始将彻底解决字符串替代弊端,支持所有数据库★★★
67 |
68 | #### 2021.06.12 -> 《IDEA 2021.3 测试通过支持使用。》
69 |
70 | #### 2021.01.18 -> 支持IDEA:2020.3.1,Master代码升级到IDEA2020.3.1版本(JAVA_11版本)
71 |
72 | #### 2021.01.31 -> 发布2.0包。不向下兼容IDEA:2020.3以下版本,拥抱Java11,代码将保持兼容度,如果需要2020.3以下包支持,自行编译以下。
73 |
74 | #### 2021.02.11 -> 发布2.0.1包。修复兼容性问题,不兼容还是会有不少后遗症。
75 |
76 | #### 2021.06.15 -> 发布2.0.5包。修复无法自定义关键字问题。
77 |
78 | #### 2021.09.16 -> 发布2.0.6包。增加自动生成字面量按钮。
79 |
80 | #### 2021.12.15 -> 支持IDEA 2020.3 发布2.0.7包。修复无法自定义关键字问题。
81 |
82 | #### 2020.08.11 -> 《IDEA 2020.2 测试通过支持使用。》
83 |
84 | #### 2020.08.25 -> 重构代码所有代码,代码中完善备注信息
85 |
86 | #### 2020.09.19 -> 添加对特点类型的引号支持
87 |
88 | #### 2020.10.07 -> 支持2020.2.3版本
89 |
90 | #### 2020.11.20 -> 改进分隔判断,由单纯通过,判断会存在无法对文本正常分隔的情况下。
91 |
92 | #### 2020.12.18 -> 改进Like判断异常(解决还不够优雅,不影响正常使用)。
93 |
94 | #### 2020.12.19 -> 添加可选是否格式化。
95 |
96 | ---
97 |
98 | ### 使用环境
99 |
100 | `IntelliJ IDEA Ultimate版(191+)`
101 |
102 | ### 源代码构建
103 |
104 | 项目管理:Gradle
105 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/PluginUtil.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | import com.intellij.ide.plugins.IdeaPluginDescriptor;
4 | import com.intellij.ide.plugins.PluginManagerCore;
5 | import com.intellij.notification.*;
6 | import com.intellij.openapi.actionSystem.AnAction;
7 | import com.intellij.openapi.actionSystem.AnActionEvent;
8 | import com.intellij.openapi.application.ApplicationInfo;
9 | import com.intellij.openapi.extensions.PluginId;
10 | import com.intellij.openapi.ui.MessageType;
11 | import com.plugins.mybaitslog.gui.FilterSetting;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import javax.swing.event.HyperlinkEvent;
15 | import java.io.File;
16 | import java.io.FileOutputStream;
17 | import java.io.InputStream;
18 | import java.lang.reflect.Method;
19 | import java.net.URL;
20 |
21 | public class PluginUtil {
22 |
23 | /**
24 | * 获取核心Jar路径
25 | *
26 | * @return String
27 | */
28 | public static String getAgentCoreJarPath() {
29 | return getJarPathByStartWith();
30 | }
31 |
32 | /**
33 | * 根据jar包的前缀名称获路径
34 | *
35 | * @return String
36 | */
37 | private static String getJarPathByStartWith() {
38 | PluginId pluginId = PluginId.getId("com.linkkou.plugin.intellij.assistant.mybaitslog");
39 | final File filePlugin = PluginManagerCore.getPlugin(pluginId).getPluginPath().toFile();
40 | final File[] fileslibs = filePlugin.listFiles();
41 | for (File listFile : fileslibs) {
42 | if ("lib".equals(listFile.getName())) {
43 | final File[] fileslib = listFile.listFiles();
44 | for (File file : fileslib) {
45 | //优化非写死
46 | if (file.getName().contains("mybatis-agent")) {
47 | return file.toPath().toString();
48 | }
49 | }
50 | }
51 | }
52 | return null;
53 | }
54 |
55 | public static void Notificat_AddConfiguration() {
56 | NotificationListener.Adapter notificationListener = new NotificationListener.Adapter() {
57 | @Override
58 | protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
59 | // e.getDescription() 的值就是标签 a 中的 href 属性值
60 | //启动filter配置
61 | FilterSetting dialog = new FilterSetting();
62 | dialog.pack();
63 | dialog.setSize(520, 420);//配置大小
64 | dialog.setResizable(true);
65 | dialog.setLocationRelativeTo(null);//位置居中显示
66 | dialog.setVisible(true);
67 | }
68 | };
69 | String content = "There is a new unknown actuator, Please exclude the options for configuration.Open the configuration window";
70 | NotificationGroup notificationGroup = new NotificationGroup("Notification", NotificationDisplayType.BALLOON, false);
71 | Notification notification = notificationGroup.createNotification("MyBatis Log EasyPlus", "", content, NotificationType.WARNING, notificationListener);
72 | Notifications.Bus.notify(notification);
73 | }
74 |
75 | public static void Notificat_Success() {
76 | String content = "MyBatis Log EasyPlus Run";
77 | NotificationGroup notificationGroup = new NotificationGroup("Notification", NotificationDisplayType.BALLOON, false);
78 | Notification notification = notificationGroup.createNotification("MyBatis Log EasyPlus", "", content, NotificationType.INFORMATION);
79 | Notifications.Bus.notify(notification);
80 | }
81 |
82 | public static void Notificat_Error(String error) {
83 | String content = error + ", MyBatis Log EasyPlus Unable to Run";
84 | NotificationGroup notificationGroup = new NotificationGroup("Notification", NotificationDisplayType.BALLOON, false);
85 | Notification notification = notificationGroup.createNotification("MyBatis Log EasyPlus", "", content, NotificationType.ERROR);
86 | Notifications.Bus.notify(notification);
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/PerRun.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | import com.intellij.execution.Executor;
4 | import com.intellij.execution.configurations.JavaParameters;
5 | import com.intellij.execution.configurations.ParametersList;
6 | import com.intellij.execution.configurations.RunConfiguration;
7 | import com.intellij.execution.configurations.RunProfile;
8 | import com.intellij.execution.runners.JavaProgramPatcher;
9 | import com.intellij.openapi.projectRoots.JavaSdk;
10 | import com.intellij.openapi.projectRoots.JavaSdkVersion;
11 | import com.intellij.openapi.projectRoots.Sdk;
12 | import com.intellij.openapi.diagnostic.Logger;
13 | import com.plugins.mybaitslog.unix.UnixServer;
14 |
15 | import java.util.*;
16 |
17 | public class PerRun extends JavaProgramPatcher {
18 |
19 | private Logger LOG = Logger.getInstance(PerRun.class);
20 |
21 | //com.intellij.execution.junit
22 | @Override
23 | public void patchJavaParameters(Executor executor, RunProfile configuration, JavaParameters javaParameters) {
24 | if (!Config.Idea.getStartup()) {
25 | return;
26 | }
27 | if (!(configuration instanceof RunConfiguration)) {
28 | PluginUtil.Notificat_AddConfiguration();
29 | }
30 | final String name = configuration.getClass().getPackage().getName();
31 | //默认关闭,做个冒泡提示
32 | Config.Idea.setPerRunMap(name, false, false);
33 | //IDEA中有大量的执行器。这里需要做排除和生效处理
34 | final Map perRunMap = Config.Idea.getPerRunMap();
35 | if (!perRunMap.get(name)) {
36 | return;
37 | }
38 | String id = null;
39 | if (configuration instanceof RunConfiguration) {
40 | final RunConfiguration runConfiguration = (RunConfiguration) configuration;
41 | id = UnixServer.getId(runConfiguration.getProject());
42 | }
43 | //
44 | Sdk jdk = javaParameters.getJdk();
45 | if (Objects.isNull(jdk)) {
46 | PluginUtil.Notificat_Error("JDK does not exist in the project");
47 | return;
48 | }
49 | JavaSdkVersion version = JavaSdk.getInstance().getVersion(jdk);
50 | if (Objects.isNull(version)) {
51 | return;
52 | }
53 | if (version.compareTo(JavaSdkVersion.JDK_1_8) < 0) {
54 | PluginUtil.Notificat_Error("JDK < 1.8");
55 | return;
56 | }
57 | String agentCoreJarPath = PluginUtil.getAgentCoreJarPath();
58 | if (null != agentCoreJarPath) {
59 | //RunConfiguration runConfiguration = (RunConfiguration) configuration;
60 | ParametersList vmParametersList = javaParameters.getVMParametersList();
61 | String agentParameter = "-javaagent:" + agentCoreJarPath;
62 | LOG.info("MyBatis Log EasyPlus" + agentParameter);
63 | //JDK17的改进
64 | final JavaSdkVersion javaSdkVersion = JavaSdkVersion.fromVersionString("17");
65 | if (null != javaSdkVersion && version.compareTo(javaSdkVersion) >= 0) {
66 | final ArrayList addOpens = Config.Idea.getAddOpens();
67 | for (String opens : addOpens) {
68 | if (!vmParametersList.hasParameter(opens)) {
69 | vmParametersList.addParametersString(opens);
70 | }
71 | }
72 | }
73 | if (!vmParametersList.hasParameter(agentParameter)) {
74 | if (null != id) {
75 | agentParameter += "=" + id;
76 | }
77 | vmParametersList.prepend(agentParameter);
78 | }
79 | if (Config.Idea.getRunNotification()) {
80 | PluginUtil.Notificat_Success();
81 | }
82 | //vmParametersList.addParametersString("-javaagent:\"" + agentCoreJarPath + "\"");
83 | //vmParametersList.addNotEmptyProperty("guide-idea-plugin-probe.projectId", runConfiguration.getProject().getLocationHash());
84 | } else {
85 | PluginUtil.Notificat_Error("Agent Jar Path Error");
86 | }
87 | }
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/console/ConsolePanel.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.console;
2 |
3 | import com.intellij.execution.filters.Filter;
4 | import com.intellij.execution.filters.TextConsoleBuilder;
5 | import com.intellij.execution.filters.TextConsoleBuilderFactory;
6 | import com.intellij.execution.ui.ConsoleView;
7 | import com.intellij.openapi.actionSystem.ActionManager;
8 | import com.intellij.openapi.actionSystem.ActionToolbar;
9 | import com.intellij.openapi.actionSystem.AnAction;
10 | import com.intellij.openapi.actionSystem.DefaultActionGroup;
11 | import com.intellij.openapi.project.Project;
12 | import com.intellij.openapi.ui.SimpleToolWindowPanel;
13 | import com.plugins.mybaitslog.gui.FilterSetting;
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | import javax.swing.*;
17 | import java.awt.*;
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * console 窗口
23 | *
24 | * @author lk
25 | * @version 1.0
26 | * @date 2020/4/10 22:00
27 | */
28 | public class ConsolePanel {
29 |
30 | private final List myFilterList = new ArrayList<>();
31 |
32 | /**
33 | * 创建 输出面板
34 | *
35 | * @param project 项目
36 | * @return
37 | */
38 | private ConsoleView createConsole(@NotNull Project project) {
39 | TextConsoleBuilder consoleBuilder = TextConsoleBuilderFactory.getInstance().createBuilder(project);
40 | consoleBuilder.filters(myFilterList);
41 | ConsoleView console = consoleBuilder.getConsole();
42 | PrintlnUtil.setConsoleView(project, console);
43 | PrintlnUtil.printsInit(console);
44 | return console;
45 | }
46 |
47 |
48 | private static JComponent createConsolePanel(ConsoleView view) {
49 | JPanel panel = new JPanel();
50 | panel.setLayout(new BorderLayout());
51 | panel.add(view.getComponent(), BorderLayout.CENTER);
52 | return panel;
53 | }
54 |
55 |
56 | /**
57 | * 构建面板
58 | */
59 | public JComponent getConsolePanel(final Project myProject) {
60 | final ConsoleView consoleView = createConsole(myProject);
61 | //左边显示的控件
62 | final JComponent consolePanel = createConsolePanel(consoleView);
63 | final ActionToolbar actionToolbar = createActionToolbar(myProject, consolePanel, consoleView);
64 | actionToolbar.setTargetComponent(consolePanel);
65 | SimpleToolWindowPanel panel = new SimpleToolWindowPanel(false, true);
66 | panel.setContent(consolePanel);
67 | panel.setToolbar(actionToolbar.getComponent());
68 | DefaultActionGroup actions = new DefaultActionGroup();
69 | for (AnAction action : consoleView.createConsoleActions()) {
70 | actions.add(action);
71 | }
72 | final JComponent component = panel.getComponent();
73 | return component;
74 | }
75 |
76 | /**
77 | * 创建工具栏
78 | *
79 | * @param consolePanel 输出面板
80 | * @param consoleView 输出窗口
81 | * @return
82 | */
83 | @NotNull
84 | private ActionToolbar createActionToolbar(final Project project, JComponent consolePanel, ConsoleView consoleView) {
85 | final DefaultActionGroup actionGroup = new DefaultActionGroup();
86 | ConsoleActionGroup.withFilter(() -> {
87 | //启动filter配置
88 | FilterSetting dialog = new FilterSetting();
89 | dialog.pack();
90 | dialog.setSize(520, 420);//配置大小
91 | dialog.setResizable(true);
92 | dialog.setLocationRelativeTo(null);//位置居中显示
93 | dialog.setVisible(true);
94 | });
95 | actionGroup.add(new ConsoleActionGroup.FilterAction());
96 | actionGroup.addAll(consoleView.createConsoleActions());
97 | /*actionGroup.add(consoleView.createConsoleActions()[2]);
98 | actionGroup.add(consoleView.createConsoleActions()[3]);
99 | actionGroup.add(consoleView.createConsoleActions()[5]);*/
100 | return ActionManager.getInstance().createActionToolbar("EventLog", actionGroup, false);
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | com.linkkou.plugin.intellij.assistant.mybaitslog
3 | MyBatis Log EasyPlus
4 | linkkou
5 |
6 |
7 | 5.0.8.2
8 |
9 |
10 |
11 | MyBatis Log EasyPlus plugin for IntelliJ IDEs.
13 | Output the MyBatis log information with formatting
14 |
15 | English:
16 | - Support all SQL formatted output for all databases above MyBatis3.2.0
17 | - This is a MybaitLog output plugin that lets you feel silky
18 | 中文:
19 | - 支持MyBatis3.2.0以上所有数据库的所有SQL格式化输出
20 | - 这是一个让你感受丝滑的MybaitLog输出插件
21 |
22 |
23 |
24 |
25 | ]]>
26 |
27 |
28 |
30 | 5.0.8
31 | 修正部分也知问题;优化界面感官
32 | Correct part of the problem; optimize the interface senses.
33 |
34 |
35 | 5.0.7
36 | - 修正部分也知问题
37 | - The correction part is also aware of the problem.
38 |
39 |
40 | 5.0.6
41 | - 修复颜色设置bug
42 | - Fixed a color setting bug
43 |
44 |
45 | 5.0.5
46 | - 参数转换JSON未经过对象复杂度判断
47 | - Parameter conversion JSON is not determined by object complexity
48 |
49 |
50 | 5.0.4
51 | - 改进对JRebel支持
52 | - Optimize support for JRebel
53 |
54 |
55 | 5.0.3
56 | - 添加执行器过滤
57 | - Add actuator filtering
58 |
59 |
60 | 5.0.2
61 | - 改进JDK17的支持
62 | - Improved support for JDK17
63 |
64 |
65 | 5.0.1
66 | - 修正GSON未依赖的BUG
67 | - Fixed a BUG where GSON was not dependent
68 |
69 |
70 | 5.0.0
71 | - 支持MyBatis输出的Sql进行格式化
72 | - Support MyBatis output Sql for formatting
73 |
74 | ]]>
75 |
76 |
77 |
79 |
80 |
81 |
82 | com.intellij.modules.lang
83 | com.intellij.modules.platform
84 | com.intellij.modules.java
85 | com.intellij.gradle
86 |
87 |
88 |
89 |
90 |
91 |
92 |
94 |
95 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatisplus/boot/config/EnableDataSourceImpl.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatislog.mybatisplus.boot.config;
2 |
3 | import com.alibaba.druid.pool.DruidDataSource;
4 | import com.baomidou.mybatisplus.annotation.DbType;
5 | import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
6 | import com.baomidou.mybatisplus.core.MybatisConfiguration;
7 | import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
8 | import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
9 | import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
10 | import org.apache.ibatis.session.SqlSessionFactory;
11 | import org.mybatis.spring.SqlSessionFactoryBean;
12 | import org.mybatis.spring.SqlSessionTemplate;
13 | import org.mybatis.spring.annotation.MapperScan;
14 | import org.springframework.beans.factory.annotation.Qualifier;
15 | import org.springframework.beans.factory.annotation.Value;
16 | import org.springframework.context.annotation.Bean;
17 | import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
18 | import org.springframework.jdbc.datasource.DataSourceTransactionManager;
19 |
20 | import javax.sql.DataSource;
21 | import java.sql.SQLException;
22 | import java.util.Properties;
23 |
24 | /**
25 | * 数据源配置
26 | *
27 | * @author deppon
28 | * @version 1.0
29 | * @date 2020/9/10 19:05
30 | */
31 | @MapperScan(basePackages = {"com.linkkou.mybatislog.orm.**.dao", "com.baomidou.mybatisplus.samples.quickstart.mapper"}, sqlSessionTemplateRef = EnableDataSourceImpl.MAPPER_SCANNER_CONFIGURER)
32 | public class EnableDataSourceImpl {
33 |
34 | public static final String MAPPER_LOCATION = "classpath*:mybatis/mapper/run/*.xml";
35 | public static final String DATASOURCE_NAME = "dataSourceAuth";
36 | public static final String TX_AUTHM_ANAGER = "txAuthManager";
37 | public static final String MAPPER_SCANNER_CONFIGURER = "mapperScannerConfigurerAuth";
38 | public static final String SQLSESSIONFACTORY_NAME = "sqlSessionFactoryAuth";
39 |
40 | @Bean(DATASOURCE_NAME)
41 | public DataSource buildDataSource(@Value("${datasource.url}") String url, @Value("${datasource.username}") String username, @Value("${datasource.password}") String password) throws SQLException {
42 | DruidDataSource dataSource = new DruidDataSource();
43 | dataSource.setUrl(url);
44 | dataSource.setMinIdle(20);
45 | dataSource.setMaxActive(20);
46 | dataSource.setMaxWait(6000);
47 | dataSource.setTimeBetweenEvictionRunsMillis(60000);
48 | dataSource.setMinEvictableIdleTimeMillis(300000);
49 | dataSource.setTestWhileIdle(true);
50 | dataSource.setTestOnBorrow(false);
51 | dataSource.setPoolPreparedStatements(true);
52 | dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
53 | dataSource.setFilters("stat");
54 | dataSource.setUsername(username);
55 | dataSource.setPassword(password);
56 | return dataSource;
57 | }
58 |
59 | /**
60 | * 新的分页插件,一缓和二缓遵循mybatis的规则,需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
61 | */
62 | @Bean("mybatisPlusInterceptor")
63 | public MybatisPlusInterceptor mybatisPlusInterceptor() {
64 | MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
65 | final PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
66 | paginationInnerInterceptor.setDbType(DbType.MYSQL);
67 | paginationInnerInterceptor.setOptimizeJoin(true);
68 | paginationInnerInterceptor.setOverflow(true);
69 | interceptor.addInnerInterceptor(paginationInnerInterceptor);
70 | return interceptor;
71 | }
72 |
73 | @Bean(SQLSESSIONFACTORY_NAME)
74 | public SqlSessionFactory buildSqlSessionFactory(@Qualifier(DATASOURCE_NAME) DataSource dataSource,@Qualifier("mybatisPlusInterceptor") MybatisPlusInterceptor mybatisPlusInterceptor) throws Exception {
75 | MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
76 | bean.setDataSource(dataSource);
77 | bean.setPlugins(mybatisPlusInterceptor);
78 | bean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(MAPPER_LOCATION));
79 | return bean.getObject();
80 | }
81 |
82 | @Bean(TX_AUTHM_ANAGER)
83 | public DataSourceTransactionManager worldTransactionManager(@Qualifier(DATASOURCE_NAME) DataSource dataSource) {
84 | return new DataSourceTransactionManager(dataSource);
85 | }
86 |
87 |
88 | @Bean(MAPPER_SCANNER_CONFIGURER)
89 | public SqlSessionTemplate worldSqlSessionTemplate(@Qualifier(SQLSESSIONFACTORY_NAME) SqlSessionFactory sqlSessionFactory) throws Exception {
90 | return new SqlSessionTemplate(sqlSessionFactory);
91 | }
92 |
93 | }
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/gui/FilterSetting.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.gui;
2 |
3 | import com.intellij.ui.ColorChooser;
4 | import com.plugins.mybaitslog.Config;
5 | import com.plugins.mybaitslog.gui.compone.MyColorButton;
6 | import com.plugins.mybaitslog.gui.compone.MyTableModel;
7 |
8 | import javax.swing.*;
9 | import javax.swing.table.TableModel;
10 | import java.awt.*;
11 | import java.awt.event.KeyEvent;
12 | import java.awt.event.WindowAdapter;
13 | import java.awt.event.WindowEvent;
14 | import java.util.Map;
15 |
16 | /**
17 | * 过滤设置 窗口
18 | *
19 | * @author lk
20 | * @version 1.0
21 | * @date 2020/8/23 17:14
22 | */
23 | public class FilterSetting extends JDialog {
24 | private JPanel contentPane;
25 | private JButton buttonOK;
26 | private JButton buttonCancel;
27 | private JTextField preparingTextField;
28 | private JCheckBox startupCheckBox;
29 | private JPanel jpanel_select;
30 | private JPanel jpanel_update;
31 | private JPanel jpanel_delect;
32 | private JPanel jpanel_insert;
33 | private JPanel jpanel_other;
34 | private JTextArea addOpensTextArea;
35 | private JTable excludeTable;
36 | private JCheckBox checkBox_sql;
37 | private JCheckBox checkBox_notification;
38 | private JCheckBox checkBox_fold;
39 | private JCheckBox checkBox_welcome;
40 | private JCheckBox checkBox_rmi;
41 |
42 |
43 | /**
44 | * 窗口初始化
45 | */
46 | public FilterSetting() {
47 | //设置标题
48 | this.setTitle("Filter Setting");
49 | this.setBackground(Color.WHITE);
50 | this.preparingTextField.setText(Config.Idea.getParameters());
51 | //PropertiesComponent.getInstance(project).getInt(Config.Idea.DB_STARTUP_KEY, 1);
52 | boolean startup = Config.Idea.getStartup();
53 | boolean formatSql = Config.Idea.getFormatSql();
54 | boolean notification = Config.Idea.getRunNotification();
55 | boolean welcomeMessage = Config.Idea.getWelcomeMessage();
56 | boolean whetherfold = Config.Idea.getWhetherfold();
57 | boolean runrmi = Config.Idea.getRunRmi();
58 |
59 | startupCheckBox.setSelected(startup);
60 | checkBox_sql.setSelected(formatSql);
61 | checkBox_notification.setSelected(notification);
62 | checkBox_fold.setSelected(whetherfold);
63 | checkBox_welcome.setSelected(welcomeMessage);
64 | checkBox_rmi.setSelected(runrmi);
65 |
66 | setContentPane(contentPane);
67 | setModal(true);
68 | getRootPane().setDefaultButton(buttonOK);
69 |
70 | //region 自定义控件
71 | final MyTableModel myTableModel = new MyTableModel();
72 | final Map perRunMap = Config.Idea.getPerRunMap();
73 | for (Map.Entry next : perRunMap.entrySet()) {
74 | myTableModel.addRow(new Object[]{next.getKey(), next.getValue()});
75 | }
76 | this.excludeTable.setModel(myTableModel);
77 |
78 | addOpensTextArea.setText(String.join("\n", Config.Idea.getAddOpens()));
79 | String[] colorname = {"select", "update", "delete", "insert", "other"};
80 | for (String s : colorname) {
81 | final MyColorButton myColorButton = new MyColorButton(Config.Idea.getColor(s));
82 | myColorButton.addActionListener(e -> onColor(s, myColorButton));
83 | switch (s) {
84 | case "select":
85 | this.jpanel_select.add(myColorButton);
86 | break;
87 | case "update":
88 | this.jpanel_update.add(myColorButton);
89 | break;
90 | case "delete":
91 | this.jpanel_delect.add(myColorButton);
92 | break;
93 | case "insert":
94 | this.jpanel_insert.add(myColorButton);
95 | break;
96 | case "other":
97 | this.jpanel_other.add(myColorButton);
98 | break;
99 | default:
100 | break;
101 | }
102 | }
103 | //endregion
104 |
105 | buttonOK.addActionListener(e -> onOK());
106 | buttonCancel.addActionListener(e -> onCancel());
107 | setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
108 | addWindowListener(new WindowAdapter() {
109 | @Override
110 | public void windowClosing(WindowEvent e) {
111 | onCancel();
112 | }
113 | });
114 | contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
115 | }
116 |
117 |
118 | private void onColor(String type, MyColorButton myColorButton) {
119 | Color newColor = ColorChooser.chooseColor(this, "Choose Color", Color.white, true);
120 | if (null != newColor) {
121 | myColorButton.setColor(newColor);
122 | Config.Idea.setColor(type, newColor);
123 | }
124 | }
125 |
126 | /**
127 | * 点击确认按钮处理
128 | */
129 | private void onOK() {
130 | String preparing = this.preparingTextField.getText();
131 | String addOpens = this.addOpensTextArea.getText();
132 | final TableModel model = this.excludeTable.getModel();
133 | final int rowCount = model.getRowCount();
134 | for (int r = 0; r < rowCount; r++) {
135 | final Object key = model.getValueAt(r, 0);
136 | final Object value = model.getValueAt(r, 1);
137 | Config.Idea.setPerRunMap((String) key, (Boolean) value, true);
138 | }
139 | Config.Idea.setAddOpens(addOpens);
140 | Config.Idea.setParameters(preparing, Config.Idea.PARAMETERS);
141 | Config.Idea.setStartup(startupCheckBox.isSelected() ? 1 : 0);
142 | Config.Idea.setFormatSql(checkBox_sql.isSelected() ? 1 : 0);
143 | Config.Idea.setRunNotification(checkBox_notification.isSelected() ? 1 : 0);
144 | Config.Idea.setWelcomeMessage(checkBox_welcome.isSelected() ? 1 : 0);
145 | Config.Idea.setWhetherfold(checkBox_fold.isSelected() ? 1 : 0);
146 | Config.Idea.setRunRmi(checkBox_rmi.isSelected() ? 1 : 0);
147 | onCancel();
148 | }
149 |
150 | private void onCancel() {
151 | this.setModal(false);
152 | this.setVisible(false);
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/image/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/resources/icons/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/console/PrintlnUtil.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog.console;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.intellij.execution.ui.ConsoleView;
6 | import com.intellij.execution.ui.ConsoleViewContentType;
7 | import com.intellij.openapi.editor.markup.TextAttributes;
8 | import com.intellij.openapi.project.Project;
9 | import com.plugins.mybaitslog.Config;
10 | import org.apache.commons.lang.StringUtils;
11 |
12 | import java.awt.*;
13 | import java.util.Map;
14 | import java.util.concurrent.ConcurrentHashMap;
15 |
16 | /**
17 | * 打印简单工具类
18 | *
19 | * @author lk
20 | * @version 1.0
21 | * @date 2020/8/23 17:14
22 | */
23 | public class PrintlnUtil {
24 |
25 | /**
26 | * 多项目控制台独立性
27 | */
28 | public static Map consoleViewMap = new ConcurrentHashMap<>(16);
29 |
30 |
31 | private static final Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
32 | //当Map的key为复杂对象时,需要开启该方法
33 | .enableComplexMapKeySerialization()
34 | //当字段值为空或null时,依然对该字段进行转换
35 | .serializeNulls()
36 | //防止特殊字符出现乱码
37 | .disableHtmlEscaping().create();
38 |
39 | /**
40 | * Sql语句还原,整个插件的核心就是该方法
41 | *
42 | * @param parametersLine 参数
43 | * @return
44 | */
45 | private static SqlVO restoreSql(final String parametersLine) {
46 | final String[] split = parametersLine.split(Config.Idea.getParameters());
47 | if (split.length == 2) {
48 | final String s = split[1];
49 | return gson.fromJson(s, SqlVO.class);
50 | }
51 | return null;
52 | }
53 |
54 |
55 | public static void printsInit(ConsoleView consoleView) {
56 | if (Config.Idea.getWelcomeMessage()) {
57 | consoleView.print(" ============================================================================ " + "\n", ConsoleViewContentType.NORMAL_OUTPUT);
58 | consoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT);
59 | consoleView.print(" MyBatis Log EasyPlus" + "\n", ConsoleViewContentType.NORMAL_OUTPUT);
60 | consoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT);
61 | consoleView.print(" A mybatis javaagent framework :)" + "\n", ConsoleViewContentType.NORMAL_OUTPUT);
62 | consoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT);
63 | consoleView.print(" https://github.com/Link-Kou/intellij-mybaitslog" + "\n", ConsoleViewContentType.NORMAL_OUTPUT);
64 | consoleView.print("\n", ConsoleViewContentType.NORMAL_OUTPUT);
65 | consoleView.print(" ============================================================================ " + "\n", ConsoleViewContentType.NORMAL_OUTPUT);
66 | }
67 | }
68 |
69 | public static void prints(Project project, String currentLine) {
70 | final String parameters = Config.Idea.getParameters();
71 | if (currentLine.contains(parameters)) {
72 | //序号前缀字符串
73 | final SqlVO sqlVO = restoreSql(currentLine);
74 | if (null != sqlVO) {
75 | String completesql = sqlVO.getCompleteSql().replaceAll("\t|\r|\n", "");
76 | final String id = sqlVO.getId();
77 | final String parameter = sqlVO.getParameter();
78 | if (Config.Idea.getFormatSql()) {
79 | completesql = new BasicFormatter().format(completesql);
80 | }
81 | //序号
82 | PrintlnUtil.println(project, Config.SQL_START_LINE + id + "\n", ConsoleViewContentType.USER_INPUT);
83 | PrintlnUtil.printlnSqlType(project, Config.SQL_MIDDLE_LINE, completesql + "\n");
84 | PrintlnUtil.printlnSqlType(project, Config.SQL_MIDDLE_LINE, parameter + "\n");
85 | PrintlnUtil.println(project, Config.SQL_END_LINE + "\n", ConsoleViewContentType.USER_INPUT);
86 | }
87 | }
88 | }
89 |
90 | /**
91 | * 输出语句
92 | *
93 | * @param project 项目
94 | * @param rowLine 行数据
95 | * @param consoleViewContentType 输出颜色
96 | */
97 | public static void println(Project project, String rowLine, ConsoleViewContentType consoleViewContentType) {
98 | ConsoleView consoleView = consoleViewMap.get(project);
99 | if (consoleView != null) {
100 | consoleView.print(rowLine, consoleViewContentType);
101 | }
102 | }
103 |
104 | public static void setConsoleView(Project project, ConsoleView consoleView) {
105 | consoleViewMap.put(project, consoleView);
106 | }
107 |
108 | public static ConsoleView getConsoleView(Project project) {
109 | return consoleViewMap.get(project);
110 | }
111 |
112 | /**
113 | * 获取Sql语句类型
114 | *
115 | * @param sql 语句
116 | * @return String
117 | */
118 | private static String getSqlType(String sql) {
119 | if (StringUtils.isNotBlank(sql)) {
120 | String lowerLine = sql.toLowerCase().trim();
121 | if (lowerLine.startsWith("insert")) {
122 | return "insert";
123 | }
124 | if (lowerLine.startsWith("update")) {
125 | return "update";
126 | }
127 | if (lowerLine.startsWith("delete")) {
128 | return "delete";
129 | }
130 | if (lowerLine.startsWith("select")) {
131 | return "select";
132 | }
133 | }
134 | return "other";
135 | }
136 |
137 |
138 | /**
139 | * SQL 输出语句
140 | *
141 | * @param rowLine 行数据
142 | */
143 | public static void printlnSqlType(Project project, String title, String rowLine) {
144 | final String sqlType = getSqlType(rowLine);
145 | final ConsoleViewContentType systemOutput = ConsoleViewContentType.SYSTEM_OUTPUT;
146 | final TextAttributes attributes = systemOutput.getAttributes();
147 | final ConsoleViewContentType styleName = new ConsoleViewContentType("styleName", new TextAttributes(attributes.getForegroundColor(), attributes.getBackgroundColor(), attributes.getEffectColor(), attributes.getEffectType(), attributes.getFontType()));
148 | switch (sqlType) {
149 | case "select":
150 | case "insert":
151 | case "update":
152 | case "delete":
153 | final Color color = Config.Idea.getColor(sqlType);
154 | styleName.getAttributes().setForegroundColor(color);
155 | println(project, title + rowLine, styleName);
156 | break;
157 | default:
158 | final Color color1 = Config.Idea.getColor("other");
159 | styleName.getAttributes().setForegroundColor(color1);
160 | println(project, title + rowLine, styleName);
161 | }
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/resources/mapper/EmployeesMapper.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
25 |
26 |
27 |
53 |
54 |
55 |
79 |
80 |
81 |
82 | insert into employees(emp_no, birth_date, first_name, last_name, gender, hire_date)
83 | values (#{empNo}, #{birthDate}, #{firstName}, #{lastName}, #{gender}, #{hireDate})
84 |
85 |
86 |
87 | insert into employees(emp_no, birth_date, first_name, last_name, gender, hire_date)
88 | values
89 |
90 | (#{entity.empNo}, #{entity.birthDate}, #{entity.firstName}, #{entity.lastName}, #{entity.gender},
91 | #{entity.hireDate})
92 |
93 |
94 |
95 |
96 | insert into employees(emp_no, birth_date, first_name, last_name, gender, hire_date)
97 | values
98 |
99 | (#{entity.empNo}, #{entity.birthDate}, #{entity.firstName}, #{entity.lastName}, #{entity.gender},
100 | #{entity.hireDate})
101 |
102 | on duplicate key update
103 | emp_no = values(emp_no),
104 | birth_date = values(birth_date),
105 | first_name = values(first_name),
106 | last_name = values(last_name),
107 | gender = values(gender),
108 | hire_date = values(hire_date)
109 |
110 |
111 |
112 |
113 | update employees
114 |
115 |
116 | emp_no = #{empNo},
117 |
118 |
119 | birth_date = #{birthDate},
120 |
121 |
122 | first_name = #{firstName},
123 |
124 |
125 | last_name = #{lastName},
126 |
127 |
128 | gender = #{gender},
129 |
130 |
131 | hire_date = #{hireDate},
132 |
133 |
134 | where emp_no = #{empNo}
135 |
136 |
137 |
150 |
151 |
152 |
162 |
163 |
164 |
174 |
175 |
176 |
186 |
187 |
196 |
197 |
198 |
199 |
--------------------------------------------------------------------------------
/mybatis-test/src/test/java/com/linkkou/mybatislog/mybatis/boot/plugins/QueryPaginatorInterceptor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License (MIT)
3 | *
4 | * Copyright (c) 2014-2017 abel533@gmail.com
5 | *
6 | * Permission is hereby granted, free of charge, to any person obtaining a copy
7 | * of this software and associated documentation files (the "Software"), to deal
8 | * in the Software without restriction, including without limitation the rights
9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | * copies of the Software, and to permit persons to whom the Software is
11 | * furnished to do so, subject to the following conditions:
12 | *
13 | * The above copyright notice and this permission notice shall be included in
14 | * all copies or substantial portions of the Software.
15 | *
16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | * THE SOFTWARE.
23 | */
24 |
25 | package com.linkkou.mybatislog.mybatis.boot.plugins;
26 |
27 | import net.sf.jsqlparser.JSQLParserException;
28 | import net.sf.jsqlparser.parser.CCJSqlParserUtil;
29 | import net.sf.jsqlparser.statement.select.PlainSelect;
30 | import net.sf.jsqlparser.statement.select.Select;
31 | import net.sf.jsqlparser.util.TablesNamesFinder;
32 | import org.apache.ibatis.cache.CacheKey;
33 | import org.apache.ibatis.executor.Executor;
34 | import org.apache.ibatis.mapping.*;
35 | import org.apache.ibatis.plugin.*;
36 | import org.apache.ibatis.session.ResultHandler;
37 | import org.apache.ibatis.session.RowBounds;
38 |
39 | import java.lang.reflect.Field;
40 | import java.util.ArrayList;
41 | import java.util.List;
42 | import java.util.Properties;
43 |
44 | /**
45 | * 目前只有支持MySQL分页支持
46 | * 需要开启allowMultiQueries
47 | *
48 | * @author lk
49 | * @version 1.0.0
50 | */
51 | @Intercepts(
52 | {
53 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
54 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class})
55 | }
56 | )
57 | //@SuppressWarnings()
58 | public class QueryPaginatorInterceptor implements Interceptor {
59 |
60 | private final static String QUERY = "query";
61 | /**
62 | * FOUND_ROWS == true
63 | * COUNT(*) == false
64 | */
65 | private boolean PAGINATORTYPE = false;
66 |
67 | /**
68 | * 是否支持多条语句执行
69 | */
70 | protected boolean ALLOWMULTIQUERIES = true;
71 |
72 | public void setPaginatortype(boolean paginator) {
73 | this.PAGINATORTYPE = paginator;
74 | }
75 |
76 | @Override
77 | public Object intercept(Invocation invocation) throws Throwable {
78 | final Object[] queryArgs = invocation.getArgs();
79 | if (invocation.getTarget() instanceof Executor && ALLOWMULTIQUERIES) {
80 | final MappedStatement mappedStatement = (MappedStatement) queryArgs[0];
81 | if (SqlCommandType.SELECT == mappedStatement.getSqlCommandType()) {
82 | if (QUERY.equals(invocation.getMethod().getName()) && queryArgs.length == 4) {
83 | final Object MappedStatement = queryArgs[0];
84 | final Object parameter = queryArgs[1];
85 | final BoundSql boundSql = mappedStatement.getBoundSql(parameter);
86 |
87 |
88 | MappedStatement newMs = ProxyResultSetHandler(mappedStatement, new BoundSqlSqlSource(getPagingSql(mappedStatement, boundSql)));
89 | queryArgs[0] = newMs;
90 | }
91 | }
92 | }
93 | return invocation.proceed();
94 | }
95 |
96 | /**
97 | * 返回分页sql语句
98 | *
99 | * @param mappedStatement
100 | * @param boundSql
101 | * @return
102 | */
103 | private BoundSql getPagingSql(MappedStatement mappedStatement, BoundSql boundSql) throws JSQLParserException {
104 | return getSqlCountTrue(mappedStatement, boundSql);
105 | }
106 |
107 | /**
108 | * ALLOWMULTIQUERIES = true count(*) 模式
109 | *
110 | * select rowid, fid
111 | * from t_sysconfig_carspec_config tscc
112 | * WHERE fcar_name = #{car}
113 | * LIMIT
114 | * #{offset},#{rows}
115 | *
116 | *
117 | * @param mappedStatement
118 | * @param boundSql
119 | * @return
120 | */
121 | private BoundSql getSqlCountTrue(MappedStatement mappedStatement, BoundSql boundSql) throws JSQLParserException {
122 | String sql = boundSql.getSql();
123 | String newSql = String.format("select count(*) from (%s);", sql);
124 | List newparameterMappings = new ArrayList<>();
125 | List parameterMappings = boundSql.getParameterMappings();
126 | newparameterMappings.addAll(parameterMappings);
127 | //Limit 去两个参数,所有参数以Mapper顺序为准
128 | for (int i = 0; i < parameterMappings.size() - 2; i++) {
129 | newparameterMappings.add(parameterMappings.get(i));
130 | }
131 | BoundSql countBoundSql = new BoundSql(mappedStatement.getConfiguration(), newSql, newparameterMappings, boundSql.getParameterObject());
132 | return countBoundSql;
133 | }
134 |
135 | /**
136 | * 新加Mapper结构
137 | *
138 | * @param ms
139 | * @param newSqlSource
140 | * @return
141 | */
142 | private MappedStatement ProxyResultSetHandler(MappedStatement ms, SqlSource newSqlSource) {
143 | MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
144 | builder.resource(ms.getResource());
145 | builder.fetchSize(ms.getFetchSize());
146 | builder.statementType(ms.getStatementType());
147 | builder.keyGenerator(ms.getKeyGenerator());
148 | if (ms.getKeyProperties() != null && ms.getKeyProperties().length > 0) {
149 | builder.keyProperty(ms.getKeyProperties()[0]);
150 | }
151 | builder.timeout(ms.getTimeout());
152 | builder.parameterMap(ms.getParameterMap());
153 | builder.resultMaps(newResultMap(ms.getResultMaps()));
154 | builder.resultSetType(ms.getResultSetType());
155 | builder.cache(ms.getCache());
156 | builder.flushCacheRequired(ms.isFlushCacheRequired());
157 | builder.useCache(ms.isUseCache());
158 | return builder.build();
159 | }
160 |
161 | /**
162 | * 构建统一的返回值
163 | * 支持 allowMultiQueries=true的时候ResultMap会返回多值
164 | */
165 | protected List newResultMap(List lrm) {
166 | ResultMap resultMap = new ResultMap.Builder(null, lrm.size() > 0 ? lrm.get(0).getId() : "", Integer.class, new ArrayList()).build();
167 | List list = new ArrayList<>();
168 | if (lrm.size() > 0) {
169 | list.add(lrm.get(0));
170 | }
171 | list.add(resultMap);
172 | return list;
173 | }
174 |
175 | @Override
176 | public Object plugin(Object target) {
177 | return Plugin.wrap(target, this);
178 | }
179 |
180 | @Override
181 | public void setProperties(Properties properties) {
182 | }
183 |
184 | public static class BoundSqlSqlSource implements SqlSource {
185 | private BoundSql boundSql;
186 |
187 | public BoundSqlSqlSource(BoundSql boundSql) {
188 | this.boundSql = boundSql;
189 | }
190 |
191 | @Override
192 | public BoundSql getBoundSql(Object parameterObject) {
193 | return boundSql;
194 | }
195 | }
196 |
197 | }
198 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Stop when "xargs" is not available.
209 | if ! command -v xargs >/dev/null 2>&1
210 | then
211 | die "xargs is not available"
212 | fi
213 |
214 | # Use "xargs" to parse quoted args.
215 | #
216 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
217 | #
218 | # In Bash we could simply go:
219 | #
220 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
221 | # set -- "${ARGS[@]}" "$@"
222 | #
223 | # but POSIX shell has neither arrays nor command substitution, so instead we
224 | # post-process each arg (as a line of input to sed) to backslash-escape any
225 | # character that might be a shell metacharacter, then use eval to reverse
226 | # that process (while maintaining the separation between arguments), and wrap
227 | # the whole thing up as a single "set" statement.
228 | #
229 | # This will of course break if any of these variables contains a newline or
230 | # an unmatched quote.
231 | #
232 |
233 | eval "set -- $(
234 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
235 | xargs -n1 |
236 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
237 | tr '\n' ' '
238 | )" '"$@"'
239 |
240 | exec "$JAVACMD" "$@"
241 |
--------------------------------------------------------------------------------
/mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/Config.java:
--------------------------------------------------------------------------------
1 | package com.plugins.mybaitslog;
2 |
3 | import com.intellij.ide.util.PropertiesComponent;
4 | import com.intellij.openapi.project.Project;
5 |
6 | import java.awt.*;
7 | import java.util.*;
8 | import java.util.List;
9 |
10 | /**
11 | * A Config Class
12 | *
13 | * @author lk
14 | * @version 1.0
15 | * date: 2023/3/30 18:08
16 | */
17 | public class Config {
18 |
19 | private static final String PROJECT_ID = "MyBatisLogPlugin";
20 |
21 | public final static String KEY_NAME = "==> SQLStructure: ";
22 | public final static String KEY_ERROR_NAME = "==> SQLStructureError: ";
23 |
24 | public static final String SQL_START_LINE = "- --> ";
25 | public static final String SQL_MIDDLE_LINE = " > ";
26 | public static final String SQL_END_LINE = "- --< ";
27 |
28 | public static class Idea {
29 |
30 | /**
31 | * 存储的key名称
32 | */
33 | private static final String DB_PARAMETERS_KEY = PROJECT_ID + "SQLStructure";
34 | /**
35 | * 存储的key名称 是否允许运行
36 | */
37 | public static final String DB_STARTUP_KEY = PROJECT_ID + "startup";
38 |
39 |
40 | public static final String FORMAT_SQL_1 = PROJECT_ID + "SQL_FORMAT";
41 |
42 | /**
43 | * 运行提示
44 | */
45 | public static final String NOTIFICATION = PROJECT_ID + "NOTIFICATION";
46 |
47 | /**
48 | * 欢迎信息
49 | */
50 | public static final String WELCOMEMESSAGE = PROJECT_ID + "WELCOMEMESSAGE";
51 |
52 | /**
53 | * 是否折叠
54 | */
55 | public static final String WHETHERFOLD = PROJECT_ID + "WHETHERFOLD";
56 |
57 | public static final String RMISERVER = PROJECT_ID + "RMISERVER";
58 |
59 | public static final String PARAMETERS = "SQLStructure:";
60 |
61 | public static final Map ColorMap = new HashMap() {{
62 | put("select", "42,199,180");
63 | put("update", "158,190,92");
64 | put("delete", "231,29,54");
65 | put("insert", "97,163,172");
66 | put("other", "252,255,253");
67 | }};
68 |
69 | public static final Map PerRunMap = new HashMap() {{
70 | put("org.jetbrains.idea.maven.execution", false);
71 | put("com.intellij.execution.junit", true);
72 | put("com.intellij.spring.boot.run", true);
73 | put("org.jetbrains.plugins.gradle", false);
74 | }};
75 |
76 | public static final ArrayList AddOpens = new ArrayList() {{
77 | add("--add-opens java.base/java.lang=ALL-UNNAMED");
78 | }};
79 |
80 | /**
81 | * 获取关键字常量配置
82 | *
83 | * @return string
84 | */
85 | public static String getParameters() {
86 | return PropertiesComponent.getInstance().getValue(DB_PARAMETERS_KEY, PARAMETERS);
87 | }
88 |
89 |
90 | /**
91 | * 设置配置
92 | *
93 | * @param value 值
94 | * @param defaultValue 默认
95 | */
96 | public static void setParameters(String value, String defaultValue) {
97 | PropertiesComponent.getInstance().setValue(DB_PARAMETERS_KEY, null == value ? defaultValue : value);
98 | }
99 |
100 | /**
101 | * 设置启动过滤
102 | *
103 | * @param value 值
104 | */
105 | public static void setStartup(int value) {
106 | PropertiesComponent.getInstance().setValue(DB_STARTUP_KEY, Integer.toString(value), "1");
107 | }
108 |
109 | /**
110 | * 获取启动过滤
111 | */
112 | public static boolean getStartup() {
113 | final String value = PropertiesComponent.getInstance().getValue(DB_STARTUP_KEY, "1");
114 | return Integer.parseInt(value) == 1;
115 | }
116 |
117 | /**
118 | * 运行通知
119 | *
120 | * @param value 值
121 | */
122 | public static void setRunNotification(int value) {
123 | PropertiesComponent.getInstance().setValue(NOTIFICATION, Integer.toString(value), "1");
124 | }
125 |
126 | /**
127 | * 运行通知
128 | */
129 | public static boolean getRunNotification() {
130 | final String value = PropertiesComponent.getInstance().getValue(NOTIFICATION, "1");
131 | return Integer.parseInt(value) == 1;
132 | }
133 |
134 | /**
135 | * 欢迎信息
136 | *
137 | * @param value 值
138 | */
139 | public static void setWelcomeMessage(int value) {
140 | PropertiesComponent.getInstance().setValue(WELCOMEMESSAGE, Integer.toString(value), "1");
141 | }
142 |
143 | /**
144 | * 欢迎信息
145 | */
146 | public static boolean getWelcomeMessage() {
147 | final String value = PropertiesComponent.getInstance().getValue(WELCOMEMESSAGE, "1");
148 | return Integer.parseInt(value) == 1;
149 | }
150 |
151 | /**
152 | * 是否折叠
153 | *
154 | * @param value 值
155 | */
156 | public static void setWhetherfold(int value) {
157 | PropertiesComponent.getInstance().setValue(WHETHERFOLD, Integer.toString(value), "1");
158 | }
159 |
160 | /**
161 | * 是否折叠
162 | */
163 | public static boolean getWhetherfold() {
164 | final String value = PropertiesComponent.getInstance().getValue(WHETHERFOLD, "1");
165 | return Integer.parseInt(value) == 1;
166 | }
167 |
168 | /**
169 | * 是否RMI输出
170 | *
171 | * @param value 值
172 | */
173 | public static void setRunRmi(int value) {
174 | PropertiesComponent.getInstance().setValue(RMISERVER, Integer.toString(value), "0");
175 | }
176 |
177 | /**
178 | * 是否RMI输出
179 | */
180 | public static boolean getRunRmi() {
181 | final String value = PropertiesComponent.getInstance().getValue(RMISERVER, "0");
182 | return Integer.parseInt(value) == 1;
183 | }
184 |
185 |
186 | /**
187 | * 设置格式化
188 | *
189 | * @param value 值
190 | */
191 | public static void setFormatSql(int value) {
192 | PropertiesComponent.getInstance().setValue(FORMAT_SQL_1, Integer.toString(value), "0");
193 | }
194 |
195 | /**
196 | * 设置格式化
197 | */
198 | public static boolean getFormatSql() {
199 | final String value = PropertiesComponent.getInstance().getValue(FORMAT_SQL_1, "0");
200 | return Integer.parseInt(value) == 1;
201 | }
202 |
203 | /**
204 | * 设置配置
205 | *
206 | * @param type 值
207 | */
208 | public static Color getColor(String type) {
209 | final String s = ColorMap.get(type);
210 | final String value = PropertiesComponent.getInstance().getValue("color:" + type, s);
211 | final String[] split = value.split(",");
212 | return new Color(Integer.parseInt(split[0]), Integer.parseInt(split[1]), Integer.parseInt(split[2]));
213 | }
214 |
215 | /**
216 | * 设置启动过滤
217 | *
218 | * @param value 值
219 | */
220 | public static void setColor(String type, Color value) {
221 | final String color = String.format("%s,%s,%s", value.getRed(), value.getGreen(), value.getBlue());
222 | PropertiesComponent.getInstance().setValue("color:" + type, color);
223 | }
224 |
225 | public static ArrayList getAddOpens() {
226 | final String value = PropertiesComponent.getInstance().getValue("addOpens:", String.join(";", AddOpens));
227 | return new ArrayList(Arrays.asList(value.split(";")));
228 | }
229 |
230 | public static void setAddOpens(String opens) {
231 | final List openlist = Arrays.asList(opens.split("\n"));
232 | PropertiesComponent.getInstance().setValue("addOpens:", String.join(";", openlist));
233 | }
234 |
235 | public static Map getPerRunMap() {
236 | final String value = PropertiesComponent.getInstance().getValue("perRunMap:");
237 | if (null == value) {
238 | return PerRunMap;
239 | }
240 | final String[] split1 = value.split(";");
241 | final List strings = Arrays.asList(split1);
242 | strings.forEach(e -> {
243 | final String[] split2 = e.split("=");
244 | if (!PerRunMap.containsKey(split2[0])) {
245 | PerRunMap.put(split2[0], Boolean.valueOf(split2[1]));
246 | }
247 | });
248 | return PerRunMap;
249 | }
250 |
251 | /**
252 | * 添加执行器
253 | *
254 | * @param name 执行器名称
255 | * @param run 是否可以运行
256 | * @param cover 是否替换 false=不替换 true=强制替换
257 | */
258 | public static void setPerRunMap(String name, boolean run, boolean cover) {
259 | final Boolean aBoolean = PerRunMap.containsKey(name);
260 | if (cover) {
261 | PerRunMap.put(name, run);
262 | }
263 | if (!cover && !aBoolean) {
264 | PluginUtil.Notificat_AddConfiguration();
265 | PerRunMap.put(name, run);
266 | }
267 | ArrayList value = new ArrayList();
268 | for (Map.Entry next : PerRunMap.entrySet()) {
269 | final String format = String.format("%s=%s", next.getKey(), next.getValue());
270 | value.add(format);
271 | }
272 | PropertiesComponent.getInstance().setValue("perRunMap:", String.join(";", value));
273 | }
274 |
275 |
276 | }
277 |
278 | public static String id;
279 | }
280 |
--------------------------------------------------------------------------------
/mybatis-plugin/src/main/java/com/linkkou/mybatis/log/LogInterceptor.java:
--------------------------------------------------------------------------------
1 | package com.linkkou.mybatis.log;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import org.apache.ibatis.cache.CacheKey;
6 | import org.apache.ibatis.executor.Executor;
7 | import org.apache.ibatis.mapping.BoundSql;
8 | import org.apache.ibatis.mapping.MappedStatement;
9 | import org.apache.ibatis.mapping.ParameterMapping;
10 | import org.apache.ibatis.mapping.SqlSource;
11 | import org.apache.ibatis.plugin.*;
12 | import org.apache.ibatis.reflection.MetaObject;
13 | import org.apache.ibatis.scripting.defaults.RawSqlSource;
14 | import org.apache.ibatis.scripting.xmltags.DynamicContext;
15 | import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
16 | import org.apache.ibatis.scripting.xmltags.SqlNode;
17 | import org.apache.ibatis.session.Configuration;
18 | import org.apache.ibatis.session.ResultHandler;
19 | import org.apache.ibatis.session.RowBounds;
20 | import org.apache.ibatis.type.JdbcType;
21 | import org.apache.ibatis.type.TypeHandler;
22 | import org.javatuples.Pair;
23 |
24 | import java.lang.reflect.Field;
25 | import java.util.*;
26 | import java.util.regex.Matcher;
27 |
28 |
29 | /**
30 | * 用于构建完整的SQL,彻底解决通过?替换的问题存在的不正确的情况
31 | *
32 | * @author lk
33 | */
34 | @Intercepts({
35 | @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
36 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
37 | @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
38 | @Signature(type = Executor.class, method = "queryCursor", args = {MappedStatement.class, Object.class, RowBounds.class})
39 | })
40 | public class LogInterceptor implements Interceptor {
41 |
42 | /**
43 | * 对象名称
44 | */
45 | private static final String ROOTSQLNODE = "rootSqlNode";
46 | private static final String ROOTSQLNODE2 = "_rootSqlNode_";
47 | /**
48 | * 参数数量
49 | */
50 | private static final Integer ARGSNUMBER = 2;
51 |
52 | private final String id;
53 |
54 | public static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss")
55 | //当Map的key为复杂对象时,需要开启该方法
56 | .enableComplexMapKeySerialization()
57 | //当字段值为空或null时,依然对该字段进行转换
58 | .serializeNulls()
59 | //防止特殊字符出现乱码
60 | .disableHtmlEscaping().create();
61 |
62 | public LogInterceptor(String id) {
63 | this.id = id;
64 | }
65 |
66 | @Override
67 | public Object intercept(Invocation invocation) throws Throwable {
68 | if (invocation.getArgs().length >= ARGSNUMBER) {
69 | final Pair args = getArgs(invocation);
70 | MappedStatement mappedStatement = args.getValue0();
71 | Object parameter = args.getValue1();
72 | try {
73 | final String originalSql = this.getOriginalSql(mappedStatement, parameter);
74 | if (originalSql != null) {
75 | BoundSql boundSql = mappedStatement.getBoundSql(parameter);
76 | Configuration configuration = mappedStatement.getConfiguration();
77 | // 通过配置信息和BoundSql对象来生成带值得sql语句
78 | final Pair>> completeSql = getCompleteSql(configuration, boundSql, originalSql);
79 | final SqlVO sqlVO = new SqlVO().setId(mappedStatement.getId())
80 | .setCompleteSql(completeSql.getValue0())
81 | .setParameter(gson.toJson(completeSql.getValue1()))
82 | .setOriginalSql(originalSql);
83 | final String json = gson.toJson(sqlVO);
84 | PrintlnLog.log("==> SQLStructure: " + json, this.id);
85 | }
86 | } catch (Exception e) {
87 | e.printStackTrace();
88 | }
89 | }
90 | return invocation.proceed();
91 | }
92 |
93 | private Pair getArgs(Invocation invocation) {
94 | final Object[] args = invocation.getArgs();
95 | return Pair.with((MappedStatement) args[0], args[1]);
96 | }
97 |
98 | /**
99 | * 生成对应的带有值得sql语句
100 | *
101 | * @param configuration 配置
102 | * @param boundSql 对象
103 | * @param originalSql sql
104 | * @return String
105 | */
106 | private Pair>> getCompleteSql(Configuration configuration, BoundSql boundSql, String originalSql) {
107 | Object parameterObject = boundSql.getParameterObject();
108 | List parameterMappings = boundSql.getParameterMappings();
109 | List