mark

public class IconUtils {
    private static ImageIcon methodIcon = new ImageIcon(IconUtils.class.getClassLoader().getResource("icon/mybatis.png"));

    private static ImageIcon xmlIcon = new ImageIcon(IconUtils.class.getClassLoader().getResource("icon/mybatis-ns.png"));

    public static Icon useMyBatisIcon() {
        return methodIcon;
    }

    public static Icon useXmlIcon() {
        return xmlIcon;
    }
}

  

package com.ccnode.codegenerator.view;

import com.ccnode.codegenerator.util.IconUtils;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.NotNull;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by bruce.ge on 2016/12/8.
 */
public class MybatisXmlLineMarkerProvider extends RelatedItemLineMarkerProvider {

    private static Set<String> tagNameSet = new HashSet<String>() {{
        add("select");
        add("insert");
        add("update");
        add("delete");
    }};

    @Override
    protected void collectNavigationMarkers(@NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
        if (!(element instanceof XmlTag))
            return;
        PsiFile psiFile = element.getContainingFile();
        if (!(psiFile instanceof XmlFile))
            return;
        XmlFile xmlFile = (XmlFile) psiFile;
        if (!xmlFile.getRootTag().getName().equals("mapper")) {
            return;
        }
        XmlTag tag = (XmlTag) element;
        if (!tagNameSet.contains(tag.getName())) {
            return;
        }
        XmlAttribute namespaceAttribute = xmlFile.getRootTag().getAttribute("namespace");
        if (namespaceAttribute == null || namespaceAttribute.getValue() == null) {
            return;
        }
        String namespace = namespaceAttribute.getValue();
        XmlAttribute id = tag.getAttribute("id");
        if (id == null || id.getValue() == null) {
            return;
        }
        String[] split = namespace.split("\.");
        String className = split[split.length - 1];
        Module moduleForPsiElement = ModuleUtilCore.findModuleForPsiElement(element);
        if (moduleForPsiElement == null) {
            return;
        }
        PsiClass[] classesByName = PsiShortNamesCache.getInstance(element.getProject()).getClassesByName(className, GlobalSearchScope.moduleScope(moduleForPsiElement));
        PsiClass realClass = null;
        for (PsiClass psiClass : classesByName) {
            if (psiClass.isInterface() && psiClass.getQualifiedName().equals(namespace)) {
                //
                realClass = psiClass;
                break;
            }
        }
        if (realClass == null) {
            return;
        }
        String xmlMethodName = id.getValue();
        PsiElement findedMethod = null;
        PsiMethod[] allMethods = realClass.getAllMethods();
        for (PsiMethod classMethod : allMethods) {
            if (xmlMethodName.equals(classMethod.getName())) {
                findedMethod = classMethod;
                break;
            }
        }
        if (findedMethod == null) {
            return;
        }
        result.add(NavigationGutterIconBuilder.create(IconUtils.useXmlIcon()).setAlignment(GutterIconRenderer.Alignment.CENTER)
                .setTarget(findedMethod).setTooltipTitle("navigation to mapper class").createLineMarkerInfo(element));


        //means we find the class. then get it all method and get it.
    }
}

  

package com.ccnode.codegenerator.view;

import com.ccnode.codegenerator.util.IconUtils;
import com.ccnode.codegenerator.util.MyPsiXmlUtils;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerInfo;
import com.intellij.codeInsight.daemon.RelatedItemLineMarkerProvider;
import com.intellij.codeInsight.navigation.NavigationGutterIconBuilder;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiNonJavaFileReferenceProcessor;
import com.intellij.psi.search.PsiSearchHelper;
import com.intellij.psi.search.PsiShortNamesCache;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * Created by bruce.ge on 2016/12/8.
 */
public class MybatisJavaLineMarkerProvider extends RelatedItemLineMarkerProvider {
    @Override
    protected void collectNavigationMarkers(@NotNull PsiElement element, Collection<? super RelatedItemLineMarkerInfo> result) {
        if (element instanceof PsiMethod) {
            PsiMethod method = (PsiMethod) element;
            PsiClass containingClass = method.getContainingClass();
            if (!containingClass.isInterface()) {
                return;
            }
            // if it's interface, then find it in the xml file to check if it contain the name.
            //shall be mapper then go to find to corresponding xml file.
            Project project = element.getProject();
            String qualifiedName = containingClass.getQualifiedName();
            PsiElement methodElement = null;
            PsiFile[] filesByName = PsiShortNamesCache.getInstance(project).getFilesByName(containingClass.getName() + ".xml");
            //first search with samename xml.
            if (filesByName.length == 0) {
                methodElement = handleWithFileNotFound(method, project, qualifiedName, result);
            } else {
                for (PsiFile file : filesByName) {
                    if (file instanceof XmlFile) {
                        XmlFile xmlFile = (XmlFile) file;
                        XmlAttribute namespace = xmlFile.getRootTag().getAttribute("namespace");
                        if (namespace == null || !namespace.getValue().equals(qualifiedName)) {
                            continue;
                        }
                        //say we find the xml file.
                        PsiElement psiElement = MyPsiXmlUtils.findTagForMethodName(xmlFile, method.getName());
                        if (psiElement != null) {
                            methodElement = psiElement;
                            break;
                        }
                    }
                }
                if (methodElement == null) {
                    methodElement = handleWithFileNotFound(method, project, qualifiedName, result);
                }
            }
            if (methodElement != null) {
                result.add(NavigationGutterIconBuilder.create(IconUtils.useMyBatisIcon()).setAlignment(GutterIconRenderer.Alignment.CENTER)
                        .setTarget(methodElement).setTooltipTitle("navigation to mapper xml").createLineMarkerInfo(method.getNameIdentifier()));
            }

            //只进行method的判断 进行控制 其他的不管
        }
    }

    private PsiElement handleWithFileNotFound(@NotNull PsiMethod method, Project project, final String qualifiedName, Collection<? super RelatedItemLineMarkerInfo> result) {
        PsiSearchHelper searchService = ServiceManager.getService(project, PsiSearchHelper.class);
        List<XmlFile> xmlFiles = new ArrayList<XmlFile>();
        Module moduleForPsiElement = ModuleUtilCore.findModuleForPsiElement(method);
        if (moduleForPsiElement == null) {
            return null;
        }
        searchService.processUsagesInNonJavaFiles("mapper", new PsiNonJavaFileReferenceProcessor() {
            @Override
            public boolean process(PsiFile file, int startOffset, int endOffset) {
                if (file instanceof XmlFile) {
                    XmlFile xmlFile = (XmlFile) file;
                    if (xmlFile.getRootTag() != null) {
                        XmlAttribute namespace = xmlFile.getRootTag().getAttribute("namespace");
                        if (namespace != null && namespace.getValue().equals(qualifiedName)) {
                            xmlFiles.add(xmlFile);
                            return false;
                        }
                    }
                }
                return true;
            }
        }, GlobalSearchScope.moduleScope(moduleForPsiElement));
        if (xmlFiles.size() == 0) {
            return null;
        }
        return MyPsiXmlUtils.findTagForMethodName(xmlFiles.get(0), method.getName());
    }

}

  

<idea-plugin version="2">
    <id>com.ccnode.codegenerator.MyBatisCodeHelper</id>
    <name>MyBatisCodeHelper</name>
    <version>1.5.0-SNAPSHOT</version>
    <vendor email="gejun123456@gmail.com">MyBatisCodeHelper</vendor>

    <description><![CDATA[
      <div>
      <p><a href="https://github.com/gejun123456/MyBatisCodeHelper">GitHub</a>
      |&nbsp<a href="https://github.com/gejun123456/MyBatisCodeHelper/issues">Issues</a></p>
      <p>特性</p>
      <ul>
      <li>支持mysql和oracle</li>
      <li><p>根据java对象生成mybatis crud代码和建表sql</p></li>
      <li><p><b>根据mybatis接口中的方法名生成mybatis的sql
            支持find,update,delete,count方法 只需定义一个方法名就可以得到完整mybatis xml代码 可生成大部分单表操作sql 极大提升效率</b></p></li>
      <li><p>mybatis接口文件的mapper xml之间的相互跳转</p></li>
      <li><p>数据库对象更新后一键更新对应的Sql和mybatis xml文件</p></li>
      <li><p>默认提供insert,insertSelective,insertList,update。因为delete可以由方法名生成 默认不提供</p></li>
      <li><p>提供mybatis接口方法名的重构</p></li>
      <li>refid, resultMap跳转到到定义,支持重命名</li>
      <li>refid,resultMap,keyProperty,property的自动补全</li>
      <li><p>mybatis mapper xml文件sql的自动补全</p></li>
      </ul>
      <p>使用方法</p>
      <ul>
      <li><p>在数据库对象上使用alt+insert (generate mybatis files)来生成crud代码和建表sql(mac上使用ctrl+N)</p></li>
      <li><p>数据库对象添加字段后使用alt+insert (generate mybatis files) 来生成更新sql,mapper xml中的字段</p></li>
      <li><p>在mybatis接口的方法名上使用alt+enter来生成对应的mapper sql</p></li>
      <li><p>详细配置: <a href="https://github.com/gejun123456/MyBatisCodeHelper">https://github.com/gejun123456/MyBatisCodeHelper</a></p></li>
      <li>qq群:542735959</li>
      </ul>

      <p>Features</p>
      <ul>
      <li>Generate mybatis crud and create table sql according to domain class</li>
      <li><p><b>Generate mybatis sql based on mybatis interface method name, with this, you don't have to write most sql for
      non join query</b>,support with method name start with find,update,delete,count</p></li>
      <li><p>Jump from mybatis dao interface to mapper xml each other</p></li>
      <li><p>generate files provide insert, insertSelective,insertList,update. others can be generated by methodName</p></li>
      <li><p>refactor for mybatis interface method name</p></li>
      <li><p>jump from refid resultMap to their definition, refactor their name as well</li>
      <li><p>mybatis mapper sql auto completion</p></li>
      <li>refid,resultMap,keyProperty,property auto complete</li>
      <li><p>Support java + MySQL and Oracle and later will support more DB.</p></li>
      <li><a href="https://github.com/gejun123456/MyBatisCodeHelper">https://github.com/gejun123456/MyBatisCodeHelper</a> to learn more.</li>
      </ul>
      <p>How to use</p>
      <ul>
      <li>alt+insert (generate mybatis files) on domain class to generate mybatis files (ctrl+N on mac)</li>
      <li>alt+insert (generate mybatis files) on domain class to update mybatis files when domain class add field (ctrl+N on mac)</li>
      <li>alt+enter on dao interface method to generate mybatis mapper sql</li>
      <li>view more on <a href="https://github.com/gejun123456/MyBatisCodeHelper">https://github.com/gejun123456/MyBatisCodeHelper</a></li>
      </ul>


      </div>
    ]]></description>

    <change-notes><![CDATA[

    <p><h4>1.4.5</h4>
            <ul>
                <li>support with enum type</li>
            </ul>
     </p>
    <p><h4>1.4.4</h4>
            <ul>
                <li>fix exception when start up</li>
            </ul>
     </p>
    <p><h4>1.4.3</h4>
            <ul>
                <li> support multiple method xml generate</li>
                <li> support for mybatis plus</li>
                <li> support domain class with protected field and static field</li>
                <li> support for small resolution</li>
                <li>bugfix - fix can't generate to path</li>
            </ul>
     </p>
    <p><h4>1.4.2</h4>
            <ul>
                <li>bugfix - fix Could not initialize class com.ccnode.codegenerator.freemarker.TemplateUtil</li>
            </ul>
     </p>
    <p><h4>1.4.1</h4>
            <ul>
                <li>bugfix - oralce insertList</li>
                <li>bugfix - import issue</li>
            </ul>
     </p>
    <p><h4>1.4</h4>
            <ul>
                <li>add support for oracle</li>
                <li>config use generate key</li>
                <li>auto complete for resultMap,refid,keyProperty,property</li>
                <li>support with java.sql.Timestamp java.sql.Date java.sql.Time Enum LocalDateTime LocalDate</li>
                <li>support update field with insertSelective</li>
                <li>add new icon of mybatis jump to xml ect</li>
            </ul>
     </p>
    <p><h4>1.3</h4>
            <ul>
                <li>add index column and hasDefault column when generate mybatis files</li>
                <li>jump from refid resultMap to their definition in mybatis xml. could refactor as well</li>
                <li>could refactor method name in xml</li>
                <li>add insertSelective when generate mybatis files</li>
                <li>generate for greaterThanOrEqualTo and lessThanOrEqualTo and betweenOrEqualTo</li>
                <li>add configuration to use with @Mapper</li>
                <li>fix not null issue for find module - bug fix</li>
            </ul>
     </p>
     <p><h4>1.2</h4>
            <ul>
                <li>add support for unsigned type, small int.</li>
                <li>check for using object type instead of primitive type</li>
                <li>support more auto completion for sql</li>
                <li>double type support - bug fix</li>
                <li>update field exception -bug fix</li>
            </ul>
     </p>
     <p> 1.1 fix doc</p>
     <p>1.0 use gradle, fix bugs.</p>
    ]]>
    </change-notes>

    <actions>
        <group id="com.ccnode.codegenerator.MybatisCodeHelper" text="MybatisCodeHelper" description="MybatisCodeHelper"
               popup="true">
            <separator/>
            <group id="MybatisCodeHelperSubGroup"/>
            <add-to-group group-id="ToolsMenu" relative-to-action="GenerateJavadoc" anchor="before"/>

            <action id="MybatisCodeHelper.LearnMore" class="com.ccnode.codegenerator.view.ShowLearnMoreAction"
                    text="Learn More"
                    description="Learn_More"/>
            <!--<action id="mybatis.enterLicense" class="com.ccnode.codegenerator.view.EnterLicenseAction" text="Register" description="License"/>-->

            <!--<action id="mybatis.generator" class="com.ccnode.codegenerator.view.GenCodeAction" text="genCode" description="A test menu item"/>-->
        </group>

        <group id="MybatisCodeHelpergeneratesqlgroup">
            <add-to-group group-id="GenerateGroup" relative-to-action="GenerateGetter" anchor="after"/>
            <action class="com.ccnode.codegenerator.view.GenCodeActionUsingAlt" id="MybatisCodeHelpergencodeusingalt"
                    text="generate mybatis files"
                    description="generate sql"/>
        </group>

        <group id="MyBatisCodeHelperEditorGroup">
            <add-to-group group-id="EditorPopupMenu"></add-to-group>
            <action class="com.ccnode.codegenerator.view.MultipleMethodGenerateAction"
                    id="MybatisMutlipleMethodGenerate"
                    text="generate mybatis xml" description="generate mybatis xml"/>
        </group>
        <!--<group id="com.ccnode.codegenerator.mybatis.generator" text="Gen" description="CodeGenerator">-->
        <!--<add-to-group group-id="TestActionSubGroup" />-->
        <!--<action id="mybatis.generator_1" class="com.ccnode.codegenerator.view.GenCodeAction" text="genCode1" description="A test menu item1"/>-->
        <!--<action id="mybatis.generator_2" class="com.ccnode.codegenerator.view.GenCodeAction" text="genCode2" description="A test menu item2"/>-->

        <!--</group>-->
    </actions>

    <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/build_number_ranges.html for description -->
    <idea-version since-build="141.0"/>

    <!-- please see http://www.jetbrains.org/intellij/sdk/docs/basics/getting_started/plugin_compatibility.html
         on how to target different products -->
    <!-- uncomment to enable plugin in all products
    <depends>com.intellij.modules.lang</depends>
    -->

    <application-components>
        <component>
            <implementation-class>com.ccnode.codegenerator.myconfigurable.MyBatisCodeHelperApplicationComponent
            </implementation-class>
        </component>
    </application-components>

    <project-components>
        <component>
            <implementation-class>com.ccnode.codegenerator.view.datasource.MyBatisDatasourceComponent</implementation-class>
        </component>
    </project-components>



    <extensions defaultExtensionNs="com.intellij">
        <!-- Add your extensions here -->
        <codeInsight.lineMarkerProvider language="JAVA"
                                        implementationClass="com.ccnode.codegenerator.view.MybatisJavaLineMarkerProvider"/>
        <codeInsight.lineMarkerProvider language="XML"
                                        implementationClass="com.ccnode.codegenerator.view.MybatisXmlLineMarkerProvider"/>
        <completion.contributor language="JAVA"
                                implementationClass="com.ccnode.codegenerator.view.completion.MethodNameCompletionContributor"/>

        <completion.contributor language="XML"
                                implementationClass="com.ccnode.codegenerator.view.completion.MapperSqlCompletionContributor"/>

        <completion.contributor language="XML"
                                implementationClass="com.ccnode.codegenerator.view.completion.MapperXmlTagElementCompletionContributor"/>


        <inspectionToolProvider implementation="com.ccnode.codegenerator.view.inspection.MyBatisMethodNotFoundInXmlProvider"/>
        <psi.referenceContributor
                implementation="com.ccnode.codegenerator.view.MyBatisJavaToXmlPsiReferenceContributor"/>
        <psi.referenceContributor
                implementation="com.ccnode.codegenerator.view.MyBatisXmlAttributeReferenceContributor"/>
        <applicationConfigurable instance="com.ccnode.codegenerator.myconfigurable.MyConfigurable"
                                 id="MyBatisCodeHelper"
                                 displayName="MyBatisCodeHelper"/>

        <toolWindow id="Mybatis datasource" secondary="true" anchor="right" factoryClass="com.ccnode.codegenerator.view.datasource.MyBatisDatasourceToolWindow"/>

        <!--<renamePsiElementProcessor implementation="com.ccnode.codegenerator.view.rename.RenameResultMapSqlProcessor" order="first"/>-->

        <intentionAction>
            <className>com.ccnode.codegenerator.view.GenerateMethodXmlAction</className>
            <!--<category>Conditional Operator</category>-->
            <!--<descriptionDirectoryName>ConditionalOperatorConvertor</descriptionDirectoryName>-->
            <!--<bundleName>Generate daoxml</bundleName>-->
        </intentionAction>

        <projectService serviceInterface="com.ccnode.codegenerator.view.completion.MysqlCompleteCacheInteface" serviceImplementation="com.ccnode.codegenerator.view.completion.MyBatisSqlCompleteCache"/>


        <!--<intentionAction>-->
        <!--<className>com.ccnode.codegenerator.view.GenerateDaoXmlFixAction</className>-->
        <!--<category>Conditional Operator</category>-->
        <!--<descriptionDirectoryName>ConditionalOperatorConvertor</descriptionDirectoryName>-->
        <!--</intentionAction>-->
    </extensions>

    <!--<project-components>-->
    <!--<component>-->
    <!--<!–<implementation-class>com.intellij.codeInsight.intention.Condition</implementation-class>–>-->
    <!--</component>-->
    <!--</project-components>-->

    <actions>
        <!-- Add your actions here -->
    </actions>

</idea-plugin>

  

原文地址:https://www.cnblogs.com/liqiking/p/6828594.html