├── 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 | # [![Mybatislog](https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/master/image/pluginIcon.svg)](https://github.com/Link-Kou/intellij-mybaitslog) Mybatislog 2 | 3 | ![GitHub release (latest by date)](https://img.shields.io/github/v/release/Link-Kou/intellij-mybaitslog) 4 | ![GitHub](https://img.shields.io/github/license/Link-Kou/intellij-mybaitslog) 5 | ![GitHub issues](https://img.shields.io/github/issues/Link-Kou/intellij-mybaitslog) 6 | 7 | ### Mybatislog能做什么? 8 | 9 | > Mybatislog是基于IntelliJ 开发的插件项目,用来格式化输出Mybatis的Sql。 10 | 11 | ![样列](https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/master/image/2020-03-25_09-28-47.jpg "样列") 12 | 13 | ![样列](https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/master/image/2023-04-28_08-33-52.gif "样列") 14 | 15 | 16 | ### 在线安装(搜索) 17 | 18 | IDEA --> Setting --> Plugins --> 搜索 MyBatis Log EasyPlus 19 | 20 | ![样列](https://raw.githubusercontent.com/Link-Kou/intellij-mybaitslog/master/image/img.png "样列") 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 | 43 | 48 |
44 | 45 | JetBrains 46 | 47 |
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 | image 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 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /mybatis-idea-plugin/src/main/resources/META-INF/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /mybatis-idea-plugin/src/main/resources/icons/pluginIcon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 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> keyvalue = new ArrayList>(); 110 | final int size = parameterMappings.size(); 111 | if (size > 0 && parameterObject != null) { 112 | MetaObject metaObject = configuration.newMetaObject(parameterObject); 113 | for (ParameterMapping parameterMapping : parameterMappings) { 114 | String propertyName = parameterMapping.getProperty(); 115 | final JdbcType jdbcType = parameterMapping.getJdbcType(); 116 | final TypeHandler typeHandler = parameterMapping.getTypeHandler(); 117 | final HashMap stringObjectHashMap = new HashMap<>(); 118 | if (metaObject.hasGetter(propertyName)) { 119 | Object obj = metaObject.getValue(propertyName); 120 | final String parameterValue = getParameterTypeHandler(configuration, typeHandler, obj, jdbcType); 121 | stringObjectHashMap.put(propertyName, parameterValue); 122 | keyvalue.add(stringObjectHashMap); 123 | originalSql = replaceFirst(originalSql, propertyName, parameterValue); 124 | } else if (boundSql.hasAdditionalParameter(propertyName)) { 125 | Object obj = boundSql.getAdditionalParameter(propertyName); 126 | final String parameterValue = getParameterTypeHandler(configuration, typeHandler, obj, jdbcType); 127 | stringObjectHashMap.put(propertyName, parameterValue); 128 | keyvalue.add(stringObjectHashMap); 129 | originalSql = replaceFirst(originalSql, propertyName, parameterValue); 130 | } else if (!(parameterObject instanceof Map)) { 131 | //单个参数默认组合 132 | final String parameterValue = getParameterTypeHandler(configuration, typeHandler, metaObject.getOriginalObject(), jdbcType); 133 | stringObjectHashMap.put(propertyName, parameterValue); 134 | keyvalue.add(stringObjectHashMap); 135 | originalSql = replaceFirst(originalSql, propertyName, parameterValue); 136 | } 137 | } 138 | } 139 | return Pair.with(originalSql.replaceAll("[\\s]+", " "), keyvalue); 140 | } 141 | 142 | /** 143 | * 参数替换 144 | * 145 | * @param originalSql SQL 146 | * @param propertyName 名称 147 | * @param parameterValue 值 148 | * @return String 149 | */ 150 | private String replaceFirst(String originalSql, String propertyName, String parameterValue) { 151 | //(\$|#)\{\s*epNo2((?!\{).)*} 152 | return originalSql.replaceFirst("(\\$|#)\\{\\s*" + Matcher.quoteReplacement(propertyName) + "((?!\\{).)*}", Matcher.quoteReplacement(parameterValue)); 153 | } 154 | 155 | /** 156 | * 获取原始的SQL 157 | * 158 | * @param mappedStatement 对象 159 | * @param parameter 对象 160 | * @return String 161 | */ 162 | private String getOriginalSql(MappedStatement mappedStatement, Object parameter) { 163 | final SqlSource sqlSource = mappedStatement.getSqlSource(); 164 | if (sqlSource instanceof DynamicSqlSource) { 165 | return getDynamicSqlSource(mappedStatement, parameter); 166 | } 167 | if (sqlSource instanceof RawSqlSource) { 168 | return getRawSqlSource(sqlSource); 169 | } 170 | //(\'|\")(.*?)\?(.*?)+(\'|\") 171 | //(?!(\'|\"))\?(?!(\'|\")) 172 | //自定义SQL的拦截 173 | return null; 174 | } 175 | 176 | 177 | private String getDynamicSqlSource(MappedStatement mappedStatement, Object parameter) { 178 | final DynamicContext dynamicContext = new DynamicContext(mappedStatement.getConfiguration(), parameter); 179 | final SqlNode sqlNode = getSqlNode(mappedStatement.getSqlSource()); 180 | if (sqlNode != null && sqlNode.apply(dynamicContext)) { 181 | return dynamicContext.getSql(); 182 | } 183 | return null; 184 | } 185 | 186 | private String getRawSqlSource(SqlSource sqlSource) { 187 | final RawSqlSource dynamicSqlSource = (RawSqlSource) sqlSource; 188 | Field[] declaredFields = dynamicSqlSource.getClass().getDeclaredFields(); 189 | for (Field declaredField : declaredFields) { 190 | if (ROOTSQLNODE2.equals(declaredField.getName())) { 191 | try { 192 | declaredField.setAccessible(true); 193 | return (String) declaredField.get(dynamicSqlSource); 194 | } catch (IllegalAccessException e) { 195 | throw new RuntimeException(e); 196 | } 197 | } 198 | } 199 | return null; 200 | } 201 | 202 | /** 203 | * 构建 SqlNode 204 | * 205 | * @param sqlSource 对象 206 | * @return SqlNode 207 | */ 208 | private SqlNode getSqlNode(SqlSource sqlSource) { 209 | if (sqlSource instanceof DynamicSqlSource) { 210 | final DynamicSqlSource dynamicSqlSource = (DynamicSqlSource) sqlSource; 211 | Field[] declaredFields = dynamicSqlSource.getClass().getDeclaredFields(); 212 | for (Field declaredField : declaredFields) { 213 | if (ROOTSQLNODE.equals(declaredField.getName())) { 214 | try { 215 | declaredField.setAccessible(true); 216 | return (SqlNode) declaredField.get(dynamicSqlSource); 217 | } catch (IllegalAccessException e) { 218 | throw new RuntimeException(e); 219 | } 220 | } 221 | } 222 | } 223 | return null; 224 | } 225 | 226 | /** 227 | * 如果是字符串对象则加上单引号返回,如果是日期则也需要转换成字符串形式,如果是其他则直接转换成字符串返回。 228 | * 229 | * @param configuration 对象 230 | * @param jdbcType 对象 231 | * @return String 232 | */ 233 | private static String getParameterTypeHandler(Configuration configuration, TypeHandler typeHandler, Object value, JdbcType jdbcType) { 234 | try { 235 | TypeHandler _typeHandler = (TypeHandler) typeHandler; 236 | final IPreparedStatement iPreparedStatement = new IPreparedStatement(); 237 | _typeHandler.setParameter(iPreparedStatement, 1, value, jdbcType); 238 | return iPreparedStatement.getValue(); 239 | } catch (Exception e) { 240 | //e.printStackTrace(); 241 | } 242 | return getParameterValue(value); 243 | } 244 | 245 | 246 | /** 247 | * 如果是字符串对象则加上单引号返回,如果是日期则也需要转换成字符串形式,如果是其他则直接转换成字符串返回。 248 | * todo 需要改进为MyBatis内置的数据解析能力 249 | * 250 | * @param obj 对象 251 | * @return String 252 | */ 253 | private static String getParameterValue(Object obj) { 254 | String value = ""; 255 | if (obj instanceof String) { 256 | value = "'" + obj + "'"; 257 | } else { 258 | if (obj != null) { 259 | value = obj.toString(); 260 | } 261 | } 262 | return value; 263 | } 264 | 265 | 266 | @Override 267 | public Object plugin(Object target) { 268 | return Plugin.wrap(target, this); 269 | } 270 | 271 | @Override 272 | public void setProperties(Properties properties) { 273 | } 274 | 275 | } -------------------------------------------------------------------------------- /mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/console/BasicFormatter.java: -------------------------------------------------------------------------------- 1 | package com.plugins.mybaitslog.console; 2 | 3 | 4 | /* 5 | * Original class is here: 6 | * https://github.com/hibernate/hibernate-orm/blob/a30635f14ae272fd63a653f9a9e1a9aeb390fad4/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/BasicFormatterImpl.java 7 | * 8 | * it imported org.hibernate.internal.util.StringHelper, but it doesn't really need that. 9 | */ 10 | 11 | import java.util.HashSet; 12 | import java.util.LinkedList; 13 | import java.util.Locale; 14 | import java.util.Set; 15 | import java.util.StringTokenizer; 16 | 17 | /** 18 | * Performs formatting of basic SQL statements (DML + query). 19 | * 20 | * @author Gavin King 21 | * @author Steve Ebersole 22 | */ 23 | public class BasicFormatter { 24 | 25 | // MOD: from org.hibernate.internal.util.StringHelper 26 | private static final String WHITESPACE = " \n\r\f\t"; 27 | 28 | private static final Set BEGIN_CLAUSES = new HashSet(); 29 | private static final Set END_CLAUSES = new HashSet(); 30 | private static final Set LOGICAL = new HashSet(); 31 | private static final Set QUANTIFIERS = new HashSet(); 32 | private static final Set DML = new HashSet(); 33 | private static final Set MISC = new HashSet(); 34 | 35 | static { 36 | BEGIN_CLAUSES.add("left"); 37 | BEGIN_CLAUSES.add("right"); 38 | BEGIN_CLAUSES.add("inner"); 39 | BEGIN_CLAUSES.add("outer"); 40 | BEGIN_CLAUSES.add("group"); 41 | BEGIN_CLAUSES.add("order"); 42 | 43 | END_CLAUSES.add("where"); 44 | END_CLAUSES.add("set"); 45 | END_CLAUSES.add("having"); 46 | END_CLAUSES.add("join"); 47 | END_CLAUSES.add("from"); 48 | END_CLAUSES.add("by"); 49 | END_CLAUSES.add("into"); 50 | END_CLAUSES.add("union"); 51 | 52 | LOGICAL.add("and"); 53 | LOGICAL.add("or"); 54 | LOGICAL.add("when"); 55 | LOGICAL.add("else"); 56 | LOGICAL.add("end"); 57 | 58 | QUANTIFIERS.add("in"); 59 | QUANTIFIERS.add("all"); 60 | QUANTIFIERS.add("exists"); 61 | QUANTIFIERS.add("some"); 62 | QUANTIFIERS.add("any"); 63 | 64 | DML.add("insert"); 65 | DML.add("update"); 66 | DML.add("delete"); 67 | 68 | MISC.add("select"); 69 | MISC.add("on"); 70 | } 71 | 72 | private static final String INDENT_STRING = " "; 73 | // MOD: Make initial indent zero 74 | /*System.lineSeparator() + INDENT_STRING*/ 75 | private static final String INITIAL = ""; 76 | 77 | public String format(String source) { 78 | return new FormatProcess(source).perform(); 79 | } 80 | 81 | private static class FormatProcess { 82 | boolean beginLine = true; 83 | boolean afterBeginBeforeEnd; 84 | boolean afterByOrSetOrFromOrSelect; 85 | boolean afterValues; 86 | boolean afterOn; 87 | boolean afterBetween; 88 | boolean afterInsert; 89 | int inFunction; 90 | int parensSinceSelect; 91 | private LinkedList parenCounts = new LinkedList(); 92 | private LinkedList afterByOrFromOrSelects = new LinkedList(); 93 | 94 | // MOD: Make BOL indent zero 95 | int indent = /*1*/0; 96 | 97 | StringBuilder result = new StringBuilder(); 98 | StringTokenizer tokens; 99 | String lastToken; 100 | String token; 101 | String lcToken; 102 | 103 | public FormatProcess(String sql) { 104 | tokens = new StringTokenizer( 105 | sql, 106 | "()+*/-=<>'`\"[]," + /*StringHelper.*/WHITESPACE, 107 | true 108 | ); 109 | } 110 | 111 | public String perform() { 112 | 113 | result.append(INITIAL); 114 | 115 | while (tokens.hasMoreTokens()) { 116 | token = tokens.nextToken(); 117 | lcToken = token.toLowerCase(Locale.ROOT); 118 | 119 | if ("'".equals(token)) { 120 | String t; 121 | do { 122 | t = tokens.nextToken(); 123 | token += t; 124 | } 125 | // cannot handle single quotes 126 | while (!"'".equals(t) && tokens.hasMoreTokens()); 127 | } else if ("\"".equals(token)) { 128 | String t; 129 | do { 130 | t = tokens.nextToken(); 131 | token += t; 132 | } 133 | while (!"\"".equals(t) && tokens.hasMoreTokens()); 134 | } 135 | // SQL Server uses "[" and "]" to escape reserved words 136 | // see SQLServerDialect.openQuote and SQLServerDialect.closeQuote 137 | else if ("[".equals(token)) { 138 | String t; 139 | do { 140 | t = tokens.nextToken(); 141 | token += t; 142 | } 143 | while (!"]".equals(t) && tokens.hasMoreTokens()); 144 | } 145 | 146 | if (afterByOrSetOrFromOrSelect && ",".equals(token)) { 147 | commaAfterByOrFromOrSelect(); 148 | } else if (afterOn && ",".equals(token)) { 149 | commaAfterOn(); 150 | } else if ("(".equals(token)) { 151 | openParen(); 152 | } else if (")".equals(token)) { 153 | closeParen(); 154 | } else if (BEGIN_CLAUSES.contains(lcToken)) { 155 | beginNewClause(); 156 | } else if (END_CLAUSES.contains(lcToken)) { 157 | endNewClause(); 158 | } else if ("select".equals(lcToken)) { 159 | select(); 160 | } else if (DML.contains(lcToken)) { 161 | updateOrInsertOrDelete(); 162 | } else if ("values".equals(lcToken)) { 163 | values(); 164 | } else if ("on".equals(lcToken)) { 165 | on(); 166 | } else if (afterBetween && lcToken.equals("and")) { 167 | misc(); 168 | afterBetween = false; 169 | } else if (LOGICAL.contains(lcToken)) { 170 | logical(); 171 | } else if (isWhitespace(token)) { 172 | white(); 173 | } else { 174 | misc(); 175 | } 176 | 177 | if (!isWhitespace(token)) { 178 | lastToken = lcToken; 179 | } 180 | 181 | } 182 | return result.toString(); 183 | } 184 | 185 | private void commaAfterOn() { 186 | out(); 187 | indent--; 188 | newline(); 189 | afterOn = false; 190 | afterByOrSetOrFromOrSelect = true; 191 | } 192 | 193 | private void commaAfterByOrFromOrSelect() { 194 | out(); 195 | newline(); 196 | } 197 | 198 | private void logical() { 199 | if ("end".equals(lcToken)) { 200 | indent--; 201 | } 202 | newline(); 203 | out(); 204 | beginLine = false; 205 | } 206 | 207 | private void on() { 208 | indent++; 209 | afterOn = true; 210 | newline(); 211 | out(); 212 | beginLine = false; 213 | } 214 | 215 | private void misc() { 216 | out(); 217 | if ("between".equals(lcToken)) { 218 | afterBetween = true; 219 | } 220 | if (afterInsert) { 221 | newline(); 222 | afterInsert = false; 223 | } else { 224 | beginLine = false; 225 | if ("case".equals(lcToken)) { 226 | indent++; 227 | } 228 | } 229 | } 230 | 231 | private void white() { 232 | if (!beginLine) { 233 | result.append(" "); 234 | } 235 | } 236 | 237 | private void updateOrInsertOrDelete() { 238 | out(); 239 | indent++; 240 | beginLine = false; 241 | if ("update".equals(lcToken)) { 242 | newline(); 243 | } 244 | if ("insert".equals(lcToken)) { 245 | afterInsert = true; 246 | } 247 | } 248 | 249 | private void select() { 250 | out(); 251 | indent++; 252 | newline(); 253 | parenCounts.addLast(parensSinceSelect); 254 | afterByOrFromOrSelects.addLast(afterByOrSetOrFromOrSelect); 255 | parensSinceSelect = 0; 256 | afterByOrSetOrFromOrSelect = true; 257 | } 258 | 259 | private void out() { 260 | result.append(token); 261 | } 262 | 263 | private void endNewClause() { 264 | if (!afterBeginBeforeEnd) { 265 | indent--; 266 | if (afterOn) { 267 | indent--; 268 | afterOn = false; 269 | } 270 | newline(); 271 | } 272 | out(); 273 | if (!"union".equals(lcToken)) { 274 | indent++; 275 | } 276 | newline(); 277 | afterBeginBeforeEnd = false; 278 | afterByOrSetOrFromOrSelect = "by".equals(lcToken) 279 | || "set".equals(lcToken) 280 | || "from".equals(lcToken); 281 | } 282 | 283 | private void beginNewClause() { 284 | if (!afterBeginBeforeEnd) { 285 | if (afterOn) { 286 | indent--; 287 | afterOn = false; 288 | } 289 | indent--; 290 | newline(); 291 | } 292 | out(); 293 | beginLine = false; 294 | afterBeginBeforeEnd = true; 295 | } 296 | 297 | private void values() { 298 | indent--; 299 | newline(); 300 | out(); 301 | indent++; 302 | newline(); 303 | afterValues = true; 304 | } 305 | 306 | private void closeParen() { 307 | parensSinceSelect--; 308 | if (parensSinceSelect < 0) { 309 | indent--; 310 | parensSinceSelect = parenCounts.removeLast(); 311 | afterByOrSetOrFromOrSelect = afterByOrFromOrSelects.removeLast(); 312 | } 313 | if (inFunction > 0) { 314 | inFunction--; 315 | out(); 316 | } else { 317 | if (!afterByOrSetOrFromOrSelect) { 318 | indent--; 319 | newline(); 320 | } 321 | out(); 322 | } 323 | beginLine = false; 324 | } 325 | 326 | private void openParen() { 327 | if (isFunctionName(lastToken) || inFunction > 0) { 328 | inFunction++; 329 | } 330 | beginLine = false; 331 | if (inFunction > 0) { 332 | out(); 333 | } else { 334 | out(); 335 | if (!afterByOrSetOrFromOrSelect) { 336 | indent++; 337 | newline(); 338 | beginLine = true; 339 | } 340 | } 341 | parensSinceSelect++; 342 | } 343 | 344 | private static boolean isFunctionName(String tok) { 345 | if (tok == null || tok.length() == 0) { 346 | return false; 347 | } 348 | 349 | final char begin = tok.charAt(0); 350 | final boolean isIdentifier = Character.isJavaIdentifierStart(begin) || '"' == begin; 351 | return isIdentifier && 352 | !LOGICAL.contains(tok) && 353 | !END_CLAUSES.contains(tok) && 354 | !QUANTIFIERS.contains(tok) && 355 | !DML.contains(tok) && 356 | !MISC.contains(tok); 357 | } 358 | 359 | private static boolean isWhitespace(String token) { 360 | return /*StringHelper.*/WHITESPACE.contains(token); 361 | } 362 | 363 | private void newline() { 364 | result.append(System.lineSeparator()); 365 | for (int i = 0; i < indent; i++) { 366 | result.append(INDENT_STRING); 367 | } 368 | beginLine = true; 369 | } 370 | } 371 | } -------------------------------------------------------------------------------- /mybatis-plugin/src/main/java/com/linkkou/mybatis/log/IPreparedStatement.java: -------------------------------------------------------------------------------- 1 | package com.linkkou.mybatis.log; 2 | 3 | import java.io.InputStream; 4 | import java.io.Reader; 5 | import java.math.BigDecimal; 6 | import java.net.URL; 7 | import java.sql.*; 8 | import java.time.LocalDate; 9 | import java.time.LocalDateTime; 10 | import java.time.LocalTime; 11 | import java.time.format.DateTimeFormatter; 12 | import java.util.Calendar; 13 | 14 | /** 15 | * A IPreparedStatement Class 16 | * 17 | * @author lk 18 | * @version 1.0 19 | *

    date: 2023/4/19 16:21

    20 | */ 21 | public class IPreparedStatement implements PreparedStatement { 22 | 23 | private String value; 24 | 25 | 26 | @Override 27 | public void setNull(int parameterIndex, int sqlType) throws SQLException { 28 | value = "Null"; 29 | } 30 | 31 | @Override 32 | public void setBoolean(int parameterIndex, boolean x) throws SQLException { 33 | value = Boolean.toString(x); 34 | } 35 | 36 | @Override 37 | public void setByte(int parameterIndex, byte x) throws SQLException { 38 | value = Byte.toString(x); 39 | } 40 | 41 | @Override 42 | public void setShort(int parameterIndex, short x) throws SQLException { 43 | value = Short.toString(x); 44 | } 45 | 46 | @Override 47 | public void setInt(int parameterIndex, int x) throws SQLException { 48 | value = Integer.toString(x); 49 | } 50 | 51 | @Override 52 | public void setLong(int parameterIndex, long x) throws SQLException { 53 | value = Long.toString(x); 54 | } 55 | 56 | @Override 57 | public void setFloat(int parameterIndex, float x) throws SQLException { 58 | value = Float.toString(x); 59 | } 60 | 61 | @Override 62 | public void setDouble(int parameterIndex, double x) throws SQLException { 63 | value = Double.toString(x); 64 | } 65 | 66 | @Override 67 | public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { 68 | value = x.toString(); 69 | } 70 | 71 | @Override 72 | public void setString(int parameterIndex, String x) throws SQLException { 73 | value = String.format("'%s'", x); 74 | } 75 | 76 | @Override 77 | public void setBytes(int parameterIndex, byte[] x) throws SQLException { 78 | value = "……"; 79 | } 80 | 81 | @Override 82 | public void setDate(int parameterIndex, Date x) throws SQLException { 83 | DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 84 | final LocalDate localDate = x.toLocalDate(); 85 | value = String.format("'%s'", fmt.format(localDate)); 86 | } 87 | 88 | @Override 89 | public void setTime(int parameterIndex, Time x) throws SQLException { 90 | DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss"); 91 | final LocalTime localTime = x.toLocalTime(); 92 | value = String.format("'%s'", fmt.format(localTime)); 93 | } 94 | 95 | @Override 96 | public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { 97 | DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 98 | final LocalDateTime localDateTime = x.toLocalDateTime(); 99 | value = String.format("'%s'", fmt.format(localDateTime)); 100 | } 101 | 102 | @Override 103 | public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { 104 | value = "……"; 105 | } 106 | 107 | @Override 108 | public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { 109 | value = "……"; 110 | } 111 | 112 | @Override 113 | public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { 114 | value = "……"; 115 | } 116 | 117 | @Override 118 | public void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException { 119 | value = x.toString(); 120 | } 121 | 122 | @Override 123 | public void setObject(int parameterIndex, Object x) throws SQLException { 124 | value = x.toString(); 125 | } 126 | 127 | @Override 128 | public void setCharacterStream(int parameterIndex, Reader reader, int length) throws SQLException { 129 | value = "……"; 130 | } 131 | 132 | @Override 133 | public void setRef(int parameterIndex, Ref x) throws SQLException { 134 | value = "……"; 135 | } 136 | 137 | @Override 138 | public void setBlob(int parameterIndex, Blob x) throws SQLException { 139 | value = "……"; 140 | } 141 | 142 | @Override 143 | public void setClob(int parameterIndex, Clob x) throws SQLException { 144 | value = "……"; 145 | } 146 | 147 | @Override 148 | public void setArray(int parameterIndex, Array x) throws SQLException { 149 | value = "……"; 150 | } 151 | 152 | @Override 153 | public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { 154 | DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd"); 155 | final LocalDate localDate = x.toLocalDate(); 156 | value = String.format("'%s'", fmt.format(localDate)); 157 | } 158 | 159 | @Override 160 | public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { 161 | DateTimeFormatter fmt = DateTimeFormatter.ofPattern("HH:mm:ss"); 162 | final LocalTime localTime = x.toLocalTime(); 163 | value = String.format("'%s'", fmt.format(localTime)); 164 | } 165 | 166 | @Override 167 | public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { 168 | DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); 169 | final LocalDateTime localDateTime = x.toLocalDateTime(); 170 | value = String.format("'%s'", fmt.format(localDateTime)); 171 | } 172 | 173 | @Override 174 | public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { 175 | value = "null"; 176 | } 177 | 178 | @Override 179 | public void setURL(int parameterIndex, URL x) throws SQLException { 180 | value = x.toString(); 181 | } 182 | 183 | @Override 184 | public void setRowId(int parameterIndex, RowId x) throws SQLException { 185 | value = x.toString(); 186 | } 187 | 188 | @Override 189 | public void setNString(int parameterIndex, String str) throws SQLException { 190 | value = String.format("'%s'", str); 191 | } 192 | 193 | @Override 194 | public void setNCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { 195 | value = "……"; 196 | } 197 | 198 | @Override 199 | public void setNClob(int parameterIndex, NClob nClob) throws SQLException { 200 | value = "……"; 201 | } 202 | 203 | @Override 204 | public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { 205 | value = "……"; 206 | } 207 | 208 | @Override 209 | public void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { 210 | value = "……"; 211 | } 212 | 213 | @Override 214 | public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { 215 | value = "……"; 216 | } 217 | 218 | @Override 219 | public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { 220 | value = xmlObject.toString(); 221 | } 222 | 223 | @Override 224 | public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLException { 225 | value = x.toString(); 226 | } 227 | 228 | @Override 229 | public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { 230 | value = "……"; 231 | } 232 | 233 | @Override 234 | public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { 235 | value = "……"; 236 | } 237 | 238 | @Override 239 | public void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { 240 | value = "……"; 241 | } 242 | 243 | @Override 244 | public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { 245 | value = "……"; 246 | } 247 | 248 | @Override 249 | public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { 250 | value = "……"; 251 | } 252 | 253 | @Override 254 | public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { 255 | value = "……"; 256 | } 257 | 258 | @Override 259 | public void setNCharacterStream(int parameterIndex, Reader reader) throws SQLException { 260 | value = "……"; 261 | } 262 | 263 | @Override 264 | public void setClob(int parameterIndex, Reader reader) throws SQLException { 265 | value = "……"; 266 | } 267 | 268 | @Override 269 | public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { 270 | value = "……"; 271 | } 272 | 273 | @Override 274 | public void setNClob(int parameterIndex, Reader reader) throws SQLException { 275 | value = "……"; 276 | } 277 | 278 | //region 其他 279 | 280 | @Override 281 | public ParameterMetaData getParameterMetaData() throws SQLException { 282 | return null; 283 | } 284 | 285 | @Override 286 | public ResultSet executeQuery() throws SQLException { 287 | return null; 288 | } 289 | 290 | @Override 291 | public int executeUpdate() throws SQLException { 292 | return 0; 293 | } 294 | 295 | @Override 296 | public void clearParameters() throws SQLException { 297 | 298 | } 299 | 300 | @Override 301 | public boolean execute() throws SQLException { 302 | return false; 303 | } 304 | 305 | @Override 306 | public void addBatch() throws SQLException { 307 | 308 | } 309 | 310 | @Override 311 | public ResultSetMetaData getMetaData() throws SQLException { 312 | return null; 313 | } 314 | 315 | @Override 316 | public ResultSet executeQuery(String sql) throws SQLException { 317 | return null; 318 | } 319 | 320 | @Override 321 | public int executeUpdate(String sql) throws SQLException { 322 | return 0; 323 | } 324 | 325 | @Override 326 | public void close() throws SQLException { 327 | 328 | } 329 | 330 | @Override 331 | public int getMaxFieldSize() throws SQLException { 332 | return 0; 333 | } 334 | 335 | @Override 336 | public void setMaxFieldSize(int max) throws SQLException { 337 | 338 | } 339 | 340 | @Override 341 | public int getMaxRows() throws SQLException { 342 | return 0; 343 | } 344 | 345 | @Override 346 | public void setMaxRows(int max) throws SQLException { 347 | 348 | } 349 | 350 | @Override 351 | public void setEscapeProcessing(boolean enable) throws SQLException { 352 | 353 | } 354 | 355 | @Override 356 | public int getQueryTimeout() throws SQLException { 357 | return 0; 358 | } 359 | 360 | @Override 361 | public void setQueryTimeout(int seconds) throws SQLException { 362 | 363 | } 364 | 365 | @Override 366 | public void cancel() throws SQLException { 367 | 368 | } 369 | 370 | @Override 371 | public SQLWarning getWarnings() throws SQLException { 372 | return null; 373 | } 374 | 375 | @Override 376 | public void clearWarnings() throws SQLException { 377 | 378 | } 379 | 380 | @Override 381 | public void setCursorName(String name) throws SQLException { 382 | 383 | } 384 | 385 | @Override 386 | public boolean execute(String sql) throws SQLException { 387 | return false; 388 | } 389 | 390 | @Override 391 | public ResultSet getResultSet() throws SQLException { 392 | return null; 393 | } 394 | 395 | @Override 396 | public int getUpdateCount() throws SQLException { 397 | return 0; 398 | } 399 | 400 | @Override 401 | public boolean getMoreResults() throws SQLException { 402 | return false; 403 | } 404 | 405 | @Override 406 | public void setFetchDirection(int direction) throws SQLException { 407 | 408 | } 409 | 410 | @Override 411 | public int getFetchDirection() throws SQLException { 412 | return 0; 413 | } 414 | 415 | @Override 416 | public void setFetchSize(int rows) throws SQLException { 417 | 418 | } 419 | 420 | @Override 421 | public int getFetchSize() throws SQLException { 422 | return 0; 423 | } 424 | 425 | @Override 426 | public int getResultSetConcurrency() throws SQLException { 427 | return 0; 428 | } 429 | 430 | @Override 431 | public int getResultSetType() throws SQLException { 432 | return 0; 433 | } 434 | 435 | @Override 436 | public void addBatch(String sql) throws SQLException { 437 | 438 | } 439 | 440 | @Override 441 | public void clearBatch() throws SQLException { 442 | 443 | } 444 | 445 | @Override 446 | public int[] executeBatch() throws SQLException { 447 | return new int[0]; 448 | } 449 | 450 | @Override 451 | public Connection getConnection() throws SQLException { 452 | return null; 453 | } 454 | 455 | @Override 456 | public boolean getMoreResults(int current) throws SQLException { 457 | return false; 458 | } 459 | 460 | @Override 461 | public ResultSet getGeneratedKeys() throws SQLException { 462 | return null; 463 | } 464 | 465 | @Override 466 | public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { 467 | return 0; 468 | } 469 | 470 | @Override 471 | public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { 472 | return 0; 473 | } 474 | 475 | @Override 476 | public int executeUpdate(String sql, String[] columnNames) throws SQLException { 477 | return 0; 478 | } 479 | 480 | @Override 481 | public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { 482 | return false; 483 | } 484 | 485 | @Override 486 | public boolean execute(String sql, int[] columnIndexes) throws SQLException { 487 | return false; 488 | } 489 | 490 | @Override 491 | public boolean execute(String sql, String[] columnNames) throws SQLException { 492 | return false; 493 | } 494 | 495 | @Override 496 | public int getResultSetHoldability() throws SQLException { 497 | return 0; 498 | } 499 | 500 | @Override 501 | public boolean isClosed() throws SQLException { 502 | return false; 503 | } 504 | 505 | @Override 506 | public void setPoolable(boolean poolable) throws SQLException { 507 | 508 | } 509 | 510 | @Override 511 | public boolean isPoolable() throws SQLException { 512 | return false; 513 | } 514 | 515 | @Override 516 | public void closeOnCompletion() throws SQLException { 517 | 518 | } 519 | 520 | @Override 521 | public boolean isCloseOnCompletion() throws SQLException { 522 | return false; 523 | } 524 | 525 | @Override 526 | public T unwrap(Class iface) throws SQLException { 527 | return null; 528 | } 529 | 530 | @Override 531 | public boolean isWrapperFor(Class iface) throws SQLException { 532 | return false; 533 | } 534 | //endregion 535 | 536 | public String getValue() { 537 | return value; 538 | } 539 | } 540 | -------------------------------------------------------------------------------- /mybatis-idea-plugin/src/main/java/com/plugins/mybaitslog/gui/FilterSetting.form: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 |
    371 | --------------------------------------------------------------------------------