├── .DS_Store ├── .gitignore ├── RestfulToolkit.iml ├── src └── main │ ├── java │ └── com │ │ ├── github │ │ └── aborn │ │ │ └── wdt │ │ │ ├── package-info.java │ │ │ ├── core │ │ │ ├── helper │ │ │ │ ├── AnnotationHelper.java │ │ │ │ ├── JavaxrsAnnotationHelper.java │ │ │ │ └── SpringAnnotationHelper.java │ │ │ ├── resolver │ │ │ │ ├── IResolver.java │ │ │ │ ├── BaseResolver.java │ │ │ │ ├── JavaxrsResolver.java │ │ │ │ └── SpringResolver.java │ │ │ └── RestServiceDataManager.java │ │ │ └── utils │ │ │ └── FileUtils.java │ │ └── zhaow │ │ ├── restful │ │ ├── common │ │ │ ├── RestSupportedAnnotationHelper.java │ │ │ ├── PsiAnnotationHelper.java │ │ │ ├── ToolkitIcons.java │ │ │ ├── ChineseUtill.java │ │ │ ├── jaxrs │ │ │ │ └── JaxrsAnnotationHelper.java │ │ │ ├── spring │ │ │ │ ├── StringUtils.java │ │ │ │ └── RequestMappingAnnotationHelper.java │ │ │ ├── KtClassHelper.java │ │ │ ├── KtFunctionHelper.java │ │ │ └── RequestHelper.java │ │ ├── navigator │ │ │ ├── RestServicesNavigatorState.java │ │ │ ├── EditSourceAction.java │ │ │ ├── RefreshProjectAction.java │ │ │ ├── CopyFullUrlAction.java │ │ │ ├── RestServiceProject.java │ │ │ ├── RestServiceProjectsManager.java │ │ │ ├── RestServiceDetail.form │ │ │ ├── RestServicesNavigatorPanel.java │ │ │ └── RestServicesNavigator.java │ │ ├── annotations │ │ │ ├── PathMappingAnnotation.java │ │ │ ├── BasePathMapping.java │ │ │ ├── JaxrsRequestParamAnnotation.java │ │ │ ├── SpringRequestParamAnnotations.java │ │ │ ├── JaxrsPathAnnotation.java │ │ │ ├── SpringControllerAnnotation.java │ │ │ ├── JaxrsHttpMethodAnnotation.java │ │ │ ├── JaxrsRequestAnnotation.java │ │ │ └── SpringRequestMethodAnnotation.java │ │ ├── action │ │ │ ├── AbstractBaseAction.java │ │ │ ├── ConvertClassToJSONCompressedAction.java │ │ │ ├── ConvertKtClassToJSONAction.java │ │ │ └── ConvertClassToJSONAction.java │ │ ├── method │ │ │ ├── HttpMethod.java │ │ │ ├── RequestPath.java │ │ │ ├── action │ │ │ │ ├── ModuleHelper.java │ │ │ │ ├── GenerateQueryParamAction.java │ │ │ │ ├── GenerateQueryParamJsonAction.java │ │ │ │ ├── GenerateFullUrlAction.java │ │ │ │ ├── SpringAnnotatedMethodAction.java │ │ │ │ ├── GenerateUrlAction.java │ │ │ │ └── PropertiesHandler.java │ │ │ └── Parameter.java │ │ ├── navigation │ │ │ └── action │ │ │ │ ├── GotoRequestMappingConfiguration.java │ │ │ │ ├── GotoRequestMappingProvider.java │ │ │ │ ├── GotoRequestMappingContributor.java │ │ │ │ ├── RestServiceChooseByNamePopup.java │ │ │ │ ├── GotoRequestMappingModel.java │ │ │ │ ├── RestServiceItem.java │ │ │ │ └── GotoRequestMappingAction.java │ │ ├── statistics │ │ │ └── RestfulToolkitFeaturesProvider.java │ │ ├── popup │ │ │ └── action │ │ │ │ └── PopupChoiceAction.java │ │ ├── highlight │ │ │ └── JTextAreaHighlight.java │ │ └── codegen │ │ │ └── SpringBootGenerator.java │ │ ├── utils │ │ ├── RestServiceDataKeys.java │ │ ├── RestfulToolkitBundle.java │ │ ├── JsonUtils.java │ │ ├── ToolkitUtil.java │ │ └── ToolkitUtil.java.bak │ │ └── livetemplate │ │ └── RestToolkitTemplatesProvider.java │ └── resources │ ├── icons │ ├── service.png │ └── method │ │ ├── d.png │ │ ├── g.png │ │ ├── p.png │ │ ├── p2.png │ │ ├── p3.png │ │ └── undefined.png │ ├── tips │ ├── images │ │ ├── GotoService.png │ │ └── SSHKeyUpload.png │ └── GotoService.html │ └── RestfulToolkitBundle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── settings.gradle ├── README.md ├── gradlew.bat ├── gradlew └── TODO /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea/ 3 | out/ 4 | *.iml 5 | build/ 6 | .gradle/ 7 | *.hprof 8 | 9 | -------------------------------------------------------------------------------- /RestfulToolkit.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/package-info.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt; 2 | 3 | // web development toolkit -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/icons/service.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/service.png -------------------------------------------------------------------------------- /src/main/resources/icons/method/d.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/method/d.png -------------------------------------------------------------------------------- /src/main/resources/icons/method/g.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/method/g.png -------------------------------------------------------------------------------- /src/main/resources/icons/method/p.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/method/p.png -------------------------------------------------------------------------------- /src/main/resources/icons/method/p2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/method/p2.png -------------------------------------------------------------------------------- /src/main/resources/icons/method/p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/method/p3.png -------------------------------------------------------------------------------- /src/main/resources/icons/method/undefined.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/icons/method/undefined.png -------------------------------------------------------------------------------- /src/main/resources/tips/images/GotoService.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/tips/images/GotoService.png -------------------------------------------------------------------------------- /src/main/resources/tips/images/SSHKeyUpload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aborn/RestfulToolkit/HEAD/src/main/resources/tips/images/SSHKeyUpload.png -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/RestSupportedAnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | 4 | public interface RestSupportedAnnotationHelper { 5 | } 6 | -------------------------------------------------------------------------------- /src/main/resources/RestfulToolkitBundle.properties: -------------------------------------------------------------------------------- 1 | toolkit.name=RestfulToolkit 2 | toolkit.scanning.projects=Scanning projects... 3 | toolkit.navigator.nothing.to.display= No Services Found ,try use {0} to refresh services -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Jun 10 22:05:09 CST 2020 2 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.4.1-all.zip 3 | distributionBase=GRADLE_USER_HOME 4 | distributionPath=wrapper/dists 5 | zipStorePath=wrapper/dists 6 | zipStoreBase=GRADLE_USER_HOME 7 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RestServicesNavigatorState.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | import com.intellij.util.xmlb.annotations.Tag; 4 | import org.jdom.Element; 5 | 6 | public class RestServicesNavigatorState { 7 | public boolean showPort = true; 8 | 9 | @Tag("treeState") 10 | public Element treeState; 11 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file was generated by the Gradle 'init' task. 3 | * 4 | * The settings file is used to specify which projects to include in your build. 5 | * 6 | * Detailed information about configuring a multi-project build in Gradle can be found 7 | * in the user manual at https://docs.gradle.org/6.4.1/userguide/multi_project_builds.html 8 | */ 9 | 10 | rootProject.name = 'RestfulToolkit' 11 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/utils/RestServiceDataKeys.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.utils; 2 | 3 | import com.intellij.openapi.actionSystem.DataKey; 4 | import com.zhaow.restful.navigation.action.RestServiceItem; 5 | 6 | import java.util.List; 7 | 8 | public class RestServiceDataKeys { 9 | 10 | public static final DataKey> SERVICE_ITEMS = DataKey.create("SERVICE_ITEMS"); 11 | 12 | private RestServiceDataKeys() { 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/PathMappingAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | public interface PathMappingAnnotation { 4 | // List allPathMappingAnnotations = new ArrayList<>(); 5 | public String getQualifiedName() ; 6 | 7 | public String getShortName(); 8 | 9 | // public List getPathMappings(); 10 | 11 | // public void addToPathList(PathMapping mapping); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/livetemplate/RestToolkitTemplatesProvider.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.livetemplate; 2 | 3 | import com.intellij.codeInsight.template.impl.DefaultLiveTemplatesProvider; 4 | 5 | public class RestToolkitTemplatesProvider implements DefaultLiveTemplatesProvider { 6 | @Override 7 | public String[] getDefaultLiveTemplateFiles() { 8 | // return new String[]{"/liveTemplates/RestToolkit"}; 9 | return null; 10 | } 11 | 12 | @Override 13 | public String[] getHiddenLiveTemplateFiles() { 14 | return null; 15 | } 16 | } -------------------------------------------------------------------------------- /src/main/resources/tips/GotoService.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 |

7 | To navigate any rest service in the editor quickly, press &shortcut:GotoService; 8 | (Navigate | Rest Service) 9 | and start typing the url of the service. Choose the item from a drop-down list that appears.

10 |

11 |

12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/BasePathMapping.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public abstract class BasePathMapping { 7 | static List pathMappings = new ArrayList<>(); 8 | 9 | public List getPathMappings() { 10 | return pathMappings; 11 | } 12 | 13 | /*need override*/ 14 | public void addToPathList(PathMappingAnnotation mapping) { 15 | pathMappings.add(mapping); 16 | } 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/helper/AnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.helper; 2 | 3 | import com.intellij.psi.PsiClass; 4 | import com.intellij.psi.PsiMethod; 5 | import com.zhaow.restful.method.RequestPath; 6 | 7 | /** 8 | * @author aborn 9 | * @date 2020/06/15 12:02 PM 10 | */ 11 | public interface AnnotationHelper { 12 | 13 | /** 14 | * get class uri path 15 | * @param psiClass 16 | * @return 17 | */ 18 | String getClassUriPath(PsiClass psiClass); 19 | 20 | /** 21 | * 22 | * @param psiMethod 23 | * @return 24 | */ 25 | RequestPath[] getRequestPaths(PsiMethod psiMethod); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/JaxrsRequestParamAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum JaxrsRequestParamAnnotation { 5 | QUERY_PARAM("QueryParam","javax.ws.rs.QueryParam"), PATH_PARAM("PathParam","javax.ws.rs.PathParam"); 6 | 7 | JaxrsRequestParamAnnotation(String shortName, String qualifiedName) { 8 | this.shortName = shortName; 9 | this.qualifiedName = qualifiedName; 10 | } 11 | 12 | private String shortName; 13 | private String qualifiedName; 14 | 15 | public String getQualifiedName() { 16 | return qualifiedName; 17 | } 18 | 19 | public String getShortName() { 20 | return shortName; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/resolver/IResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.resolver; 2 | 3 | import com.intellij.openapi.module.Module; 4 | import com.intellij.openapi.project.Project; 5 | import com.zhaow.restful.navigation.action.RestServiceItem; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author aborn 11 | * @date 2020/06/15 11:26 AM 12 | */ 13 | public interface IResolver { 14 | /** 15 | * build data from module in project 16 | * @param project 17 | * @param module 18 | * @return 19 | */ 20 | List getRestServiceItemList(Project project, Module module); 21 | 22 | /** 23 | * build data from all project 24 | * @param project 25 | * @return 26 | */ 27 | List getRestServiceItemList(Project project); 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/SpringRequestParamAnnotations.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum SpringRequestParamAnnotations { 5 | REQUEST_PARAM("RequestParam", "org.springframework.web.bind.annotation.RequestParam"), 6 | REQUEST_BODY("RequestBody", "org.springframework.web.bind.annotation.RequestBody"), 7 | PATH_VARIABLE("PathVariable", "org.springframework.web.bind.annotation.PathVariable"); 8 | 9 | SpringRequestParamAnnotations(String shortName, String qualifiedName) { 10 | this.shortName = shortName; 11 | this.qualifiedName = qualifiedName; 12 | } 13 | 14 | private String shortName; 15 | private String qualifiedName; 16 | 17 | public String getQualifiedName() { 18 | return qualifiedName; 19 | } 20 | 21 | public String getShortName() { 22 | return shortName; 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/action/AbstractBaseAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.DataKeys; 6 | import com.intellij.openapi.module.Module; 7 | import com.intellij.openapi.project.Project; 8 | 9 | 10 | public abstract class AbstractBaseAction extends AnAction { 11 | 12 | protected Module myModule(AnActionEvent e) { 13 | return e.getData(DataKeys.MODULE); 14 | } 15 | 16 | protected Project myProject(AnActionEvent e) { 17 | return getEventProject(e); 18 | } 19 | 20 | /** 21 | * 设置触发有效条件 22 | * @param e 23 | * @param visible 24 | */ 25 | protected void setActionPresentationVisible(AnActionEvent e, boolean visible) { 26 | e.getPresentation().setVisible(visible); 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/HttpMethod.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public enum HttpMethod { 7 | GET, POST, PUT, DELETE, PATCH,HEAD,OPTIONS,TRACE,CONNECT; 8 | 9 | private static final Map methodMap = new HashMap(8); 10 | 11 | 12 | public static HttpMethod getByRequestMethod(String method) { 13 | if (method == null || method.isEmpty()) { 14 | return null; 15 | } 16 | 17 | String[] split = method.split("\\."); 18 | 19 | if (split.length > 1) { 20 | method = split[split.length - 1].toUpperCase(); 21 | return HttpMethod.valueOf(method); 22 | } 23 | 24 | return HttpMethod.valueOf(method.toUpperCase()); 25 | } 26 | 27 | static { 28 | for (HttpMethod httpMethod : values()) { 29 | methodMap.put(httpMethod.name(), httpMethod); 30 | } 31 | } 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/JaxrsPathAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum JaxrsPathAnnotation implements PathMappingAnnotation { 5 | 6 | PATH("Path", "javax.ws.rs.Path"); 7 | 8 | JaxrsPathAnnotation(String shortName, String qualifiedName) { 9 | this.shortName = shortName; 10 | this.qualifiedName = qualifiedName; 11 | } 12 | 13 | private String shortName; 14 | private String qualifiedName; 15 | 16 | public String getQualifiedName() { 17 | return qualifiedName; 18 | } 19 | 20 | public String getShortName() { 21 | return shortName; 22 | } 23 | /* 24 | @Override 25 | public List getPathMappings() { 26 | return allPathMappingAnnotations; 27 | } 28 | 29 | static { 30 | for (JaxrsPathAnnotation annotation : JaxrsPathAnnotation.values()) { 31 | allPathMappingAnnotations.add(annotation); 32 | } 33 | }*/ 34 | 35 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/action/ConvertClassToJSONCompressedAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.openapi.ide.CopyPasteManager; 6 | import com.intellij.psi.PsiClass; 7 | import com.intellij.psi.PsiElement; 8 | import com.zhaow.restful.common.PsiClassHelper; 9 | 10 | import java.awt.datatransfer.StringSelection; 11 | 12 | public class ConvertClassToJSONCompressedAction extends ConvertClassToJSONAction { 13 | @Override 14 | public void actionPerformed(AnActionEvent e) { 15 | 16 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 17 | PsiClass psiClass = getPsiClass(psiElement); 18 | 19 | if(psiClass == null) return; 20 | 21 | String json = PsiClassHelper.create(psiClass).convertClassToJSON(myProject(e), false); 22 | CopyPasteManager.getInstance().setContents(new StringSelection(json)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/utils/RestfulToolkitBundle.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.utils; 2 | 3 | import com.intellij.CommonBundle; 4 | import org.jetbrains.annotations.NonNls; 5 | import org.jetbrains.annotations.PropertyKey; 6 | 7 | import java.lang.ref.Reference; 8 | import java.lang.ref.SoftReference; 9 | import java.util.ResourceBundle; 10 | 11 | /** 12 | * @author zhaow 13 | */ 14 | public class RestfulToolkitBundle { 15 | 16 | private static Reference ourBundle; 17 | 18 | @NonNls private static final String BUNDLE = "RestfulToolkitBundle"; 19 | 20 | private RestfulToolkitBundle() { 21 | 22 | } 23 | 24 | public static String message(@PropertyKey(resourceBundle = BUNDLE) String key, Object... params) { 25 | return CommonBundle.message(getBundle(), key, params); 26 | } 27 | 28 | private static ResourceBundle getBundle() { 29 | ResourceBundle bundle = com.intellij.reference.SoftReference.dereference(ourBundle); 30 | if (bundle == null) { 31 | bundle = ResourceBundle.getBundle(BUNDLE); 32 | ourBundle = new SoftReference<>(bundle); 33 | } 34 | return bundle; 35 | } 36 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/action/ConvertKtClassToJSONAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.psi.PsiElement; 6 | import org.jetbrains.kotlin.psi.KtClass; 7 | 8 | //import com.intellij.psi.PsiClass; 9 | //import com.zhaow.restful.common.PsiClassHelper; 10 | 11 | public class ConvertKtClassToJSONAction extends AbstractBaseAction { 12 | @Override 13 | public void actionPerformed(AnActionEvent e) { 14 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 15 | if (psiElement instanceof KtClass) { 16 | 17 | /*String json = KtClassHelper.create((KtClass) psiElement).convertClassToJSON(myProject(e), true); 18 | CopyPasteManager.getInstance().setContents(new StringSelection(json));*/ 19 | } 20 | } 21 | 22 | @Override 23 | public void update(AnActionEvent e) { 24 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 25 | setActionPresentationVisible(e,psiElement instanceof KtClass); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RestfulToolkit 2 | ## A toolkit for restful services development. 3 | 4 | * 1.*ONE STEP* to navigate to service declaration. 5 | ( use: `Ctrl + \` or `Ctrl + Alt + N` ) 6 | * 2.Show RESTful service structure. 7 | * 3.A simple request client tool. 8 | * 4.Add some useful functions at request method, 9 | "Generate&Copy Query Param", "Generate&Copy URL", etc. 10 | * 5.Other useful functions, "Convert to JSON" to java class,format json data 11 | *( *Windows*: `Ctrl + Enter`; *Mac*: `Command + Enter` ) . 12 | 13 | #### supported Spring framework (Spring MVC / Spring Boot) 14 | #### supported JAX-RS ) 15 | #### supported Kotlin language 16 | ------ 17 | ### 一套 Restful 服务开发辅助工具集。 18 | 19 | * 1.根据 URL 直接导航到对应的方法定义 ( `Ctrl \` or `Ctrl Alt N` ); 20 | * 2.提供了一个 Services tree 的显示窗口; 21 | * 3.一个简单的 request client 工具; 22 | * 4.在 Controller 方法上添加了 "复制生成 URL","复制方法参数","复制生成 JSON" (方法参数中存在 RequestBody 注解) 等几个功能; 23 | * 5.其他一些个人觉得有用的小功能, java 类上添加 "Convert to JSON" 功能,格式化 json 数据 ( *Windows*: `Ctrl + Enter`; *Mac*: `Command + Enter` )。 24 | 25 | #### 支持 Spring 体系 (Spring MVC / Spring Boot) 26 | #### 支持 JAX-RS 27 | #### 支持 Kotlin 语言语法 28 | ------------ 29 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/RequestPath.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method; 2 | 3 | public class RequestPath { 4 | String path; 5 | String method; 6 | 7 | public RequestPath(String path, String method) { 8 | this.path = path; 9 | this.method = method; 10 | } 11 | 12 | public String getPath() { 13 | return path; 14 | } 15 | 16 | public void setPath(String path) { 17 | this.path = path; 18 | } 19 | 20 | public String getMethod() { 21 | return method; 22 | } 23 | 24 | public void setMethod(String method) { 25 | this.method = method; 26 | } 27 | 28 | public void concat(RequestPath classRequestPath) { 29 | String classUri = classRequestPath.getPath(); 30 | String methodUri = this.path; 31 | //TODO 32 | if (!classUri.startsWith("/")) classUri = "/".concat(classUri); 33 | if (!classUri.endsWith("/")) classUri = classUri.concat("/"); 34 | if (this.path.startsWith("/")) methodUri = this.path.substring(1, this.path.length()); 35 | 36 | this.path = classUri.concat(methodUri) ; 37 | // method 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/EditSourceAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.Presentation; 6 | import com.intellij.openapi.project.DumbAware; 7 | import com.intellij.util.PsiNavigateUtil; 8 | import com.zhaow.restful.navigation.action.RestServiceItem; 9 | import com.zhaow.utils.RestServiceDataKeys; 10 | 11 | import java.util.List; 12 | 13 | public class EditSourceAction extends AnAction implements DumbAware { 14 | @Override 15 | public void update(AnActionEvent e) { 16 | super.update(e); 17 | Presentation p = e.getPresentation(); 18 | p.setVisible(isVisible(e)); 19 | } 20 | 21 | @Override 22 | public void actionPerformed(AnActionEvent e) { 23 | List serviceItems = RestServiceDataKeys.SERVICE_ITEMS.getData(e.getDataContext()); 24 | 25 | for (RestServiceItem serviceItem : serviceItems) { 26 | PsiNavigateUtil.navigate(serviceItem.getPsiElement()); 27 | } 28 | 29 | } 30 | 31 | 32 | protected boolean isVisible(AnActionEvent e) { 33 | return true; 34 | } 35 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/SpringControllerAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum SpringControllerAnnotation implements PathMappingAnnotation { 5 | 6 | CONTROLLER("Controller", "org.springframework.stereotype.Controller"), 7 | REST_CONTROLLER("RestController", "org.springframework.web.bind.annotation.RestController"); 8 | 9 | SpringControllerAnnotation(String shortName, String qualifiedName) { 10 | this.shortName = shortName; 11 | this.qualifiedName = qualifiedName; 12 | } 13 | 14 | private String shortName; 15 | private String qualifiedName; 16 | 17 | public String getQualifiedName() { 18 | return qualifiedName; 19 | } 20 | 21 | public String getShortName() { 22 | return shortName; 23 | } 24 | 25 | /* 26 | @Override 27 | public List getPathMappings() { 28 | return allPathMappingAnnotations; 29 | } 30 | */ 31 | 32 | /* static { 33 | for (SpringControllerAnnotation springControllerAnnotation : SpringControllerAnnotation.values()) { 34 | allPathMappingAnnotations.add(springControllerAnnotation); 35 | } 36 | }*/ 37 | 38 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RefreshProjectAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.CommonDataKeys; 6 | import com.intellij.openapi.actionSystem.DataContext; 7 | import com.intellij.openapi.project.Project; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.jetbrains.annotations.Nullable; 10 | 11 | public class RefreshProjectAction extends AnAction { 12 | 13 | protected void perform(@NotNull RestServiceProjectsManager manager) { 14 | manager.forceUpdateAllProjects(this); 15 | } 16 | 17 | @Override 18 | public void actionPerformed(AnActionEvent e) { 19 | 20 | final Project project = getProject(e.getDataContext()); 21 | RestServicesNavigator servicesNavigator = RestServicesNavigator.getInstance(project); 22 | 23 | servicesNavigator.initComponent(); 24 | servicesNavigator.atachEvent(e); 25 | servicesNavigator.scheduleStructureUpdate(); 26 | } 27 | 28 | @Nullable 29 | public static Project getProject(DataContext context) { 30 | return CommonDataKeys.PROJECT.getData(context); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/GotoRequestMappingConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigation.action; 2 | 3 | import com.intellij.ide.util.gotoByName.ChooseByNameFilterConfiguration; 4 | import com.intellij.openapi.components.ServiceManager; 5 | import com.intellij.openapi.components.State; 6 | import com.intellij.openapi.components.Storage; 7 | import com.intellij.openapi.components.StoragePathMacros; 8 | import com.intellij.openapi.project.Project; 9 | import com.zhaow.restful.method.HttpMethod; 10 | 11 | /** 12 | * Configuration for file type filtering popup in "Go to | Service" action. 13 | * 14 | * @author zhaow 15 | */ 16 | @State(name = "GotoRequestMappingConfiguration", storages = @Storage(StoragePathMacros.WORKSPACE_FILE)) 17 | class GotoRequestMappingConfiguration extends ChooseByNameFilterConfiguration { 18 | /** 19 | * Get configuration instance 20 | * 21 | * @param project a project instance 22 | * @return a configuration instance 23 | */ 24 | public static GotoRequestMappingConfiguration getInstance(Project project) { 25 | return ServiceManager.getService(project, GotoRequestMappingConfiguration.class); 26 | } 27 | 28 | @Override 29 | protected String nameForElement(HttpMethod type) { 30 | return type.name(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/resolver/BaseResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.resolver; 2 | 3 | import com.github.aborn.wdt.core.helper.AnnotationHelper; 4 | import com.intellij.psi.PsiElement; 5 | import com.zhaow.restful.method.RequestPath; 6 | import com.zhaow.restful.navigation.action.RestServiceItem; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * @author aborn 11 | * @date 2020/06/15 11:41 AM 12 | */ 13 | public abstract class BaseResolver implements IResolver { 14 | protected AnnotationHelper annotationHelper; 15 | 16 | @NotNull 17 | protected RestServiceItem buildRestServiceItem(PsiElement psiMethod, String classUriPath, RequestPath requestMapping) { 18 | if (!classUriPath.startsWith("/")) { 19 | classUriPath = "/".concat(classUriPath); 20 | } 21 | if (!classUriPath.endsWith("/")) { 22 | classUriPath = classUriPath.concat("/"); 23 | } 24 | 25 | String methodPath = requestMapping.getPath(); 26 | 27 | if (methodPath.startsWith("/")) { 28 | methodPath = methodPath.substring(1, methodPath.length()); 29 | } 30 | String requestPath = classUriPath + methodPath; 31 | return new RestServiceItem(psiMethod, requestMapping.getMethod(), requestPath); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/utils/JsonUtils.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.utils; 2 | 3 | import com.google.gson.*; 4 | import com.intellij.openapi.util.text.StringUtil; 5 | 6 | /** 7 | * @author zhaow 8 | */ 9 | public class JsonUtils { 10 | public JsonUtils() { 11 | } 12 | 13 | public static boolean isValidJson(String json) { 14 | if (StringUtil.isEmptyOrSpaces(json)) { 15 | return false; 16 | } 17 | 18 | return isValidJsonObject(json) || isValidJsonArray(json); 19 | } 20 | 21 | public static String format(String str) { 22 | JsonParser parser = new JsonParser(); 23 | JsonElement parse = parser.parse(str); 24 | Gson gson = new GsonBuilder().setPrettyPrinting().create(); 25 | String json = gson.toJson(parse); 26 | return json; 27 | } 28 | 29 | private static boolean isGsonFormat(String targetStr,Class clazz) { 30 | try { 31 | new Gson().fromJson(targetStr,clazz); 32 | return true; 33 | } catch(JsonSyntaxException ex) { 34 | return false; 35 | } 36 | } 37 | 38 | public static boolean isValidJsonObject(String targetStr){ 39 | return isGsonFormat(targetStr,JsonObject.class); 40 | } 41 | 42 | public static boolean isValidJsonArray(String targetStr){ 43 | return isGsonFormat(targetStr,JsonArray.class); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/JaxrsHttpMethodAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum JaxrsHttpMethodAnnotation { 5 | GET("javax.ws.rs.GET", "GET"), 6 | POST( "javax.ws.rs.POST", "POST"), 7 | PUT( "javax.ws.rs.PUT", "PUT"), 8 | DELETE( "javax.ws.rs.DELETE", "DELETE"), 9 | HEAD( "javax.ws.rs.HEAD", "HEAD"), 10 | PATCH("javax.ws.rs.PATCH", "PATCH"); 11 | 12 | JaxrsHttpMethodAnnotation(String qualifiedName, String methodName) { 13 | this.qualifiedName = qualifiedName; 14 | this.methodName = methodName; 15 | } 16 | 17 | private String qualifiedName; 18 | private String methodName; 19 | 20 | public String methodName() { 21 | return this.methodName; 22 | } 23 | 24 | public String getQualifiedName() { 25 | return qualifiedName; 26 | } 27 | 28 | public String getShortName() { 29 | return qualifiedName.substring(qualifiedName.lastIndexOf(".")-1); 30 | } 31 | 32 | public static JaxrsHttpMethodAnnotation getByQualifiedName(String qualifiedName) { 33 | for (JaxrsHttpMethodAnnotation springRequestAnnotation : JaxrsHttpMethodAnnotation.values()) { 34 | if (springRequestAnnotation.getQualifiedName().equals(qualifiedName)) { 35 | return springRequestAnnotation; 36 | } 37 | } 38 | return null; 39 | } 40 | 41 | } -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.utils; 2 | 3 | import com.intellij.psi.PsiClass; 4 | import com.intellij.psi.PsiDirectory; 5 | import com.intellij.psi.PsiFile; 6 | import com.intellij.psi.impl.source.PsiJavaFileImpl; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class FileUtils { 12 | 13 | /** 14 | * 提取java文件 15 | * 16 | * @param directory 17 | * @return 18 | */ 19 | public static List getJavaFilesFromDir(PsiDirectory directory) { 20 | List psiClasses = new ArrayList<>(); 21 | if ( directory != null) { 22 | for ( PsiFile file : directory.getFiles() ) { 23 | if ( !file.getFileType().getName().equals("JAVA") ) { 24 | continue; 25 | } 26 | PsiClass[] classes = ((PsiJavaFileImpl) file).getClasses(); 27 | 28 | if ( classes.length > 0) { 29 | psiClasses.add( classes[0] ); 30 | } 31 | } 32 | 33 | if ( directory.getSubdirectories() != null && directory.getSubdirectories().length > 0 ) { 34 | for ( PsiDirectory subDir : directory.getSubdirectories() ) { 35 | psiClasses.addAll( getJavaFilesFromDir(subDir) ); 36 | } 37 | } 38 | } 39 | return psiClasses; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/JaxrsRequestAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum JaxrsRequestAnnotation { 5 | 6 | PATH("Path", "javax.ws.rs.Path", null); 7 | 8 | JaxrsRequestAnnotation(String shortName, String qualifiedName, String methodName) { 9 | this.shortName = shortName; 10 | this.qualifiedName = qualifiedName; 11 | this.methodName = methodName; 12 | } 13 | 14 | private String shortName; 15 | private String qualifiedName; 16 | private String methodName; 17 | 18 | public String methodName() { 19 | return this.methodName; 20 | } 21 | 22 | public String getQualifiedName() { 23 | return qualifiedName; 24 | } 25 | 26 | public String getShortName() { 27 | return shortName; 28 | } 29 | 30 | public static JaxrsRequestAnnotation getByShortName(String shortName) { 31 | for (JaxrsRequestAnnotation requestAnnotation : JaxrsRequestAnnotation.values()) { 32 | if (requestAnnotation.getShortName().equals(shortName)) { 33 | return requestAnnotation; 34 | } 35 | } 36 | return null; 37 | } 38 | 39 | public static JaxrsRequestAnnotation getByQualifiedName(String qualifiedName) { 40 | for (JaxrsRequestAnnotation requestAnnotation : JaxrsRequestAnnotation.values()) { 41 | if (requestAnnotation.getQualifiedName().equals(qualifiedName)) { 42 | return requestAnnotation; 43 | } 44 | } 45 | return null; 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/ModuleHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | 4 | import com.intellij.openapi.module.Module; 5 | import org.apache.commons.lang.StringUtils; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | //PathAndQuery AbsolutePath AbsoluteUri Query 9 | public class ModuleHelper { 10 | Module module; 11 | 12 | // URL 13 | private static final String SCHEME = "http://"; //PROTOCOL 14 | private static final String HOST = "localhost"; 15 | private static final String PORT = "8080"; // int 16 | public static String DEFAULT_URI = "http://localhost"+":"+PORT; 17 | // private static final String PATH = "http://localhost"+":"+PORT; // PATH or FILE 18 | 19 | public static String getAUTHORITY() { 20 | return null; 21 | } 22 | 23 | PropertiesHandler propertiesHandler; 24 | 25 | public ModuleHelper(Module module) { 26 | this.module = module; 27 | propertiesHandler = new PropertiesHandler(module); 28 | } 29 | 30 | 31 | public static ModuleHelper create(Module module) { 32 | return new ModuleHelper(module); 33 | } 34 | 35 | @NotNull 36 | public String getServiceHostPrefix() { 37 | if (module == null) { 38 | return DEFAULT_URI; 39 | } 40 | 41 | String port = propertiesHandler.getServerPort(); 42 | if (StringUtils.isEmpty(port)) port = PORT; 43 | 44 | String contextPath = propertiesHandler.getContextPath(); 45 | return new StringBuilder(SCHEME).append(HOST).append(":").append(port).append(contextPath).toString(); 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/CopyFullUrlAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.Presentation; 6 | import com.intellij.openapi.ide.CopyPasteManager; 7 | import com.intellij.openapi.project.DumbAware; 8 | import com.zhaow.restful.navigation.action.RestServiceItem; 9 | import com.zhaow.utils.RestServiceDataKeys; 10 | 11 | import java.awt.datatransfer.StringSelection; 12 | import java.util.List; 13 | 14 | public class CopyFullUrlAction extends AnAction implements DumbAware { 15 | @Override 16 | public void update(AnActionEvent e) { 17 | super.update(e); 18 | Presentation p = e.getPresentation(); 19 | p.setEnabled(isAvailable(e)); 20 | p.setVisible(isVisible(e)); 21 | } 22 | 23 | @Override 24 | public void actionPerformed(AnActionEvent e) { 25 | List serviceItems = RestServiceDataKeys.SERVICE_ITEMS.getData(e.getDataContext()); 26 | StringBuilder sb = new StringBuilder(); 27 | for (RestServiceItem serviceItem : serviceItems) { 28 | if (sb.length() > 1) { 29 | sb.append("\n\n"); 30 | } 31 | sb.append(serviceItem.getFullUrl()); 32 | } 33 | 34 | CopyPasteManager.getInstance().setContents(new StringSelection(sb.toString())); 35 | 36 | // RestServiceProjectsManager.getInstance(getEventProject(e)). 37 | /* CopyPasteManager.getInstance().setContents(...);*/ 38 | } 39 | 40 | /* getSelectRestServiceNodes */ 41 | 42 | protected boolean isAvailable(AnActionEvent e) { 43 | return true; 44 | } 45 | 46 | protected boolean isVisible(AnActionEvent e) { 47 | return true; 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/statistics/RestfulToolkitFeaturesProvider.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.statistics; 2 | 3 | import com.intellij.featureStatistics.ApplicabilityFilter; 4 | import com.intellij.featureStatistics.FeatureDescriptor; 5 | import com.intellij.featureStatistics.GroupDescriptor; 6 | import com.intellij.featureStatistics.ProductivityFeaturesProvider; 7 | 8 | import java.util.Collections; 9 | 10 | public class RestfulToolkitFeaturesProvider extends ProductivityFeaturesProvider { 11 | public static final String CLOUDS_GROUP_ID = "clouds"; 12 | public static final String UPLOAD_SSH_KEY_FEATURE_ID = "upload.ssh.key"; 13 | 14 | @Override 15 | public FeatureDescriptor[] getFeatureDescriptors() { 16 | return new FeatureDescriptor[]{new FeatureDescriptor(UPLOAD_SSH_KEY_FEATURE_ID, 17 | CLOUDS_GROUP_ID, 18 | "UploadSshKey.html", 19 | "upload.ssh.key.display.name", 20 | 0, 21 | 0, 22 | Collections.emptySet(), 23 | 0, 24 | this)}; 25 | } 26 | 27 | @Override 28 | public GroupDescriptor[] getGroupDescriptors() 29 | { 30 | return new GroupDescriptor[] { 31 | new GroupDescriptor(CLOUDS_GROUP_ID, "group.display.name") 32 | }; 33 | } 34 | 35 | @Override 36 | public ApplicabilityFilter[] getApplicabilityFilters() { 37 | return new ApplicabilityFilter[0]; 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/GotoRequestMappingProvider.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigation.action; 2 | 3 | 4 | import com.intellij.ide.util.gotoByName.ChooseByNameBase; 5 | import com.intellij.ide.util.gotoByName.DefaultChooseByNameItemProvider; 6 | import com.intellij.openapi.progress.ProgressIndicator; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.codeStyle.MinusculeMatcher; 9 | import com.intellij.psi.codeStyle.NameUtil; 10 | import com.intellij.util.Processor; 11 | import com.zhaow.utils.ToolkitUtil; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | import java.util.List; 16 | 17 | public class GotoRequestMappingProvider extends DefaultChooseByNameItemProvider { 18 | 19 | @NotNull 20 | @Override 21 | public List filterNames(@NotNull ChooseByNameBase base, @NotNull String[] names, @NotNull String pattern) { 22 | return super.filterNames(base, names, pattern); 23 | } 24 | 25 | 26 | @NotNull 27 | private static MinusculeMatcher buildPatternMatcher(@NotNull String pattern, @NotNull NameUtil.MatchingCaseSensitivity caseSensitivity) { 28 | return NameUtil.buildMatcher(pattern, caseSensitivity); 29 | } 30 | 31 | public GotoRequestMappingProvider(@Nullable PsiElement context) { 32 | super(context); 33 | } 34 | 35 | @Override 36 | public boolean filterElements(@NotNull ChooseByNameBase base, @NotNull String pattern, boolean everywhere, @NotNull ProgressIndicator indicator, @NotNull Processor consumer) { 37 | 38 | pattern = ToolkitUtil.removeRedundancyMarkup(pattern); 39 | 40 | return super.filterElements(base, pattern, everywhere, indicator, consumer); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/PsiAnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | import com.intellij.psi.*; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.ArrayList; 7 | import java.util.List; 8 | 9 | public class PsiAnnotationHelper { 10 | @NotNull 11 | public static List getAnnotationAttributeValues(PsiAnnotation annotation, String attr) { 12 | PsiAnnotationMemberValue value = annotation.findDeclaredAttributeValue(attr); 13 | 14 | List values = new ArrayList<>(); 15 | //只有注解 16 | //一个值 class com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl 17 | //多个值 class com.intellij.psi.impl.source.tree.java.PsiArrayInitializerMemberValueImpl 18 | if (value instanceof PsiReferenceExpression) { 19 | PsiReferenceExpression expression = (PsiReferenceExpression) value; 20 | values.add(expression.getText()); 21 | } else if (value instanceof PsiLiteralExpression) { 22 | // values.add(psiNameValuePair.getLiteralValue()); 23 | values.add(((PsiLiteralExpression) value).getValue().toString()); 24 | } else if (value instanceof PsiArrayInitializerMemberValue) { 25 | PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue) value).getInitializers(); 26 | 27 | for (PsiAnnotationMemberValue initializer : initializers) { 28 | values.add(initializer.getText().replaceAll("\\\"", "")); 29 | } 30 | } 31 | 32 | return values; 33 | } 34 | 35 | public static String getAnnotationAttributeValue(PsiAnnotation annotation, String attr) { 36 | List values = getAnnotationAttributeValues(annotation, attr); 37 | if (!values.isEmpty()) { 38 | return values.get(0); 39 | } 40 | return null; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/popup/action/PopupChoiceAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.popup.action; 2 | 3 | 4 | import com.intellij.codeInsight.lookup.LookupManager; 5 | import com.intellij.openapi.actionSystem.ActionGroup; 6 | import com.intellij.openapi.actionSystem.ActionManager; 7 | import com.intellij.openapi.actionSystem.AnActionEvent; 8 | import com.intellij.openapi.actionSystem.CommonDataKeys; 9 | import com.intellij.openapi.editor.Editor; 10 | import com.intellij.openapi.project.DumbAwareAction; 11 | import com.intellij.openapi.project.Project; 12 | import com.intellij.openapi.ui.popup.JBPopupFactory; 13 | import com.intellij.openapi.ui.popup.ListPopup; 14 | 15 | /** 16 | * @author Olivier Smedile 17 | * @version $Id: File Header.java 3 2008-03-11 08:52:55Z osmedile $ 18 | */ 19 | public class PopupChoiceAction extends DumbAwareAction { 20 | private ActionGroup actionGroup; 21 | 22 | 23 | public PopupChoiceAction() { 24 | actionGroup = (ActionGroup) ActionManager.getInstance().getAction("RestfulToolkitGroup"); 25 | } 26 | 27 | @Override 28 | public void actionPerformed(AnActionEvent e) { 29 | ListPopup popup = JBPopupFactory.getInstance().createActionGroupPopup(null, actionGroup, 30 | e.getDataContext(), JBPopupFactory.ActionSelectionAid.ALPHA_NUMBERING, false); 31 | 32 | popup.showInBestPositionFor(e.getDataContext()); 33 | } 34 | 35 | @Override 36 | public void update(AnActionEvent e) { 37 | super.update(e); 38 | Editor editor = CommonDataKeys.EDITOR.getData(e.getDataContext()); 39 | if (editor == null) { 40 | e.getPresentation().setEnabled(false); 41 | return; 42 | } 43 | Project project = getEventProject(e); 44 | if (project != null) { 45 | e.getPresentation().setEnabled(LookupManager.getInstance(project).getActiveLookup() == null); 46 | return; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/action/ConvertClassToJSONAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.openapi.ide.CopyPasteManager; 6 | import com.intellij.psi.PsiClass; 7 | import com.intellij.psi.PsiElement; 8 | import com.zhaow.restful.common.PsiClassHelper; 9 | import org.jetbrains.annotations.Nullable; 10 | import org.jetbrains.kotlin.asJava.LightClassUtil; 11 | import org.jetbrains.kotlin.asJava.LightClassUtilsKt; 12 | import org.jetbrains.kotlin.psi.KtClassOrObject; 13 | 14 | import java.awt.datatransfer.StringSelection; 15 | 16 | public class ConvertClassToJSONAction extends AbstractBaseAction { 17 | @Override 18 | public void actionPerformed(AnActionEvent e) { 19 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 20 | PsiClass psiClass = getPsiClass(psiElement); 21 | 22 | if(psiClass == null) return; 23 | 24 | String json = PsiClassHelper.create(psiClass).convertClassToJSON(myProject(e), true); 25 | CopyPasteManager.getInstance().setContents(new StringSelection(json)); 26 | } 27 | 28 | @Nullable 29 | protected PsiClass getPsiClass(PsiElement psiElement) { 30 | PsiClass psiClass = null; 31 | if (psiElement instanceof PsiClass) { 32 | psiClass = (PsiClass) psiElement; 33 | 34 | }else if (psiElement instanceof KtClassOrObject) { 35 | if (LightClassUtil.INSTANCE.canGenerateLightClass((KtClassOrObject) psiElement)) { 36 | psiClass = LightClassUtilsKt.toLightClass((KtClassOrObject) psiElement); 37 | } 38 | } 39 | return psiClass; 40 | } 41 | 42 | @Override 43 | public void update(AnActionEvent e) { 44 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 45 | setActionPresentationVisible(e,psiElement instanceof PsiClass || psiElement instanceof KtClassOrObject); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/GotoRequestMappingContributor.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigation.action; 2 | 3 | 4 | import com.github.aborn.wdt.core.RestServiceDataManager; 5 | import com.intellij.navigation.ChooseByNameContributor; 6 | import com.intellij.navigation.NavigationItem; 7 | import com.intellij.openapi.module.Module; 8 | import com.intellij.openapi.project.Project; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.List; 12 | 13 | public class GotoRequestMappingContributor implements ChooseByNameContributor { 14 | Module myModule; 15 | 16 | private List navItem; 17 | 18 | public GotoRequestMappingContributor(Module myModule) { 19 | this.myModule = myModule; 20 | } 21 | 22 | @NotNull 23 | @Override 24 | public String[] getNames(Project project, boolean onlyThisModuleChecked) { 25 | String[] names = null; 26 | List itemList; 27 | 28 | // data source 29 | if (onlyThisModuleChecked && myModule != null) { 30 | itemList = RestServiceDataManager.buildRestServiceItemListFrom(project, myModule); 31 | } else { 32 | itemList = RestServiceDataManager.buildRestServiceItemListFrom(project); 33 | } 34 | 35 | navItem = itemList; 36 | 37 | if (itemList != null) { 38 | names = new String[itemList.size()]; 39 | } 40 | 41 | for (int i = 0; i < itemList.size(); i++) { 42 | RestServiceItem requestMappingNavigationItem = itemList.get(i); 43 | names[i] = requestMappingNavigationItem.getName(); 44 | } 45 | 46 | return names; 47 | } 48 | 49 | @NotNull 50 | @Override 51 | public NavigationItem[] getItemsByName(String name, String pattern, Project project, boolean onlyThisModuleChecked) { 52 | NavigationItem[] navigationItems = navItem.stream().filter(item -> item.getName().equals(name)).toArray(NavigationItem[]::new); 53 | return navigationItems; 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/annotations/SpringRequestMethodAnnotation.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.annotations; 2 | 3 | 4 | public enum SpringRequestMethodAnnotation { 5 | 6 | REQUEST_MAPPING("org.springframework.web.bind.annotation.RequestMapping", null), 7 | GET_MAPPING("org.springframework.web.bind.annotation.GetMapping", "GET"), 8 | POST_MAPPING( "org.springframework.web.bind.annotation.PostMapping", "POST"), 9 | PUT_MAPPING( "org.springframework.web.bind.annotation.PutMapping", "PUT"), 10 | DELETE_MAPPING( "org.springframework.web.bind.annotation.DeleteMapping", "DELETE"), 11 | PATCH_MAPPING("org.springframework.web.bind.annotation.PatchMapping", "PATCH"); 12 | 13 | SpringRequestMethodAnnotation(String qualifiedName, String methodName) { 14 | this.qualifiedName = qualifiedName; 15 | this.methodName = methodName; 16 | } 17 | 18 | private String qualifiedName; 19 | private String methodName; 20 | 21 | public String methodName() { 22 | return this.methodName; 23 | } 24 | 25 | public String getQualifiedName() { 26 | return qualifiedName; 27 | } 28 | 29 | public String getShortName() { 30 | return qualifiedName.substring(qualifiedName.lastIndexOf(".")-1); 31 | } 32 | 33 | public static SpringRequestMethodAnnotation getByQualifiedName(String qualifiedName) { 34 | for (SpringRequestMethodAnnotation springRequestAnnotation : SpringRequestMethodAnnotation.values()) { 35 | if (springRequestAnnotation.getQualifiedName().equals(qualifiedName)) { 36 | return springRequestAnnotation; 37 | } 38 | } 39 | return null; 40 | } 41 | 42 | public static SpringRequestMethodAnnotation getByShortName(String requestMapping) { 43 | for (SpringRequestMethodAnnotation springRequestAnnotation : SpringRequestMethodAnnotation.values()) { 44 | if (springRequestAnnotation.getQualifiedName().endsWith(requestMapping)) { 45 | return springRequestAnnotation; 46 | } 47 | } 48 | return null; 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/GenerateQueryParamAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.openapi.ide.CopyPasteManager; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiMethod; 8 | import com.intellij.psi.util.PsiUtil; 9 | import com.zhaow.restful.common.PsiMethodHelper; 10 | import org.jetbrains.kotlin.asJava.LightClassUtilsKt; 11 | import org.jetbrains.kotlin.psi.KtClassOrObject; 12 | import org.jetbrains.kotlin.psi.KtNamedFunction; 13 | 14 | import java.awt.datatransfer.StringSelection; 15 | import java.util.List; 16 | 17 | /** 18 | * 生成查询参数 19 | */ 20 | public class GenerateQueryParamAction extends SpringAnnotatedMethodAction { 21 | 22 | @Override 23 | public void actionPerformed(AnActionEvent e) { 24 | 25 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 26 | PsiUtil.getTopLevelClass(psiElement); 27 | PsiMethod psiMethod = null; 28 | if (psiElement instanceof PsiMethod) { 29 | psiMethod = (PsiMethod) psiElement; 30 | } 31 | 32 | if (psiElement instanceof KtNamedFunction) { 33 | KtNamedFunction ktNamedFunction = (KtNamedFunction) psiElement; 34 | PsiElement parentPsi = psiElement.getParent().getParent(); 35 | if (parentPsi instanceof KtClassOrObject) { 36 | // KtLightClass ktLightClass = LightClassUtilsKt.toLightClass(((KtClassOrObject) parentPsi)); 37 | 38 | List psiMethods = LightClassUtilsKt.toLightMethods(ktNamedFunction); 39 | // String params = PsiMethodHelper.create(psiMethods.get(0)).buildParamString(); 40 | psiMethod = psiMethods.get(0); 41 | // String buildParamString = KtFunctionHelper.create(ktNamedFunction).buildParamString(); 42 | } 43 | } 44 | 45 | if (psiMethod != null) { 46 | String params = PsiMethodHelper.create(psiMethod).buildParamString(); 47 | 48 | CopyPasteManager.getInstance().setContents(new StringSelection(params)); 49 | } 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RestServiceProject.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | 4 | import com.intellij.openapi.module.Module; 5 | import com.zhaow.restful.navigation.action.RestServiceItem; 6 | 7 | import java.util.List; 8 | 9 | public class RestServiceProject { 10 | String port = "8080"; 11 | String appName; 12 | 13 | String moduleName; 14 | Module module; 15 | 16 | String applicationClass; 17 | 18 | List serviceItems; 19 | 20 | public RestServiceProject() { 21 | appName = "demoAppName"; 22 | moduleName = "demoModuleName"; 23 | } 24 | 25 | public RestServiceProject(String moduleName, List serviceItems) { 26 | this.moduleName = moduleName; 27 | port = port; 28 | appName = moduleName; 29 | this.serviceItems = serviceItems; 30 | } 31 | 32 | public RestServiceProject(Module module, List serviceItems) { 33 | this.moduleName = module.getName(); 34 | port = port; 35 | appName = moduleName; 36 | this.serviceItems = serviceItems; 37 | } 38 | 39 | // service list 40 | 41 | public String getPort() { 42 | return port; 43 | } 44 | 45 | public void setPort(String port) { 46 | this.port = port; 47 | } 48 | 49 | public String getAppName() { 50 | return appName; 51 | } 52 | 53 | public void setAppName(String appName) { 54 | this.appName = appName; 55 | } 56 | 57 | public String getModuleName() { 58 | return moduleName; 59 | } 60 | 61 | public void setModuleName(String moduleName) { 62 | this.moduleName = moduleName; 63 | } 64 | 65 | public Module getModule() { 66 | return module; 67 | } 68 | 69 | public void setModule(Module module) { 70 | this.module = module; 71 | } 72 | 73 | public String getApplicationClass() { 74 | return applicationClass; 75 | } 76 | 77 | public void setApplicationClass(String applicationClass) { 78 | this.applicationClass = applicationClass; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | return appName + ":" + port; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/ToolkitIcons.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | 4 | import com.intellij.icons.AllIcons; 5 | import com.intellij.openapi.util.IconLoader; 6 | import com.zhaow.restful.method.HttpMethod; 7 | 8 | import javax.swing.*; 9 | 10 | public class ToolkitIcons { 11 | 12 | public static class METHOD { 13 | public static Icon get(HttpMethod method) { 14 | if (method == null) { 15 | return UNDEFINED; 16 | } 17 | if (method.equals(HttpMethod.GET)) { 18 | return METHOD.GET; 19 | }else if(method.equals(HttpMethod.POST)) { 20 | return METHOD.POST; 21 | } else if (method.equals(HttpMethod.PUT) || method.equals(HttpMethod.PATCH)) { 22 | return METHOD.PUT; 23 | }else if(method.equals(HttpMethod.DELETE)) { 24 | return METHOD.DELETE; 25 | } 26 | return null; 27 | } 28 | 29 | public static Icon GET = IconLoader.getIcon("/icons/method/g.png"); // 16x16 GREEN 30 | // post put patch 31 | public static Icon PUT = IconLoader.getIcon("/icons/method/p2.png"); // 16x16 ORANGE 32 | public static Icon POST = IconLoader.getIcon("/icons/method/p.png"); // 16x16 BLUE 33 | public static Icon PATCH = IconLoader.getIcon("/icons/method/p3.png"); // 16x16 GRAY 34 | public static Icon DELETE = IconLoader.getIcon("/icons/method/d.png"); // 16x16 RED 35 | public static Icon UNDEFINED = IconLoader.getIcon("/icons/method/undefined.png"); // 16x16 GRAY 36 | // OPTIONS HEAD 37 | } 38 | 39 | public static final Icon MODULE = AllIcons.Nodes.ModuleGroup; // 16x16 40 | public static final Icon Refresh = AllIcons.Actions.Refresh; // 16x16 41 | // public static final Icon SERVICE = IconLoader.getIcon("/icons/service.png"); // 16x16 42 | 43 | // public static final Icon SERVICE = IconLoader.getIcon("/icons/s1.png"); // 16x16 44 | // public static final Icon SERVICE = IconLoader.getIcon("/icons/s2.png"); // 16x16 45 | // public static final Icon SERVICE = IconLoader.getIcon("/icons/s3.png"); // 16x16 46 | public static final Icon SERVICE = IconLoader.getIcon("/icons/service.png"); // 16x16 47 | 48 | 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/ChineseUtill.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | public class ChineseUtill { 7 | 8 | private static boolean isChinese(char c) { 9 | Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); 10 | if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS 11 | || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS 12 | || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A 13 | || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION 14 | || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION 15 | || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { 16 | return true; 17 | } 18 | return false; 19 | } 20 | 21 | public static boolean isMessyCode(String strName) { 22 | Pattern p = Pattern.compile("\\s*|\t*|\r*|\n*"); 23 | Matcher m = p.matcher(strName); 24 | String after = m.replaceAll(""); 25 | String temp = after.replaceAll("\\p{P}", ""); 26 | char[] ch = temp.trim().toCharArray(); 27 | float chLength = 0 ; 28 | float count = 0; 29 | for (int i = 0; i < ch.length; i++) { 30 | char c = ch[i]; 31 | if (!Character.isLetterOrDigit(c)) { 32 | if (!isChinese(c)) { 33 | count = count + 1; 34 | } 35 | chLength++; 36 | } 37 | } 38 | float result = count / chLength ; 39 | if (result > 0.4) { 40 | return true; 41 | } else { 42 | return false; 43 | } 44 | } 45 | 46 | 47 | public static String toChinese(Object msg){ 48 | // String tempMsg = TransformUtils.toString(msg) ; 49 | String tempMsg = msg.toString() ; 50 | if(isMessyCode(tempMsg)){ 51 | try { 52 | return new String(tempMsg.getBytes("ISO8859-1"), "UTF-8"); 53 | } catch (Exception e) { 54 | } 55 | } 56 | return tempMsg ; 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/Parameter.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method; 2 | 3 | /** 4 | * 方法参数 5 | */ 6 | public class Parameter { // MethodParameter 7 | 8 | private String paramType; 9 | private String paramName; 10 | private String defaultValue = null; 11 | private boolean required = false; 12 | private boolean requestBodyFound = false; 13 | 14 | public Parameter() { } 15 | 16 | public Parameter(String paramType, String paramName) { 17 | this.paramType = paramType; 18 | this.paramName = paramName; 19 | } 20 | 21 | public Parameter(String paramType, String paramName, String defaultValue) { 22 | this.paramType = paramType; 23 | this.paramName = paramName; 24 | this.defaultValue = defaultValue; 25 | } 26 | 27 | /* public Parameter required() { 28 | this.required = true; 29 | return this; 30 | } 31 | */ 32 | public String getParamType() { 33 | return paramType; 34 | } 35 | 36 | 37 | 38 | public void setParamType(String paramType) { 39 | this.paramType = paramType; 40 | } 41 | 42 | public String getParamName() { 43 | return paramName; 44 | } 45 | 46 | public void setParamName(String paramName) { 47 | this.paramName = paramName; 48 | } 49 | 50 | public String getDefaultValue() { 51 | return defaultValue; 52 | } 53 | 54 | public void setDefaultValue(String defaultValue) { 55 | this.defaultValue = defaultValue; 56 | } 57 | 58 | public boolean isRequired() { 59 | return required; 60 | } 61 | 62 | public Parameter setRequired(boolean required) { 63 | this.required = required; 64 | return this; 65 | } 66 | 67 | public boolean isRequestBodyFound() { 68 | return requestBodyFound; 69 | } 70 | 71 | public void setRequestBodyFound(boolean requestBodyFound) { 72 | this.requestBodyFound = requestBodyFound; 73 | } 74 | 75 | public Parameter requestBodyFound(boolean requestBodyFound) { 76 | this.requestBodyFound = requestBodyFound; 77 | return this; 78 | } 79 | 80 | public String getShortTypeName() { 81 | //todo : List 82 | 83 | String shortName = paramType.substring(paramType.lastIndexOf(".") + 1, paramType.length()); 84 | return shortName; 85 | } 86 | 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/helper/JavaxrsAnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.helper; 2 | 3 | import com.intellij.psi.PsiAnnotation; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiMethod; 6 | import com.zhaow.restful.annotations.JaxrsHttpMethodAnnotation; 7 | import com.zhaow.restful.annotations.JaxrsPathAnnotation; 8 | import com.zhaow.restful.common.PsiAnnotationHelper; 9 | import com.zhaow.restful.method.RequestPath; 10 | 11 | import java.util.ArrayList; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | /** 16 | * @author aborn 17 | * @date 2020/06/15 12:03 PM 18 | */ 19 | public class JavaxrsAnnotationHelper implements AnnotationHelper { 20 | 21 | @Override 22 | public String getClassUriPath(PsiClass psiClass) { 23 | PsiAnnotation annotation = psiClass.getModifierList().findAnnotation(JaxrsPathAnnotation.PATH.getQualifiedName()); 24 | String path = PsiAnnotationHelper.getAnnotationAttributeValue(annotation, "value"); 25 | return path != null ? path : ""; 26 | } 27 | 28 | @Override 29 | public RequestPath[] getRequestPaths(PsiMethod psiMethod) { 30 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 31 | if (annotations == null) { 32 | return null; 33 | } 34 | 35 | List list = new ArrayList<>(); 36 | 37 | PsiAnnotation wsPathAnnotation = psiMethod.getModifierList().findAnnotation(JaxrsPathAnnotation.PATH.getQualifiedName()); 38 | String path = wsPathAnnotation == null ? psiMethod.getName() : getWsPathValue(wsPathAnnotation); 39 | JaxrsHttpMethodAnnotation[] jaxrsHttpMethodAnnotations = JaxrsHttpMethodAnnotation.values(); 40 | 41 | Arrays.stream(annotations).forEach(a -> Arrays.stream(jaxrsHttpMethodAnnotations).forEach(methodAnnotation -> { 42 | if (a.getQualifiedName().equals(methodAnnotation.getQualifiedName())) { 43 | list.add(new RequestPath(path, methodAnnotation.getShortName())); 44 | } 45 | })); 46 | 47 | return list.toArray(new RequestPath[list.size()]); 48 | } 49 | 50 | private String getWsPathValue(PsiAnnotation annotation) { 51 | String value = PsiAnnotationHelper.getAnnotationAttributeValue(annotation, "value"); 52 | 53 | return value != null ? value : ""; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/GenerateQueryParamJsonAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.openapi.ide.CopyPasteManager; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiMethod; 8 | import com.zhaow.restful.common.PsiMethodHelper; 9 | import com.zhaow.restful.method.Parameter; 10 | import org.jetbrains.kotlin.asJava.LightClassUtilsKt; 11 | import org.jetbrains.kotlin.psi.KtClassOrObject; 12 | import org.jetbrains.kotlin.psi.KtNamedFunction; 13 | 14 | import java.awt.datatransfer.StringSelection; 15 | import java.util.List; 16 | 17 | /** 18 | * 生成Request Body JSON 字符串 19 | */ 20 | public class GenerateQueryParamJsonAction extends SpringAnnotatedMethodAction { 21 | 22 | @Override 23 | public void actionPerformed(AnActionEvent e) { 24 | 25 | // @RequestBody entity 生成 json 26 | 27 | PsiMethod psiMethod = null; 28 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 29 | if (psiElement instanceof PsiMethod) { 30 | psiMethod = (PsiMethod) psiElement; 31 | } 32 | 33 | if (psiElement instanceof KtNamedFunction) { 34 | KtNamedFunction ktNamedFunction = (KtNamedFunction) psiElement; 35 | PsiElement parentPsi = psiElement.getParent().getParent(); 36 | if (parentPsi instanceof KtClassOrObject) { 37 | List psiMethods = LightClassUtilsKt.toLightMethods(ktNamedFunction); 38 | psiMethod = psiMethods.get(0); 39 | } 40 | } 41 | 42 | PsiMethodHelper psiMethodHelper = PsiMethodHelper.create(psiMethod); 43 | List parameterList = psiMethodHelper.getParameterList(); 44 | //JavaShortClassNameIndex.getInstance().get("Product",myProject(e), GlobalSearchScope.projectScope(myProject(e))) 45 | for (Parameter parameter : parameterList) { 46 | if (parameter.isRequestBodyFound()) { 47 | String queryJson = psiMethodHelper.buildRequestBodyJson(parameter); 48 | 49 | CopyPasteManager.getInstance().setContents(new StringSelection(queryJson)); 50 | 51 | break; 52 | } 53 | } 54 | } 55 | 56 | @Override 57 | public boolean displayTextInToolbar() { 58 | return true; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/GenerateFullUrlAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.ide.CopyPasteManager; 5 | import com.intellij.openapi.module.Module; 6 | import com.intellij.psi.PsiElement; 7 | import com.intellij.psi.PsiMethod; 8 | import com.zhaow.restful.common.PsiMethodHelper; 9 | import org.jetbrains.kotlin.asJava.LightClassUtilsKt; 10 | import org.jetbrains.kotlin.psi.KtClassOrObject; 11 | import org.jetbrains.kotlin.psi.KtNamedFunction; 12 | 13 | import java.awt.datatransfer.StringSelection; 14 | import java.util.List; 15 | 16 | import static com.intellij.openapi.actionSystem.CommonDataKeys.PSI_ELEMENT; 17 | 18 | /** 19 | * 生成并复制restful url 20 | * tood: 没考虑RequestMapping 多个值的情况 21 | */ 22 | public class 23 | GenerateFullUrlAction extends SpringAnnotatedMethodAction { 24 | 25 | @Override 26 | public void actionPerformed(AnActionEvent e) { 27 | 28 | Module module = myModule(e); 29 | PsiElement psiElement = e.getData(PSI_ELEMENT); 30 | if (psiElement instanceof PsiMethod) { 31 | PsiMethod psiMethod = (PsiMethod) psiElement; 32 | 33 | ModuleHelper moduleHelper = ModuleHelper.create(module); 34 | 35 | // String url = moduleHelper.buildFullUrlWithParams(psiMethod); 36 | 37 | String url = PsiMethodHelper.create(psiMethod).withModule(module).buildFullUrlWithParams(); 38 | 39 | CopyPasteManager.getInstance().setContents(new StringSelection(url)); 40 | } 41 | 42 | if (psiElement instanceof KtNamedFunction) { 43 | KtNamedFunction ktNamedFunction = (KtNamedFunction) psiElement; 44 | PsiElement parentPsi = psiElement.getParent().getParent(); 45 | if (parentPsi instanceof KtClassOrObject) { 46 | // KtLightClass ktLightClass = LightClassUtilsKt.toLightClass(((KtClassOrObject) parentPsi)); 47 | 48 | List psiMethods = LightClassUtilsKt.toLightMethods(ktNamedFunction); 49 | PsiMethod psiMethod = psiMethods.get(0); 50 | ModuleHelper moduleHelper = ModuleHelper.create(module); 51 | 52 | String url = PsiMethodHelper.create(psiMethod).withModule(module).buildFullUrlWithParams(); 53 | 54 | CopyPasteManager.getInstance().setContents(new StringSelection(url)); 55 | 56 | } 57 | 58 | } 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/highlight/JTextAreaHighlight.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.highlight; 2 | 3 | import javax.swing.*; 4 | import javax.swing.text.BadLocationException; 5 | import javax.swing.text.DefaultHighlighter; 6 | import javax.swing.text.Highlighter; 7 | import java.awt.*; 8 | 9 | /** 10 | * 文本高亮 11 | */ 12 | public class JTextAreaHighlight { 13 | 14 | /* 高亮 */ 15 | public static void highlightTextAreaData(JTextArea jTextArea) { 16 | 17 | 18 | Highlighter highLighter = jTextArea.getHighlighter(); 19 | DefaultHighlighter.DefaultHighlightPainter highlightPainter = new DefaultHighlighter.DefaultHighlightPainter(Color.DARK_GRAY); 20 | highLighter.removeAllHighlights(); 21 | String text = jTextArea.getText().trim(); 22 | //TODO: isKeyValueFormat 高亮param? 高亮 : 高亮value 23 | 24 | //TODO :isJson 高亮 value ? 25 | if (text.startsWith("[") || text.startsWith("{")) { 26 | return; 27 | } 28 | 29 | int start=0; 30 | String[] lines = text.split("\n"); 31 | for (String line : lines) { 32 | // String[] split = line.split(":"); 33 | int index = line.indexOf(":"); 34 | if (index < 0) { 35 | continue; 36 | } 37 | 38 | start += index; 39 | int end = start + 1; 40 | try { 41 | 42 | highLighter.addHighlight(start, end, highlightPainter); 43 | start += line.substring(index).length()+1; 44 | 45 | } catch (BadLocationException e) { 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | 51 | //高亮 param key 52 | /* int start=0; 53 | String[] lines = text.split("\n"); 54 | for (String line : lines) { 55 | String[] split = line.split(":"); 56 | int end = start + split[0].length(); 57 | try { 58 | 59 | highLighter.addHighlight(start, end, highlightPainter); 60 | start += line.length()+1; 61 | 62 | } catch (BadLocationException e) { 63 | e.printStackTrace(); 64 | } 65 | }*/ 66 | 67 | /* 68 | String keyWord = "demo"; 69 | int pos = 0; 70 | while ((pos = text.indexOf(keyWord, pos)) >= 0) { 71 | try { 72 | highLighter.addHighlight(pos, pos + keyWord.length(), highlightPainter); 73 | pos += keyWord.length(); 74 | } catch (BadLocationException e) { 75 | e.printStackTrace(); 76 | } 77 | } 78 | */ 79 | 80 | 81 | 82 | 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RestServiceProjectsManager.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2017 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zhaow.restful.navigator; 17 | 18 | import com.github.aborn.wdt.core.RestServiceDataManager; 19 | import com.intellij.openapi.Disposable; 20 | import com.intellij.openapi.actionSystem.AnAction; 21 | import com.intellij.openapi.actionSystem.AnActionEvent; 22 | import com.intellij.openapi.components.PersistentStateComponent; 23 | import com.intellij.openapi.components.ProjectComponent; 24 | import com.intellij.openapi.components.State; 25 | import com.intellij.openapi.project.DumbService; 26 | import com.intellij.openapi.project.Project; 27 | import org.jetbrains.annotations.Nullable; 28 | 29 | import java.util.List; 30 | 31 | @State(name = "RestServiceProjectsManager") 32 | public class RestServiceProjectsManager implements PersistentStateComponent, Disposable, ProjectComponent { 33 | protected final Project myProject; 34 | private AnAction anAction; 35 | private RestServicesNavigatorState myState = new RestServicesNavigatorState(); 36 | 37 | public static RestServiceProjectsManager getInstance(Project p) { 38 | return p.getComponent(RestServiceProjectsManager.class); 39 | } 40 | 41 | public RestServiceProjectsManager(Project project) { 42 | myProject = project; 43 | // System.out.println("RestServiceProjectsManager"); 44 | } 45 | 46 | 47 | @Override 48 | public void dispose() { 49 | 50 | } 51 | 52 | @Nullable 53 | @Override 54 | public RestServicesNavigatorState getState() { 55 | return null; 56 | } 57 | 58 | @Override 59 | public void loadState(RestServicesNavigatorState state) { 60 | 61 | } 62 | 63 | public List getServiceProjects(AnActionEvent anActionEvent) { 64 | return DumbService.getInstance(myProject).runReadActionInSmartMode(() -> 65 | RestServiceDataManager.buildRestServiceData(myProject) 66 | ); 67 | } 68 | 69 | 70 | public void forceUpdateAllProjects(AnAction anAction) { 71 | this.anAction = anAction; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/resolver/JavaxrsResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.resolver; 2 | 3 | import com.github.aborn.wdt.core.helper.JavaxrsAnnotationHelper; 4 | import com.intellij.openapi.module.Module; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.*; 7 | import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex; 8 | import com.intellij.psi.search.GlobalSearchScope; 9 | import com.zhaow.restful.annotations.JaxrsPathAnnotation; 10 | import com.zhaow.restful.method.RequestPath; 11 | import com.zhaow.restful.navigation.action.RestServiceItem; 12 | import org.apache.commons.compress.utils.Lists; 13 | 14 | import java.util.Collection; 15 | import java.util.List; 16 | 17 | /** 18 | * @author aborn 19 | * @date 2020/06/15 11:44 AM 20 | */ 21 | public class JavaxrsResolver extends BaseResolver { 22 | 23 | public JavaxrsResolver() { 24 | annotationHelper = new JavaxrsAnnotationHelper(); 25 | } 26 | 27 | @Override 28 | public List getRestServiceItemList(Project project) { 29 | Collection psiAnnotations = JavaAnnotationIndex.getInstance().get(JaxrsPathAnnotation.PATH.getShortName(), project, GlobalSearchScope.projectScope(project)); 30 | return build(psiAnnotations, null); 31 | } 32 | 33 | @Override 34 | public List getRestServiceItemList(Project project, Module module) { 35 | Collection psiAnnotations = JavaAnnotationIndex.getInstance().get(JaxrsPathAnnotation.PATH.getShortName(), project, GlobalSearchScope.moduleScope(module)); 36 | return build(psiAnnotations, module); 37 | } 38 | 39 | private List build(Collection psiAnnotations, Module module) { 40 | List itemList = Lists.newArrayList(); 41 | psiAnnotations.forEach(psiAnnotation -> { 42 | PsiModifierList psiModifierList = (PsiModifierList) psiAnnotation.getParent(); 43 | PsiElement psiElement = psiModifierList.getParent(); 44 | 45 | if (!(psiElement instanceof PsiClass)) { 46 | return; 47 | } 48 | 49 | PsiClass psiClass = (PsiClass) psiElement; 50 | PsiMethod[] psiMethods = psiClass.getMethods(); 51 | 52 | String classUriPath = annotationHelper.getClassUriPath(psiClass); 53 | for (PsiMethod psiMethod : psiMethods) { 54 | RequestPath[] methodUriPaths = annotationHelper.getRequestPaths(psiMethod); 55 | 56 | for (RequestPath methodUriPath : methodUriPaths) { 57 | RestServiceItem item = buildRestServiceItem(psiMethod, classUriPath, methodUriPath); 58 | if (module != null) { 59 | item.setModule(module); 60 | } 61 | itemList.add(item); 62 | } 63 | } 64 | 65 | }); 66 | 67 | return itemList; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/RestServiceDataManager.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core; 2 | 3 | import com.github.aborn.wdt.core.resolver.IResolver; 4 | import com.github.aborn.wdt.core.resolver.JavaxrsResolver; 5 | import com.github.aborn.wdt.core.resolver.SpringResolver; 6 | import com.intellij.openapi.diagnostic.Logger; 7 | import com.intellij.openapi.module.Module; 8 | import com.intellij.openapi.module.ModuleManager; 9 | import com.intellij.openapi.project.Project; 10 | import com.zhaow.restful.navigation.action.RestServiceItem; 11 | import com.zhaow.restful.navigator.RestServiceProject; 12 | import org.apache.commons.compress.utils.Lists; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * @author aborn 18 | * @date 2020/06/15 11:35 AM 19 | */ 20 | public class RestServiceDataManager { 21 | 22 | public static final Logger LOG = Logger.getInstance(RestServiceDataManager.class); 23 | 24 | public static List buildRestServiceData(Project project) { 25 | List serviceProjectList = Lists.newArrayList(); 26 | Module[] modules = ModuleManager.getInstance(project).getModules(); 27 | 28 | if (modules.length > 0) { 29 | for (Module module : modules) { 30 | List restServices = buildRestServiceItemListFrom(project, module); 31 | if (restServices.size() > 0) { 32 | serviceProjectList.add(new RestServiceProject(module.getName() + "(" + restServices.size() +")", restServices)); 33 | } 34 | } 35 | } else { 36 | List restServices = buildRestServiceItemListFrom(project); 37 | if (restServices.size() > 0) { 38 | serviceProjectList.add(new RestServiceProject(project.getName() + "(" + restServices.size() +")", restServices)); 39 | } 40 | LOG.info("Not find any modules in project " + project.getName() + "."); 41 | } 42 | 43 | return serviceProjectList; 44 | } 45 | 46 | /** 47 | * from module 48 | * @param project 49 | * @param module 50 | * @return 51 | */ 52 | public static List buildRestServiceItemListFrom(Project project, Module module) { 53 | IResolver[] resolvers = {new SpringResolver(), new JavaxrsResolver()}; 54 | List restServices = Lists.newArrayList(); 55 | for (IResolver resolver : resolvers) { 56 | restServices.addAll(resolver.getRestServiceItemList(project, module)); 57 | } 58 | return restServices; 59 | } 60 | 61 | /** 62 | * from project 63 | * @param project 64 | * @return 65 | */ 66 | public static List buildRestServiceItemListFrom(Project project) { 67 | IResolver[] resolvers = {new SpringResolver(), new JavaxrsResolver()}; 68 | List restServices = Lists.newArrayList(); 69 | for (IResolver resolver : resolvers) { 70 | restServices.addAll(resolver.getRestServiceItemList(project)); 71 | } 72 | return restServices; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/helper/SpringAnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.helper; 2 | 3 | import com.intellij.psi.PsiAnnotation; 4 | import com.intellij.psi.PsiClass; 5 | import com.intellij.psi.PsiMethod; 6 | import com.zhaow.restful.annotations.SpringRequestMethodAnnotation; 7 | import com.zhaow.restful.common.PsiAnnotationHelper; 8 | import com.zhaow.restful.method.RequestPath; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * @author aborn 15 | * @date 2020/06/15 1:54 PM 16 | */ 17 | public class SpringAnnotationHelper implements AnnotationHelper { 18 | 19 | @Override 20 | public String getClassUriPath(PsiClass psiClass) { 21 | return null; 22 | } 23 | 24 | @Override 25 | public RequestPath[] getRequestPaths(PsiMethod psiMethod) { 26 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 27 | 28 | if (annotations == null) { 29 | return null; 30 | } 31 | List list = new ArrayList<>(); 32 | 33 | for (PsiAnnotation annotation : annotations) { 34 | for (SpringRequestMethodAnnotation mappingAnnotation : SpringRequestMethodAnnotation.values()) { 35 | // for (PathMappingAnnotation mappingAnnotation : PathMappingAnnotation.allPathMappingAnnotations) { 36 | if (mappingAnnotation.getQualifiedName().endsWith(annotation.getQualifiedName())) { 37 | 38 | // String defaultValue = psiMethod.getName(); 39 | String defaultValue = "/"; 40 | List requestMappings = getRequestMappings(annotation, defaultValue); 41 | if (requestMappings.size() > 0) { 42 | list.addAll(requestMappings); 43 | } 44 | } 45 | } 46 | } 47 | 48 | return list.toArray(new RequestPath[list.size()]); 49 | } 50 | 51 | private static List getRequestMappings(PsiAnnotation annotation, String defaultValue) { 52 | List mappingList = new ArrayList<>(); 53 | 54 | List methodList = PsiAnnotationHelper.getAnnotationAttributeValues(annotation, "method"); 55 | 56 | List pathList = PsiAnnotationHelper.getAnnotationAttributeValues(annotation, "value"); 57 | if (pathList.size() == 0) { 58 | pathList = PsiAnnotationHelper.getAnnotationAttributeValues(annotation, "path"); 59 | } 60 | 61 | // 没有设置 value,默认方法名 62 | if (pathList.size() == 0) { 63 | pathList.add(defaultValue); 64 | } 65 | 66 | // todo: 处理没有设置 value 或 path 的 RequestMapping 67 | 68 | // List finalPathList = pathList; 69 | // methodList.forEach(method-> finalPathList.forEach(path->mappingList.add(new RequestMapping(path,method)))); 70 | 71 | if (methodList.size() > 0) { 72 | for (String method : methodList) { 73 | for (String path : pathList) { 74 | mappingList.add(new RequestPath(path, method)); 75 | } 76 | } 77 | } else { 78 | for (String path : pathList) { 79 | mappingList.add(new RequestPath(path, null)); 80 | } 81 | } 82 | 83 | return mappingList; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/SpringAnnotatedMethodAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.psi.*; 6 | import com.zhaow.restful.action.AbstractBaseAction; 7 | import com.zhaow.restful.annotations.SpringControllerAnnotation; 8 | import com.zhaow.restful.annotations.SpringRequestMethodAnnotation; 9 | import org.jetbrains.kotlin.asJava.LightClassUtilsKt; 10 | import org.jetbrains.kotlin.asJava.classes.KtLightClass; 11 | import org.jetbrains.kotlin.psi.KtClassOrObject; 12 | import org.jetbrains.kotlin.psi.KtNamedFunction; 13 | 14 | import java.util.Arrays; 15 | import java.util.List; 16 | 17 | /** 18 | * Restful method (restful 方法添加方法 ) 19 | */ 20 | public abstract class SpringAnnotatedMethodAction extends AbstractBaseAction { 21 | 22 | /** 23 | * spring rest 方法被选中才触发 24 | * @param e 25 | */ 26 | @Override 27 | public void update(AnActionEvent e) { 28 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 29 | 30 | boolean visible = false; 31 | 32 | if(psiElement instanceof PsiMethod){ 33 | PsiMethod psiMethod = (PsiMethod) psiElement; 34 | // rest method 或标注了RestController 注解 35 | visible = (isRestController(psiMethod.getContainingClass()) || isRestfulMethod(psiMethod) ); 36 | } 37 | if (psiElement instanceof KtNamedFunction) { 38 | KtNamedFunction ktNamedFunction = (KtNamedFunction) psiElement; 39 | PsiElement parentPsi = psiElement.getParent().getParent(); 40 | if (parentPsi instanceof KtClassOrObject) { 41 | KtLightClass ktLightClass = LightClassUtilsKt.toLightClass(((KtClassOrObject) parentPsi)); 42 | 43 | List psiMethods = LightClassUtilsKt.toLightMethods(ktNamedFunction); 44 | 45 | visible = (isRestController(ktLightClass) || isRestfulMethod(psiMethods.get(0)) ); 46 | 47 | } 48 | } 49 | 50 | setActionPresentationVisible(e, visible); 51 | } 52 | 53 | //包含 "RestController" "Controller" 54 | private boolean isRestController(PsiClass containingClass) { 55 | PsiModifierList modifierList = containingClass.getModifierList(); 56 | 57 | /*return modifierList.findAnnotation(SpringControllerAnnotation.REST_CONTROLLER.getQualifiedName()) != null || 58 | modifierList.findAnnotation(SpringControllerAnnotation.CONTROLLER.getQualifiedName()) != null ;*/ 59 | 60 | return modifierList.findAnnotation(SpringControllerAnnotation.REST_CONTROLLER.getQualifiedName()) != null || 61 | modifierList.findAnnotation(SpringControllerAnnotation.CONTROLLER.getQualifiedName()) != null /*|| 62 | modifierList.findAnnotation(JaxrsRequestAnnotation.PATH.getQualifiedName()) != null*/ ; 63 | } 64 | 65 | private boolean isRestfulMethod(PsiMethod psiMethod) { 66 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 67 | 68 | for (PsiAnnotation annotation : annotations) { 69 | boolean match = Arrays.stream(SpringRequestMethodAnnotation.values()).map(sra -> sra.getQualifiedName()).anyMatch(name -> name.equals(annotation.getQualifiedName())); 70 | if(match) return match; 71 | } 72 | 73 | return false; 74 | } 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /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%" == "0" goto init 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 init 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 | :init 68 | @rem Get command-line arguments, handling Windows variants 69 | 70 | if not "%OS%" == "Windows_NT" goto win9xME_args 71 | 72 | :win9xME_args 73 | @rem Slurp the command line arguments. 74 | set CMD_LINE_ARGS= 75 | set _SKIP=2 76 | 77 | :win9xME_args_slurp 78 | if "x%~1" == "x" goto execute 79 | 80 | set CMD_LINE_ARGS=%* 81 | 82 | :execute 83 | @rem Setup the command line 84 | 85 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 86 | 87 | 88 | @rem Execute Gradle 89 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 90 | 91 | :end 92 | @rem End local scope for the variables with windows NT shell 93 | if "%ERRORLEVEL%"=="0" goto mainEnd 94 | 95 | :fail 96 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 97 | rem the _cmd.exe /c_ return code! 98 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 99 | exit /b 1 100 | 101 | :mainEnd 102 | if "%OS%"=="Windows_NT" endlocal 103 | 104 | :omega 105 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RestServiceDetail.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 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/jaxrs/JaxrsAnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common.jaxrs; 2 | 3 | 4 | import com.intellij.psi.PsiAnnotation; 5 | import com.intellij.psi.PsiClass; 6 | import com.intellij.psi.PsiMethod; 7 | import com.zhaow.restful.annotations.JaxrsHttpMethodAnnotation; 8 | import com.zhaow.restful.annotations.JaxrsPathAnnotation; 9 | import com.zhaow.restful.common.PsiAnnotationHelper; 10 | import com.zhaow.restful.method.RequestPath; 11 | import org.apache.commons.lang.StringUtils; 12 | 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | 18 | public class JaxrsAnnotationHelper { 19 | 20 | private static String getWsPathValue(PsiAnnotation annotation) { 21 | String value = PsiAnnotationHelper.getAnnotationAttributeValue(annotation, "value"); 22 | 23 | return value != null ? value : ""; 24 | } 25 | 26 | /** 27 | * 过滤所有注解 28 | * @param psiMethod 29 | * @return 30 | */ 31 | public static RequestPath[] getRequestPaths(PsiMethod psiMethod) { 32 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 33 | if(annotations == null) return null; 34 | List list = new ArrayList<>(); 35 | 36 | PsiAnnotation wsPathAnnotation = psiMethod.getModifierList().findAnnotation(JaxrsPathAnnotation.PATH.getQualifiedName()); 37 | String path = wsPathAnnotation == null ? psiMethod.getName() : getWsPathValue(wsPathAnnotation); 38 | 39 | JaxrsHttpMethodAnnotation[] jaxrsHttpMethodAnnotations = JaxrsHttpMethodAnnotation.values(); 40 | 41 | /*for (PsiAnnotation annotation : annotations) { 42 | for (JaxrsHttpMethodAnnotation methodAnnotation : jaxrsHttpMethodAnnotations) { 43 | if (annotation.getQualifiedName().equals(methodAnnotation.getQualifiedName())) { 44 | list.add(new RequestPath(path, methodAnnotation.getShortName())); 45 | } 46 | } 47 | }*/ 48 | 49 | Arrays.stream(annotations).forEach(a-> Arrays.stream(jaxrsHttpMethodAnnotations).forEach(methodAnnotation-> { 50 | if (a.getQualifiedName().equals(methodAnnotation.getQualifiedName())) { 51 | list.add(new RequestPath(path, methodAnnotation.getShortName())); 52 | } 53 | })); 54 | 55 | return list.toArray(new RequestPath[list.size()]); 56 | } 57 | 58 | 59 | public static String getClassUriPath(PsiClass psiClass) { 60 | PsiAnnotation annotation = psiClass.getModifierList().findAnnotation(JaxrsPathAnnotation.PATH.getQualifiedName()); 61 | 62 | String path = PsiAnnotationHelper.getAnnotationAttributeValue(annotation, "value"); 63 | 64 | return path != null ? path : ""; 65 | } 66 | 67 | 68 | public static String getMethodUriPath(PsiMethod psiMethod) { 69 | JaxrsHttpMethodAnnotation requestAnnotation = null; 70 | 71 | List httpMethodAnnotations = Arrays.stream(JaxrsHttpMethodAnnotation.values()).filter(annotation -> 72 | psiMethod.getModifierList().findAnnotation(annotation.getQualifiedName()) != null 73 | ).collect(Collectors.toList()); 74 | 75 | /* if (httpMethodAnnotations.size() == 0) { 76 | requestAnnotation = null; 77 | }*/ 78 | 79 | if (httpMethodAnnotations.size() > 0) { 80 | requestAnnotation = httpMethodAnnotations.get(0); 81 | } 82 | 83 | String mappingPath; 84 | if(requestAnnotation != null){ 85 | PsiAnnotation annotation = psiMethod.getModifierList().findAnnotation(JaxrsPathAnnotation.PATH.getQualifiedName()); 86 | mappingPath = getWsPathValue(annotation); 87 | }else { 88 | String methodName = psiMethod.getName(); 89 | mappingPath = StringUtils.uncapitalize(methodName); 90 | } 91 | 92 | return mappingPath; 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/RestServiceChooseByNamePopup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2000-2017 JetBrains s.r.o. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.zhaow.restful.navigation.action; 17 | 18 | import com.intellij.ide.util.gotoByName.ChooseByNameItemProvider; 19 | import com.intellij.ide.util.gotoByName.ChooseByNameModel; 20 | import com.intellij.ide.util.gotoByName.ChooseByNamePopup; 21 | import com.intellij.openapi.project.Project; 22 | import com.intellij.openapi.util.Key; 23 | import com.intellij.openapi.util.text.StringUtil; 24 | import com.zhaow.utils.ToolkitUtil; 25 | import org.jetbrains.annotations.NotNull; 26 | import org.jetbrains.annotations.Nullable; 27 | 28 | public class RestServiceChooseByNamePopup extends ChooseByNamePopup { 29 | public static final Key CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY = new Key<>("ChooseByNamePopup"); 30 | 31 | protected RestServiceChooseByNamePopup(@Nullable Project project, @NotNull ChooseByNameModel model, @NotNull ChooseByNameItemProvider provider, @Nullable ChooseByNamePopup oldPopup, @Nullable String predefinedText, boolean mayRequestOpenInCurrentWindow, int initialIndex) { 32 | super(project, model, provider, oldPopup, predefinedText, mayRequestOpenInCurrentWindow, initialIndex); 33 | } 34 | 35 | public static RestServiceChooseByNamePopup createPopup(final Project project, 36 | @NotNull final ChooseByNameModel model, 37 | @NotNull ChooseByNameItemProvider provider, 38 | @Nullable final String predefinedText, 39 | boolean mayRequestOpenInCurrentWindow, 40 | final int initialIndex) { 41 | if (!StringUtil.isEmptyOrSpaces(predefinedText)) { 42 | return new RestServiceChooseByNamePopup(project, model, provider, null, predefinedText, mayRequestOpenInCurrentWindow, initialIndex); 43 | } 44 | 45 | final RestServiceChooseByNamePopup oldPopup = project == null ? null : project.getUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY); 46 | if (oldPopup != null) { 47 | oldPopup.close(false); 48 | } 49 | RestServiceChooseByNamePopup newPopup = new RestServiceChooseByNamePopup(project, model, provider, oldPopup, predefinedText, mayRequestOpenInCurrentWindow, initialIndex); 50 | 51 | if (project != null) { 52 | project.putUserData(CHOOSE_BY_NAME_POPUP_IN_PROJECT_KEY, newPopup); 53 | } 54 | return newPopup; 55 | } 56 | 57 | @Override 58 | public String transformPattern(String pattern) { 59 | final ChooseByNameModel model = getModel(); 60 | return getTransformedPattern(pattern, model); 61 | } 62 | 63 | //TODO: resolve PathVariable 64 | public static String getTransformedPattern(String pattern, ChooseByNameModel model) { 65 | if (!(model instanceof GotoRequestMappingModel)) { 66 | return pattern; 67 | } 68 | 69 | pattern = ToolkitUtil.removeRedundancyMarkup(pattern); 70 | return pattern; 71 | } 72 | 73 | 74 | @Nullable 75 | public String getMemberPattern() { 76 | final String enteredText = getTrimmedText(); 77 | final int index = enteredText.lastIndexOf('#'); 78 | if (index == -1) { 79 | return null; 80 | } 81 | 82 | String name = enteredText.substring(index + 1).trim(); 83 | return StringUtil.isEmptyOrSpaces(name) ? null : name; 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/main/java/com/github/aborn/wdt/core/resolver/SpringResolver.java: -------------------------------------------------------------------------------- 1 | package com.github.aborn.wdt.core.resolver; 2 | 3 | import com.github.aborn.wdt.core.helper.SpringAnnotationHelper; 4 | import com.intellij.openapi.module.Module; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.*; 7 | import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex; 8 | import com.intellij.psi.search.GlobalSearchScope; 9 | import com.zhaow.restful.annotations.SpringControllerAnnotation; 10 | import com.zhaow.restful.common.spring.RequestMappingAnnotationHelper; 11 | import com.zhaow.restful.method.RequestPath; 12 | import com.zhaow.restful.navigation.action.RestServiceItem; 13 | import org.apache.commons.compress.utils.Lists; 14 | 15 | import java.util.ArrayList; 16 | import java.util.Collection; 17 | import java.util.List; 18 | 19 | /** 20 | * @author aborn 21 | * @date 2020/06/15 11:50 AM 22 | */ 23 | public class SpringResolver extends BaseResolver { 24 | 25 | public SpringResolver() { 26 | annotationHelper = new SpringAnnotationHelper(); 27 | } 28 | 29 | @Override 30 | public List getRestServiceItemList(Project project) { 31 | Collection psiAnnotations = new ArrayList<>(); 32 | for (SpringControllerAnnotation annotation : SpringControllerAnnotation.values()) { 33 | psiAnnotations.addAll(JavaAnnotationIndex.getInstance().get(annotation.getShortName(), project, GlobalSearchScope.projectScope(project))); 34 | } 35 | return build(psiAnnotations, null); 36 | } 37 | 38 | @Override 39 | public List getRestServiceItemList(Project project, Module module) { 40 | Collection psiAnnotations = new ArrayList<>(); 41 | for (SpringControllerAnnotation annotation : SpringControllerAnnotation.values()) { 42 | psiAnnotations.addAll(JavaAnnotationIndex.getInstance().get(annotation.getShortName(), project, GlobalSearchScope.moduleScope(module))); 43 | } 44 | return build(psiAnnotations, module); 45 | } 46 | 47 | private List build(Collection psiAnnotations, Module module) { 48 | 49 | List itemList = Lists.newArrayList(); 50 | 51 | psiAnnotations.forEach(psiAnnotation -> { 52 | PsiModifierList psiModifierList = (PsiModifierList) psiAnnotation.getParent(); 53 | PsiElement psiElement = psiModifierList.getParent(); 54 | 55 | if (!(psiElement instanceof PsiClass)) { 56 | return; 57 | } 58 | 59 | PsiClass psiClass = (PsiClass) psiElement; 60 | PsiMethod[] psiMethods = psiClass.getMethods(); 61 | 62 | if (psiMethods == null) { 63 | return; 64 | } 65 | 66 | List restServiceItems = getServiceItemList(psiClass, module); 67 | 68 | itemList.addAll(restServiceItems); 69 | 70 | }); 71 | 72 | return itemList; 73 | } 74 | 75 | protected List getServiceItemList(PsiClass psiClass, Module module) { 76 | 77 | PsiMethod[] psiMethods = psiClass.getMethods(); 78 | if (psiMethods == null) { 79 | return new ArrayList<>(); 80 | } 81 | 82 | List itemList = new ArrayList<>(); 83 | List classRequestPaths = RequestMappingAnnotationHelper.getRequestPaths(psiClass); 84 | 85 | for (PsiMethod psiMethod : psiMethods) { 86 | RequestPath[] methodRequestPaths = annotationHelper.getRequestPaths(psiMethod); 87 | 88 | for (RequestPath classRequestPath : classRequestPaths) { 89 | for (RequestPath methodRequestPath : methodRequestPaths) { 90 | String path = classRequestPath.getPath(); 91 | 92 | RestServiceItem item = buildRestServiceItem(psiMethod, path, methodRequestPath); 93 | if (module != null) { 94 | item.setModule(module); 95 | } 96 | itemList.add(item); 97 | } 98 | } 99 | 100 | } 101 | return itemList; 102 | } 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/codegen/SpringBootGenerator.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.codegen; 2 | 3 | import com.intellij.openapi.actionSystem.AnAction; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.actionSystem.DataKeys; 6 | import com.intellij.openapi.actionSystem.PlatformDataKeys; 7 | import com.intellij.openapi.editor.Editor; 8 | import com.intellij.openapi.fileTypes.FileTypes; 9 | import com.intellij.openapi.project.Project; 10 | import com.intellij.openapi.vfs.VirtualFile; 11 | import com.intellij.psi.*; 12 | import com.zhaow.utils.ToolkitUtil; 13 | import org.apache.velocity.VelocityContext; 14 | import org.apache.velocity.app.VelocityEngine; 15 | 16 | import java.io.InputStream; 17 | import java.io.InputStreamReader; 18 | import java.io.StringWriter; 19 | import java.util.HashMap; 20 | import java.util.Map; 21 | import java.util.Properties; 22 | 23 | 24 | public class SpringBootGenerator extends AnAction { 25 | Project project; 26 | 27 | @Override 28 | public void actionPerformed(AnActionEvent e) { 29 | Editor editor = e.getData(PlatformDataKeys.EDITOR); 30 | 31 | // e.getData(PlatformDataKeys.VIRTUAL_FILE) ; 32 | // instanceof VirtualDirectoryImpl file://E:/project/module/src/test 33 | String currentPathName = e.getData(PlatformDataKeys.VIRTUAL_FILE).getName(); 34 | 35 | PsiElement psiElement = e.getData(PlatformDataKeys.PSI_ELEMENT); 36 | 37 | // instanceof PsiJavaDirectoryImpl 38 | // PsiDirectory:E:\project\module\src\test 39 | 40 | // e.getData(PlatformDataKeys.NAVIGATABLE); 同 PSI_ELEMENT 41 | 42 | // e.getData(PlatformDataKeys.SEARCH_INPUT_TEXT) 43 | // e.getData(PlatformDataKeys.e.getData(PlatformDataKeys.SPEED_SEARCH_COMPONENT)) 44 | 45 | if (editor == null) { 46 | return; 47 | } 48 | String content = editor.getDocument().getText(); 49 | 50 | 51 | 52 | 53 | // createPackage(); 54 | // createFile() 55 | 56 | String currentPath = getCurrentPath(e); 57 | /* String basePath = currentPath.replace("contract/" + className + ".java", ""); 58 | String basePackage = getPackageName(basePath); 59 | String modelName = className.substring(0, className.indexOf("Contract"));*/ 60 | 61 | 62 | } 63 | 64 | 65 | public void createFile(String fileName,String content) { 66 | PsiFile psiFile = PsiFileFactory.getInstance(project).createFileFromText(fileName, FileTypes.PLAIN_TEXT, content); 67 | 68 | PsiDirectory directory = PsiManager.getInstance(project).findDirectory(project.getBaseDir()); 69 | PsiFile file = directory.findFile(fileName); 70 | if (file == null) { 71 | ToolkitUtil.runWriteAction(() -> directory.add(psiFile)); 72 | } else { 73 | ToolkitUtil.runWriteAction(() -> { 74 | file.delete(); 75 | directory.add(psiFile); 76 | }); 77 | } 78 | } 79 | 80 | private String genFromTemplate(String templateName, Map dataMap) { 81 | 82 | VelocityContext context = new VelocityContext(); 83 | 84 | // context.put("services", services); 85 | 86 | String path = "template/"; 87 | String templatePath = path + templateName; 88 | InputStream input = getClass().getClassLoader().getResourceAsStream(templatePath); 89 | 90 | VelocityEngine engine = new VelocityEngine(); 91 | Properties props = new Properties(); 92 | props.put("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); 93 | props.put("runtime.log.logsystem.log4j.category", "velocity"); 94 | props.put("runtime.log.logsystem.log4j.logger", "velocity"); 95 | 96 | engine.init(props); 97 | StringWriter writer = new StringWriter(); 98 | engine.evaluate(context, writer, "REST", new InputStreamReader(input)); 99 | 100 | return writer.toString().replace("\n", "").replace("\r", ""); 101 | } 102 | 103 | 104 | // 首先判断要生成的目录和文件和目录是否存在,如果任何一个存在,则退出 105 | 106 | // 创建目录,文件 107 | private void createController(String basePackage, String path, String modelName) { 108 | 109 | createFile(modelName +"Controller" , genFromTemplate("controller",new HashMap<>())) ; 110 | } 111 | 112 | private void refreshProject(AnActionEvent e) { 113 | e.getProject().getBaseDir().refresh(false, true); 114 | } 115 | 116 | private String getCurrentPath(AnActionEvent e) { 117 | VirtualFile currentFile = DataKeys.VIRTUAL_FILE.getData(e.getDataContext()); 118 | if (currentFile != null) { 119 | return currentFile.getPath(); 120 | } 121 | return null; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/spring/StringUtils.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2002-2017 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.zhaow.restful.common.spring; 18 | 19 | import java.util.ArrayList; 20 | import java.util.Collection; 21 | import java.util.List; 22 | import java.util.StringTokenizer; 23 | 24 | /** 25 | * Miscellaneous {@link String} utility methods. 26 | * 27 | *

Mainly for internal use within the framework; consider 28 | * Apache's Commons Lang 29 | * for a more comprehensive suite of {@code String} utilities. 30 | * 31 | *

This class delivers some simple functionality that should really be 32 | * provided by the core Java {@link String} and {@link StringBuilder} 33 | * classes. It also provides easy-to-use methods to convert between 34 | * delimited strings, such as CSV strings, and collections and arrays. 35 | * 36 | * @author Rod Johnson 37 | * @author Juergen Hoeller 38 | * @author Keith Donald 39 | * @author Rob Harrop 40 | * @author Rick Evans 41 | * @author Arjen Poutsma 42 | * @author Sam Brannen 43 | * @author Brian Clozel 44 | * @since 16 April 2001 45 | */ 46 | public abstract class StringUtils { 47 | 48 | /** 49 | * Check that the given {@code CharSequence} is neither {@code null} nor 50 | * of length 0. 51 | *

Note: this method returns {@code true} for a {@code CharSequence} 52 | * that purely consists of whitespace. 53 | *

 54 | 	 * StringUtils.hasLength(null) = false
 55 | 	 * StringUtils.hasLength("") = false
 56 | 	 * StringUtils.hasLength(" ") = true
 57 | 	 * StringUtils.hasLength("Hello") = true
 58 | 	 * 
59 | * @param str the {@code CharSequence} to check (may be {@code null}) 60 | * @return {@code true} if the {@code CharSequence} is not {@code null} and has length 61 | * @see #hasText(String) 62 | */ 63 | public static boolean hasLength(CharSequence str) { 64 | return (str != null && str.length() > 0); 65 | } 66 | 67 | /** 68 | * Copy the given {@code Collection} into a {@code String} array. 69 | *

The {@code Collection} must contain {@code String} elements only. 70 | * @param collection the {@code Collection} to copy 71 | * @return the {@code String} array ({@code null} if the supplied 72 | * {@code Collection} was {@code null}) 73 | */ 74 | public static String[] toStringArray(Collection collection) { 75 | if (collection == null) { 76 | return null; 77 | } 78 | 79 | return collection.toArray(new String[collection.size()]); 80 | } 81 | /** 82 | * Tokenize the given {@code String} into a {@code String} array via a 83 | * {@link StringTokenizer}. 84 | *

The given {@code delimiters} string can consist of any number of 85 | * delimiter characters. Each of those characters can be used to separate 86 | * tokens. A delimiter is always a single character; for multi-character 87 | * delimiters, consider using {@link #delimitedListToStringArray}. 88 | * @param str the {@code String} to tokenize 89 | * @param delimiters the delimiter characters, assembled as a {@code String} 90 | * (each of the characters is individually considered as a delimiter) 91 | * @param trimTokens trim the tokens via {@link String#trim()} 92 | * @param ignoreEmptyTokens omit empty tokens from the result array 93 | * (only applies to tokens that are empty after trimming; StringTokenizer 94 | * will not consider subsequent delimiters as token in the first place). 95 | * @return an array of the tokens ({@code null} if the input {@code String} 96 | * was {@code null}) 97 | * @see StringTokenizer 98 | * @see String#trim() 99 | * @see #delimitedListToStringArray 100 | */ 101 | public static String[] tokenizeToStringArray( 102 | String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { 103 | 104 | if (str == null) { 105 | return null; 106 | } 107 | 108 | StringTokenizer st = new StringTokenizer(str, delimiters); 109 | List tokens = new ArrayList(); 110 | while (st.hasMoreTokens()) { 111 | String token = st.nextToken(); 112 | if (trimTokens) { 113 | token = token.trim(); 114 | } 115 | if (!ignoreEmptyTokens || token.length() > 0) { 116 | tokens.add(token); 117 | } 118 | } 119 | return toStringArray(tokens); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/KtClassHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | import com.intellij.openapi.module.Module; 4 | import com.intellij.openapi.project.Project; 5 | import com.intellij.psi.PsiClass; 6 | import com.intellij.psi.impl.java.stubs.index.JavaShortClassNameIndex; 7 | import com.intellij.psi.search.GlobalSearchScope; 8 | import com.intellij.psi.search.PsiShortNamesCache; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.jetbrains.annotations.Nullable; 11 | import org.jetbrains.kotlin.idea.caches.KotlinShortNamesCache; 12 | import org.jetbrains.kotlin.idea.stubindex.KotlinClassShortNameIndex; 13 | import org.jetbrains.kotlin.psi.KtClass; 14 | import org.jetbrains.kotlin.psi.KtClassOrObject; 15 | 16 | import java.util.Collection; 17 | 18 | // 处理 实体自关联,第二层自关联字段 19 | public class KtClassHelper { 20 | KtClass psiClass; 21 | 22 | private static int autoCorrelationCount=0; //标记实体递归 23 | private int listIterateCount = 0; //标记List递归 24 | private Module myModule; 25 | 26 | protected KtClassHelper(@NotNull KtClass psiClass) { 27 | this.psiClass = psiClass; 28 | } 29 | 30 | @NotNull 31 | protected Project getProject() { 32 | return psiClass.getProject(); 33 | } 34 | 35 | @Nullable 36 | public KtClassOrObject findOnePsiClassByClassName(String className, Project project) { 37 | KtClassOrObject psiClass = null; 38 | 39 | String shortClassName = className.substring(className.lastIndexOf(".") + 1, className.length()); 40 | 41 | PsiClass[] classesByName = KotlinShortNamesCache.getInstance(project).getClassesByName(shortClassName, GlobalSearchScope.allScope(project)); 42 | Collection psiClassCollection = JavaShortClassNameIndex.getInstance().get(shortClassName, project, GlobalSearchScope.projectScope(project)); 43 | Collection ktClassOrObjectss = KotlinClassShortNameIndex.getInstance().get(shortClassName, project, GlobalSearchScope.allScope(project)); 44 | //////////// 45 | 46 | // Collection psiClassCollection = tryDetectPsiClassByShortClassName(project, shortClassName); 47 | Collection ktClassOrObjects = tryDetectPsiClassByShortClassName(project, shortClassName); 48 | if (ktClassOrObjects.size() == 0) { 49 | 50 | return null; 51 | } 52 | if (ktClassOrObjects.size() == 1) { 53 | psiClass = ktClassOrObjects.iterator().next(); 54 | } 55 | psiClass.getPrimaryConstructor().getText(); // (val id: Long, val content: String) 56 | psiClass.getFqName(); // class fullQualifiedName :org.jetbrains.kotlin.demo.Greeting 57 | 58 | if (ktClassOrObjects.size() > 1) { 59 | //找import中对应的class 60 | // psiClass = psiClassCollection.stream().filter(tempKtClass -> tempPsiClass.getQualifiedName().equals(className)).findFirst().get(); 61 | 62 | /*Optional any = psiClassCollection.stream().filter(tempPsiClass -> tempPsiClass.getQualifiedName().equals(className)).findAny(); 63 | 64 | if (any.isPresent()) { 65 | psiClass = any.get(); 66 | }*/ 67 | 68 | for (KtClassOrObject ktClassOrObject : ktClassOrObjects) { 69 | // ktClassOrObject. 70 | } 71 | 72 | } 73 | return psiClass; 74 | } 75 | 76 | 77 | //PsiShortNamesCache : PsiClass:Demo KtLightClassImpl:data class Greeting(val id: Long, val content: String) { 代码体 } 78 | public Collection tryDetectPsiClassByShortClassName(Project project, String shortClassName) { 79 | PsiClass[] psiClasses = PsiShortNamesCache.getInstance(project).getClassesByName(shortClassName, GlobalSearchScope.allScope(project));// 所有的 80 | PsiClass[] classesByName = KotlinShortNamesCache.getInstance(project).getClassesByName(shortClassName, GlobalSearchScope.allScope(project)); 81 | // Collection psiClassCollection = JavaShortClassNameIndex.getInstance().get(shortClassName, project, GlobalSearchScope.projectScope(project)); 82 | Collection ktClassOrObjects = KotlinClassShortNameIndex.getInstance().get(shortClassName, project, GlobalSearchScope.allScope(project)); 83 | // ((KtLightClassImpl) classesByName[0]).getKotlinOrigin() ; classesByName[0] instanceof KtLightClass 84 | for (KtClassOrObject ktClassOrObject : ktClassOrObjects) { 85 | // ktClassOrObject 86 | } 87 | if (ktClassOrObjects.size() > 0) { 88 | return ktClassOrObjects; 89 | } 90 | if(myModule != null) { 91 | ktClassOrObjects = KotlinClassShortNameIndex.getInstance().get(shortClassName, project, GlobalSearchScope.allScope(project)); 92 | } 93 | return ktClassOrObjects; 94 | } 95 | 96 | public static KtClassHelper create(@NotNull KtClass psiClass) { 97 | return new KtClassHelper(psiClass); 98 | } 99 | 100 | 101 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/KtFunctionHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | 4 | import com.intellij.openapi.module.Module; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.psi.PsiMethod; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.jetbrains.kotlin.asJava.LightClassUtilsKt; 9 | import org.jetbrains.kotlin.psi.KtNamedFunction; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | 14 | /** 15 | * KtFunction处理类 16 | */ 17 | public class KtFunctionHelper extends PsiMethodHelper { 18 | KtNamedFunction ktNamedFunction; 19 | Project myProject; 20 | Module myModule; 21 | 22 | private String pathSeparator= "/"; 23 | 24 | public static KtFunctionHelper create(@NotNull KtNamedFunction psiMethod) { 25 | return new KtFunctionHelper(psiMethod); 26 | } 27 | 28 | public KtFunctionHelper withModule(Module module) { 29 | this.myModule = module; 30 | return this; 31 | } 32 | 33 | protected KtFunctionHelper(@NotNull KtNamedFunction ktNamedFunction) { 34 | super(null); 35 | List psiMethods = LightClassUtilsKt.toLightMethods(ktNamedFunction); 36 | PsiMethod psiMethod = psiMethods.get(0); 37 | super.psiMethod = psiMethod; 38 | this.ktNamedFunction = ktNamedFunction; 39 | } 40 | 41 | @NotNull 42 | protected Project getProject() { 43 | myProject = psiMethod.getProject(); 44 | return myProject; 45 | } 46 | 47 | /** 48 | * 构建URL参数 key value 49 | * @return 50 | */ 51 | public String buildParamString() { 52 | 53 | // boolean matchedGet = matchGetMethod(); 54 | // 没指定method 标示支持所有method 55 | 56 | StringBuilder param = new StringBuilder(""); 57 | Map baseTypeParamMap = getBaseTypeParameterMap(); 58 | 59 | if (baseTypeParamMap != null && baseTypeParamMap.size() > 0) { 60 | baseTypeParamMap.forEach((s, o) -> param.append(s).append("=").append(o).append("&")); 61 | } 62 | 63 | return param.length() >0 ? param.deleteCharAt(param.length()-1).toString() : ""; 64 | } 65 | 66 | /*获取方法中基础类型(primitive和string、date等以及这些类型数组)*/ 67 | /*@NotNull 68 | public Map getBaseTypeParameterMap() { 69 | List parameterList = getParameterList(); 70 | 71 | Map baseTypeParamMap = new LinkedHashMap(); 72 | 73 | // 拼接参数 74 | for (Parameter parameter : parameterList) { 75 | //跳过标注 RequestBody 注解的参数 76 | if (parameter.isRequestBodyFound()) { 77 | continue; 78 | } 79 | 80 | // todo 判断类型 81 | // 8 PsiPrimitiveType 82 | // 8 boxed types; String,Date:PsiClassReferenceType == field.getType().getPresentableText() 83 | String shortTypeName = parameter.getShortTypeName(); 84 | Object defaultValue = KtClassHelper.getJavaBaseTypeDefaultValue(shortTypeName); 85 | //简单常用类型 86 | if (defaultValue != null) { 87 | baseTypeParamMap.put(parameter.getParamName(),(defaultValue)); 88 | continue; 89 | } 90 | 91 | KtClassHelper psiClassHelper = KtClassHelper.create((KtClass) psiMethod.getParent().getParent()); 92 | KtClassOrObject ktClass = psiClassHelper.findOnePsiClassByClassName(parameter.getParamType(), getProject()); 93 | PsiClass psiClass = psiClassHelper.findOnePsiClassByClassName2(parameter.getParamType(), getProject()); 94 | if (psiClass != null) { 95 | PsiField[] fields = psiClass.getFields(); 96 | for (PsiField field : fields) { 97 | Object fieldDefaultValue = PsiClassHelper.getJavaBaseTypeDefaultValue(field.getType().getPresentableText()); 98 | if(fieldDefaultValue != null) 99 | baseTypeParamMap.put(field.getName(), fieldDefaultValue); 100 | } 101 | } 102 | *//* 103 | if (ktClass != null) { 104 | List ktParameters = ktClass.getPrimaryConstructorParameters(); 105 | for (KtParameter ktParameter : ktParameters) { 106 | Object typeDefaultValue = KtClassHelper.getJavaBaseTypeDefaultValue(ktParameter.getTypeReference().getText()); 107 | if(typeDefaultValue != null) 108 | baseTypeParamMap.put(ktParameter.getName(), typeDefaultValue); 109 | 110 | } 111 | }*//* 112 | 113 | *//* if (ktClass instanceof KtClass) { 114 | List ktProperties = ((KtClass) ktClass).getProperties(); 115 | for (KtProperty ktProperty : ktProperties) { 116 | System.out.println(ktProperty); 117 | // Object fieldDefaultValue = KtClassHelper.getJavaBaseTypeDefaultValue(ktProperty.getTypeReference()getPresentableText()); 118 | if(fieldDefaultValue != null) 119 | baseTypeParamMap.put(ktProperty.getName(), fieldDefaultValue); 120 | } 121 | }*//* 122 | } 123 | return baseTypeParamMap; 124 | }*/ 125 | 126 | 127 | 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/GenerateUrlAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | import com.intellij.openapi.actionSystem.AnActionEvent; 4 | import com.intellij.openapi.actionSystem.CommonDataKeys; 5 | import com.intellij.openapi.application.ApplicationManager; 6 | import com.intellij.openapi.editor.Editor; 7 | import com.intellij.openapi.ide.CopyPasteManager; 8 | import com.intellij.openapi.ui.popup.Balloon; 9 | import com.intellij.openapi.ui.popup.JBPopupFactory; 10 | import com.intellij.psi.*; 11 | import com.intellij.ui.JBColor; 12 | import com.zhaow.restful.action.AbstractBaseAction; 13 | import com.zhaow.restful.annotations.JaxrsHttpMethodAnnotation; 14 | import com.zhaow.restful.annotations.JaxrsRequestAnnotation; 15 | import com.zhaow.restful.annotations.SpringControllerAnnotation; 16 | import com.zhaow.restful.annotations.SpringRequestMethodAnnotation; 17 | import com.zhaow.restful.common.PsiMethodHelper; 18 | 19 | import java.awt.*; 20 | import java.awt.datatransfer.StringSelection; 21 | import java.util.Arrays; 22 | 23 | import static com.intellij.openapi.actionSystem.CommonDataKeys.PSI_ELEMENT; 24 | 25 | /** 26 | * 生成并复制restful url 27 | * todo: 没考虑RequestMapping 多个值的情况 28 | */ 29 | public class GenerateUrlAction /*extends RestfulMethodSpringSupportedAction*/ extends AbstractBaseAction { 30 | Editor myEditor ; 31 | 32 | @Override 33 | public void actionPerformed(AnActionEvent e) { 34 | 35 | myEditor = e.getData(CommonDataKeys.EDITOR); 36 | PsiElement psiElement = e.getData(PSI_ELEMENT); 37 | PsiMethod psiMethod = (PsiMethod) psiElement; 38 | 39 | //TODO: 需完善 jaxrs 支持 40 | String servicePath; 41 | if (isJaxrsRestMethod(psiMethod)) { 42 | servicePath = PsiMethodHelper.create(psiMethod).buildServiceUriPath(); 43 | } else { 44 | servicePath = PsiMethodHelper.create(psiMethod).buildServiceUriPathWithParams(); 45 | } 46 | 47 | CopyPasteManager.getInstance().setContents(new StringSelection(servicePath)); 48 | showPopupBalloon("copied servicePath:\n " + servicePath); 49 | } 50 | 51 | private boolean isJaxrsRestMethod(PsiMethod psiMethod) { 52 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 53 | 54 | for (PsiAnnotation annotation : annotations) { 55 | boolean match = Arrays.stream(JaxrsHttpMethodAnnotation.values()).map(sra -> sra.getQualifiedName()).anyMatch(name -> name.equals(annotation.getQualifiedName())); 56 | if(match) return match; 57 | } 58 | 59 | return false; 60 | } 61 | 62 | /** 63 | * spring rest 方法被选中才触发 64 | * @param e 65 | */ 66 | @Override 67 | public void update(AnActionEvent e) { 68 | PsiElement psiElement = e.getData(CommonDataKeys.PSI_ELEMENT); 69 | 70 | boolean visible = false; 71 | 72 | if(psiElement instanceof PsiMethod){ 73 | PsiMethod psiMethod = (PsiMethod) psiElement; 74 | // rest method 或标注了RestController 注解 75 | visible = (isRestController(psiMethod.getContainingClass()) || isRestfulMethod(psiMethod) ); 76 | } 77 | 78 | setActionPresentationVisible(e, visible); 79 | } 80 | 81 | //包含 "RestController" "Controller" 82 | private boolean isRestController(PsiClass containingClass) { 83 | PsiModifierList modifierList = containingClass.getModifierList(); 84 | 85 | /*return modifierList.findAnnotation(SpringControllerAnnotation.REST_CONTROLLER.getQualifiedName()) != null || 86 | modifierList.findAnnotation(SpringControllerAnnotation.CONTROLLER.getQualifiedName()) != null ;*/ 87 | 88 | return modifierList.findAnnotation(SpringControllerAnnotation.REST_CONTROLLER.getQualifiedName()) != null || 89 | modifierList.findAnnotation(SpringControllerAnnotation.CONTROLLER.getQualifiedName()) != null || 90 | modifierList.findAnnotation(JaxrsRequestAnnotation.PATH.getQualifiedName()) != null ; 91 | } 92 | 93 | private boolean isRestfulMethod(PsiMethod psiMethod) { 94 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 95 | 96 | for (PsiAnnotation annotation : annotations) { 97 | boolean match = Arrays.stream(SpringRequestMethodAnnotation.values()).map(sra -> sra.getQualifiedName()).anyMatch(name -> name.equals(annotation.getQualifiedName())); 98 | if(match) return match; 99 | } 100 | 101 | for (PsiAnnotation annotation : annotations) { 102 | boolean match = Arrays.stream(JaxrsHttpMethodAnnotation.values()).map(sra -> sra.getQualifiedName()).anyMatch(name -> name.equals(annotation.getQualifiedName())); 103 | if(match) return match; 104 | } 105 | 106 | return false; 107 | } 108 | 109 | 110 | private void showPopupBalloon(final String result) { 111 | ApplicationManager.getApplication().invokeLater(new Runnable() { 112 | public void run() { 113 | JBPopupFactory factory = JBPopupFactory.getInstance(); 114 | factory.createHtmlTextBalloonBuilder(result, null, new JBColor(new Color(186, 238, 186), new Color(73, 117, 73)), null) 115 | .setFadeoutTime(5000) 116 | .createBalloon() 117 | .show(factory.guessBestPopupLocation(myEditor), Balloon.Position.above); 118 | } 119 | }); 120 | } 121 | 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RestServicesNavigatorPanel.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | 4 | import com.intellij.openapi.actionSystem.*; 5 | import com.intellij.openapi.project.Project; 6 | import com.intellij.openapi.ui.SimpleToolWindowPanel; 7 | import com.intellij.openapi.ui.Splitter; 8 | import com.intellij.ui.PopupHandler; 9 | import com.intellij.ui.ScrollPaneFactory; 10 | import com.intellij.ui.treeStructure.SimpleTree; 11 | import com.zhaow.restful.navigation.action.RestServiceItem; 12 | import com.zhaow.utils.RestServiceDataKeys; 13 | import org.jetbrains.annotations.NonNls; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import javax.swing.*; 17 | import java.awt.*; 18 | import java.util.ArrayList; 19 | import java.util.Collection; 20 | import java.util.List; 21 | 22 | 23 | public class RestServicesNavigatorPanel extends SimpleToolWindowPanel implements DataProvider { 24 | 25 | private final Project myProject; 26 | private final SimpleTree myTree; 27 | RestServiceDetail myRestServiceDetail; 28 | 29 | private JSplitPane servicesContentPaneJSplitPane; 30 | private Splitter servicesContentPaneSplitter ; 31 | private final JTextArea defaultUnderView = new JTextArea(" json format textarea "); 32 | 33 | 34 | public RestServicesNavigatorPanel(Project project, SimpleTree tree) { 35 | super(true, true); 36 | 37 | myProject = project; 38 | myTree = tree; 39 | myRestServiceDetail = project.getComponent(RestServiceDetail.class); 40 | 41 | final ActionManager actionManager = ActionManager.getInstance(); 42 | ActionToolbar actionToolbar = actionManager.createActionToolbar("RestToolkit Navigator Toolbar", 43 | (DefaultActionGroup)actionManager 44 | .getAction("Toolkit.NavigatorActionsToolbar"), 45 | true); 46 | setToolbar(actionToolbar.getComponent()); 47 | 48 | Color gray = new Color(36,38,39); 49 | // setContent(ScrollPaneFactory.createScrollPane(myTree)); 50 | 51 | myTree.setBorder(BorderFactory.createLineBorder(gray)); 52 | JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTree); 53 | scrollPane.setBorder(BorderFactory.createLineBorder(Color.RED)); 54 | 55 | 56 | servicesContentPaneSplitter = new Splitter(true, .5f); 57 | servicesContentPaneSplitter.setShowDividerControls(true); 58 | servicesContentPaneSplitter.setDividerWidth(10); 59 | servicesContentPaneSplitter.setBorder(BorderFactory.createLineBorder(Color.RED)); 60 | 61 | servicesContentPaneSplitter.setFirstComponent(scrollPane); 62 | 63 | // servicesContentPaneSplitter.setSecondComponent(defaultUnderView); 64 | 65 | servicesContentPaneSplitter.setSecondComponent(myRestServiceDetail); 66 | 67 | setContent(servicesContentPaneSplitter); 68 | 69 | /*servicesContentPaneJSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 70 | servicesContentPaneJSplitPane.setDividerLocation(0.5); 71 | servicesContentPaneJSplitPane.setOneTouchExpandable(true);//让分割线显示出箭头 72 | servicesContentPaneJSplitPane.setLeftComponent(ScrollPaneFactory.createScrollPane(myTree)); 73 | servicesContentPaneJSplitPane.setRightComponent(new JTextArea("fdasfdsafdsafdsafdssdf")); 74 | this.setContent(servicesContentPaneJSplitPane);*/ 75 | // actionToolbar.setTargetComponent(servicesContentPaneSplitter); 76 | 77 | // popup 78 | myTree.addMouseListener(new PopupHandler() { 79 | public void invokePopup(final Component comp, final int x, final int y) { 80 | final String id = getMenuId(getSelectedNodes(RestServiceStructure.BaseSimpleNode.class)); 81 | if (id != null) { 82 | final ActionGroup actionGroup = (ActionGroup)actionManager.getAction(id); 83 | if (actionGroup != null) { 84 | // actionManager.createActionPopupMenu("", actionGroup).getComponent().show(comp, x, y); 85 | JPopupMenu component = actionManager.createActionPopupMenu("", actionGroup).getComponent(); 86 | 87 | component.show(comp, x, y); 88 | } 89 | } 90 | 91 | } 92 | 93 | @Nullable 94 | private String getMenuId(Collection nodes) { 95 | String id = null; 96 | for (RestServiceStructure.BaseSimpleNode node : nodes) { 97 | String menuId = node.getMenuId(); 98 | if (menuId == null) { 99 | return null; 100 | } 101 | if (id == null) { 102 | id = menuId; 103 | } 104 | else if (!id.equals(menuId)) { 105 | return null; 106 | } 107 | } 108 | return id; 109 | } 110 | }); 111 | } 112 | 113 | private Collection getSelectedNodes(Class aClass) { 114 | return RestServiceStructure.getSelectedNodes(myTree, aClass); 115 | } 116 | 117 | @Nullable 118 | public Object getData(@NonNls String dataId) { 119 | 120 | if (RestServiceDataKeys.SERVICE_ITEMS.is(dataId)) { 121 | return extractServices(); 122 | } 123 | 124 | return super.getData(dataId); 125 | } 126 | 127 | private List extractServices() { 128 | List result = new ArrayList<>(); 129 | 130 | Collection selectedNodes = getSelectedNodes(RestServiceStructure.BaseSimpleNode.class); 131 | for (RestServiceStructure.BaseSimpleNode selectedNode : selectedNodes) { 132 | if (selectedNode instanceof RestServiceStructure.ServiceNode) { 133 | result.add(((RestServiceStructure.ServiceNode) selectedNode).myServiceItem); 134 | } 135 | } 136 | 137 | return result; 138 | 139 | } 140 | 141 | } 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/GotoRequestMappingModel.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigation.action; 2 | 3 | import com.intellij.ide.IdeBundle; 4 | import com.intellij.ide.util.PropertiesComponent; 5 | import com.intellij.ide.util.gotoByName.CustomMatcherModel; 6 | import com.intellij.ide.util.gotoByName.FilteringGotoByModel; 7 | import com.intellij.navigation.ChooseByNameContributor; 8 | import com.intellij.navigation.NavigationItem; 9 | import com.intellij.openapi.project.DumbAware; 10 | import com.intellij.openapi.project.Project; 11 | import com.intellij.openapi.util.SystemInfo; 12 | import com.intellij.psi.codeStyle.MinusculeMatcher; 13 | import com.intellij.psi.codeStyle.NameUtil; 14 | import com.zhaow.restful.common.spring.AntPathMatcher; 15 | import com.zhaow.restful.method.HttpMethod; 16 | import org.jetbrains.annotations.NotNull; 17 | import org.jetbrains.annotations.Nullable; 18 | 19 | import javax.swing.*; 20 | import java.util.Collection; 21 | 22 | /** 23 | * Model for "Go to | File" action 24 | */ 25 | public class GotoRequestMappingModel extends FilteringGotoByModel implements DumbAware, CustomMatcherModel { 26 | 27 | protected GotoRequestMappingModel(@NotNull Project project, @NotNull ChooseByNameContributor[] contributors) { 28 | super(project, contributors); 29 | } 30 | // 设置过滤项 31 | /* @Override 32 | public synchronized void setFilterItems(Collection filterItems) { 33 | super.setFilterItems(filterItems); 34 | }*/ 35 | 36 | // TODO: 过滤模块? FilteringGotoByModel.acceptItem 调用,结合 重写 setFilterItems或 getFilterItems() 实现,可过滤模块 或者 method (如GotoClassModel2过滤language,重写 getFilterItems()) 37 | @Nullable 38 | @Override 39 | protected HttpMethod filterValueFor(NavigationItem item) { 40 | if (item instanceof RestServiceItem) { 41 | // if (((RestServiceItem) item).getModule().getName().contains("eureka")) { 42 | return ((RestServiceItem) item).getMethod(); 43 | // } 44 | } 45 | 46 | return null; 47 | } 48 | 49 | /* 可选项 */ 50 | @Nullable 51 | @Override 52 | protected synchronized Collection getFilterItems() { 53 | /*final Collection result = super.getFilterItems(); 54 | if (result == null) { 55 | return null; 56 | } 57 | final Collection items = new HashSet<>(result); 58 | items.add(Language.ANY); 59 | return items;*/ 60 | 61 | /* ArrayList items = new ArrayList(); 62 | items.add(HttpMethod.POST); 63 | return items;*/ 64 | return super.getFilterItems(); 65 | 66 | } 67 | 68 | @Override 69 | public String getPromptText() { 70 | return "Enter service URL path :"; 71 | } 72 | 73 | @Override 74 | public String getNotInMessage() { 75 | return IdeBundle.message("label.no.matches.found.in.project"); 76 | // return "No matched method found"; 77 | } 78 | 79 | @Override 80 | public String getNotFoundMessage() { 81 | return IdeBundle.message("label.no.matches.found"); 82 | // return "Service path not found"; 83 | } 84 | 85 | @Override 86 | public char getCheckBoxMnemonic() { 87 | return SystemInfo.isMac?'P':'n'; 88 | } 89 | 90 | @Override 91 | public boolean loadInitialCheckBoxState() { 92 | PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(myProject); 93 | return propertiesComponent.isTrueValue("GoToRestService.OnlyCurrentModule"); 94 | } 95 | 96 | /* 选择 item 跳转触发 */ 97 | @Override 98 | public void saveInitialCheckBoxState(boolean state) { 99 | PropertiesComponent propertiesComponent = PropertiesComponent.getInstance(myProject); 100 | if (propertiesComponent.isTrueValue("GoToRestService.OnlyCurrentModule")) { 101 | propertiesComponent.setValue("GoToRestService.OnlyCurrentModule", Boolean.toString(state)); 102 | } 103 | } 104 | 105 | @Nullable 106 | @Override 107 | public String getFullName(Object element) { 108 | return getElementName(element); 109 | } 110 | 111 | // 截取 Separators 后面pattern 112 | @NotNull 113 | @Override 114 | public String[] getSeparators() { 115 | // return new String[]{":","?"}; 116 | return new String[]{"/","?"}; 117 | } 118 | 119 | 120 | /** return null to hide checkbox panel */ 121 | @Nullable 122 | @Override 123 | public String getCheckBoxName() { 124 | return "Only This Module"; 125 | // return null; 126 | } 127 | 128 | 129 | @Override 130 | public boolean willOpenEditor() { 131 | return true; 132 | } 133 | 134 | // CustomMatcherModel 接口,Allows to implement custom matcher for matching items from ChooseByName popup 135 | // todo: resolve PathVariable annotation 136 | @Override 137 | public boolean matches(@NotNull String popupItem, @NotNull String userPattern) { 138 | String pattern = userPattern; 139 | if(pattern.equals("/")) return true; 140 | // REST风格的参数 @RequestMapping(value="{departmentId}/employees/{employeeId}") PathVariable 141 | // REST风格的参数(正则) @RequestMapping(value="/{textualPart:[a-z-]+}.{numericPart:[\\d]+}") PathVariable 142 | 143 | // pattern = StringUtils.removeRedundancyMarkup(pattern); 144 | 145 | // userPattern 输入的过滤文字 146 | // DefaultChooseByNameItemProvider.buildPatternMatcher 147 | MinusculeMatcher matcher = NameUtil.buildMatcher("*" + pattern, NameUtil.MatchingCaseSensitivity.NONE); 148 | boolean matches = matcher.matches(popupItem); 149 | if (!matches) { 150 | AntPathMatcher pathMatcher = new AntPathMatcher(); 151 | matches = pathMatcher.match(popupItem,userPattern); 152 | } 153 | return matches; 154 | // return true; 155 | 156 | } 157 | 158 | // 没用 ? 159 | @NotNull 160 | @Override 161 | public String removeModelSpecificMarkup(@NotNull String pattern) { 162 | return super.removeModelSpecificMarkup(pattern); 163 | // return "demo"; 164 | } 165 | 166 | /* TODO :重写渲染*/ 167 | @Override 168 | public ListCellRenderer getListCellRenderer() { 169 | 170 | return super.getListCellRenderer(); 171 | } 172 | 173 | 174 | } 175 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or 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 UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/RestServiceItem.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigation.action; 2 | 3 | import com.intellij.navigation.ItemPresentation; 4 | import com.intellij.navigation.NavigationItem; 5 | import com.intellij.openapi.module.Module; 6 | import com.intellij.pom.Navigatable; 7 | import com.intellij.psi.PsiElement; 8 | import com.intellij.psi.PsiMethod; 9 | import com.zhaow.restful.common.ToolkitIcons; 10 | import com.zhaow.restful.method.HttpMethod; 11 | import com.zhaow.restful.method.action.ModuleHelper; 12 | import org.jetbrains.annotations.Nullable; 13 | import org.jetbrains.kotlin.psi.KtClass; 14 | import org.jetbrains.kotlin.psi.KtNamedFunction; 15 | 16 | import javax.swing.*; 17 | 18 | //RequestMappingNavigationItem 19 | public class RestServiceItem implements NavigationItem { 20 | private PsiMethod psiMethod; //元素 21 | private PsiElement psiElement; //元素 22 | private Module module; 23 | 24 | private String requestMethod; //请求方法 get/post... 25 | private HttpMethod method; //请求方法 get/post... 26 | 27 | private String url; //url mapping; 28 | /* 29 | private String methodName; //方法名称 30 | 31 | private String hostContextPath; // todo 处理 http:// 32 | private PsiClass psiClass; 33 | private boolean foundRequestBody;*/ 34 | 35 | private Navigatable navigationElement; 36 | // ((KtClass) ((KtClassBody) psiElement.getParent()).getParent()).getModifierList().getAnnotationEntries().get(0).getText() 37 | public RestServiceItem(PsiElement psiElement, String requestMethod, String urlPath) { 38 | this.psiElement = psiElement; 39 | if (psiElement instanceof PsiMethod) { 40 | this.psiMethod = (PsiMethod) psiElement; 41 | } 42 | this.requestMethod = requestMethod; 43 | if (requestMethod != null) { 44 | method = HttpMethod.getByRequestMethod(requestMethod); 45 | } 46 | 47 | this.url = urlPath; 48 | if (psiElement instanceof Navigatable) { 49 | navigationElement = (Navigatable) psiElement; 50 | } 51 | } 52 | 53 | @Nullable 54 | @Override 55 | public String getName() { 56 | // return /*this.requestMethod + " " +*/ this.urlPath; 57 | return /*this.requestMethod + " " +*/ this.url; 58 | } 59 | 60 | @Nullable 61 | @Override 62 | public ItemPresentation getPresentation() { 63 | return new RestServiceItemPresentation(); 64 | } 65 | 66 | @Override 67 | public void navigate(boolean requestFocus) { 68 | if (navigationElement != null) { 69 | navigationElement.navigate(requestFocus); 70 | } 71 | } 72 | 73 | @Override 74 | public boolean canNavigate() { 75 | return navigationElement.canNavigate(); 76 | } 77 | 78 | @Override 79 | public boolean canNavigateToSource() { 80 | return true; 81 | } 82 | 83 | 84 | /*匹配*/ 85 | public boolean matches(String queryText) { 86 | String pattern = queryText; 87 | if (pattern.equals("/")) return true; 88 | 89 | com.intellij.psi.codeStyle.MinusculeMatcher matcher = com.intellij.psi.codeStyle.NameUtil.buildMatcher("*" + pattern, com.intellij.psi.codeStyle.NameUtil.MatchingCaseSensitivity.NONE); 90 | return matcher.matches(this.url); 91 | } 92 | 93 | private class RestServiceItemPresentation implements ItemPresentation { 94 | @Nullable 95 | @Override 96 | public String getPresentableText() { 97 | // return requestMethod + " " + url; 98 | return url; 99 | } 100 | 101 | // 对应的文件位置显示 102 | @Nullable 103 | @Override 104 | public String getLocationString() { 105 | String fileName = psiElement.getContainingFile().getName(); 106 | 107 | String location = null; 108 | 109 | if (psiElement instanceof PsiMethod) { 110 | PsiMethod psiMethod = ((PsiMethod) psiElement);; 111 | location = psiMethod.getContainingClass().getName().concat("#").concat(psiMethod.getName()); 112 | } else if (psiElement instanceof KtNamedFunction) { 113 | KtNamedFunction ktNamedFunction = (KtNamedFunction) RestServiceItem.this.psiElement; 114 | String className = ((KtClass) psiElement.getParent().getParent()).getName(); 115 | location = className.concat("#").concat(ktNamedFunction.getName()); 116 | } 117 | 118 | return "(" + location + ")"; 119 | } 120 | 121 | @Nullable 122 | @Override 123 | public Icon getIcon(boolean unused) { 124 | // System.out.println(unused + " " + this.getPresentableText()); 125 | return ToolkitIcons.METHOD.get(method); 126 | } 127 | } 128 | 129 | public Module getModule() { 130 | return module; 131 | } 132 | 133 | public PsiMethod getPsiMethod() { 134 | return psiMethod; 135 | } 136 | 137 | public void setPsiMethod(PsiMethod psiMethod) { 138 | this.psiMethod = psiMethod; 139 | } 140 | 141 | public HttpMethod getMethod() { 142 | return method; 143 | } 144 | 145 | public void setMethod(HttpMethod method) { 146 | this.method = method; 147 | } 148 | 149 | public String getUrl() { 150 | return url; 151 | } 152 | 153 | public void setUrl(String url) { 154 | this.url = url; 155 | } 156 | 157 | public String getFullUrl() { 158 | if (module == null) { 159 | return getUrl(); 160 | } 161 | 162 | ModuleHelper moduleHelper = ModuleHelper.create(module); 163 | // 处理 Mapping 设置个 value 164 | // String fullUrl = moduleHelper.buildFullUrl(psiMethod); 165 | 166 | return moduleHelper.getServiceHostPrefix() + getUrl(); 167 | } 168 | 169 | /* public String getFullUrlWithParams() { 170 | ModuleHelper moduleHelper = ModuleHelper.create(module); 171 | String urlWithParams = moduleHelper.buildFullUrlWithParams(psiMethod); 172 | return urlWithParams; 173 | }*/ 174 | 175 | public void setModule(Module module) { 176 | this.module = module; 177 | } 178 | 179 | /* public String getHostContextPath() { 180 | return hostContextPath; 181 | } 182 | 183 | public boolean isFoundRequestBody() { 184 | return foundRequestBody; 185 | } 186 | 187 | public void setFoundRequestBody(boolean foundRequestBody) { 188 | this.foundRequestBody = foundRequestBody; 189 | }*/ 190 | 191 | public PsiElement getPsiElement() { 192 | return psiElement; 193 | } 194 | } 195 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/utils/ToolkitUtil.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.utils; 2 | 3 | 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.application.ModalityState; 6 | import com.intellij.openapi.module.Module; 7 | import com.intellij.openapi.project.DumbService; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.startup.StartupManager; 10 | import com.intellij.psi.*; 11 | import com.intellij.psi.search.GlobalSearchScope; 12 | import com.intellij.util.DisposeAwareRunnable; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.net.URL; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | public class ToolkitUtil { 20 | public static void runWhenInitialized(final Project project, final Runnable r) { 21 | 22 | if (project.isDisposed()) return; 23 | 24 | if (isNoBackgroundMode()) { 25 | r.run(); 26 | return; 27 | } 28 | 29 | if (!project.isInitialized()) { 30 | StartupManager.getInstance(project).registerPostStartupActivity(DisposeAwareRunnable.create(r, project)); 31 | return; 32 | } 33 | 34 | /* System.out.println((DumbService.getInstance(project).isDumb())); 35 | if (DumbService.getInstance(project).isDumb()) { 36 | // return; 37 | runWhenInitialized(project,r); 38 | }*/ 39 | // runDumbAware(project, r); 40 | invokeLater(project, r); 41 | // ApplicationManager.getApplication().invokeAndWait(r); 42 | } 43 | 44 | 45 | public static void runWhenProjectIsReady(final Project project, final Runnable runnable) { 46 | 47 | // DumbService.getInstance(project).runWhenSmart(runnable); 48 | DumbService.getInstance(project).smartInvokeLater(runnable); 49 | // DumbService.getInstance(project).runReadActionInSmartMode(runnable); 50 | } 51 | 52 | 53 | public static boolean isNoBackgroundMode() { 54 | return (ApplicationManager.getApplication().isUnitTestMode() 55 | || ApplicationManager.getApplication().isHeadlessEnvironment()); 56 | } 57 | 58 | 59 | public static void runDumbAware(final Project project, final Runnable r) { 60 | if (DumbService.isDumbAware(r)) { 61 | r.run(); 62 | } 63 | else { 64 | DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project)); 65 | } 66 | } 67 | 68 | 69 | public static void invokeLater(Runnable r) { 70 | ApplicationManager.getApplication().invokeLater(r); 71 | } 72 | 73 | public static void invokeLater(Project p, Runnable r) { 74 | invokeLater(p, ModalityState.defaultModalityState(), r); 75 | } 76 | 77 | public static void invokeLater(final Project p, final ModalityState state, final Runnable r) { 78 | if (isNoBackgroundMode()) { 79 | r.run(); 80 | } 81 | else { 82 | ApplicationManager.getApplication().invokeLater(DisposeAwareRunnable.create(r, p), state); 83 | } 84 | } 85 | 86 | 87 | public static String formatHtmlImage(URL url) { 88 | return " "; 89 | } 90 | 91 | 92 | public static PsiClass findPsiClass(final String qualifiedName, final Module module, final Project project) { 93 | final GlobalSearchScope scope = module == null ? GlobalSearchScope.projectScope(project) : GlobalSearchScope.moduleWithDependenciesScope(module); 94 | return JavaPsiFacade.getInstance(project).findClass(qualifiedName, scope); 95 | } 96 | 97 | public static PsiPackage getContainingPackage(@NotNull PsiClass psiClass) { 98 | PsiDirectory directory = psiClass.getContainingFile().getContainingDirectory(); 99 | return directory == null ? null : JavaDirectoryService.getInstance().getPackage(directory); 100 | } 101 | 102 | public static void runWriteAction(@NotNull Runnable action) { 103 | ApplicationManager.getApplication().runWriteAction(action); 104 | } 105 | 106 | 107 | 108 | @NotNull 109 | public static String removeRedundancyMarkup(String pattern) { 110 | 111 | String localhostRegex = "(http(s?)://)?(localhost)(:\\d+)?"; 112 | String hostAndPortRegex = "(http(s?)://)?" + 113 | "( " + 114 | "([a-zA-Z0-9]([a-zA-Z0-9\\\\-]{0,61}[a-zA-Z0-9])?\\\\.)+[a-zA-Z]{2,6} |" + // domain 115 | "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)" + // ip address 116 | ")" ; 117 | 118 | String localhost = "localhost"; 119 | if (pattern.contains(localhost)) { 120 | pattern = pattern.replaceFirst(localhostRegex,""); 121 | } 122 | 123 | if (pattern.contains("http:") || pattern.contains("https:") ) { // quick test if reg exp should be used 124 | pattern = pattern.replaceFirst(hostAndPortRegex, ""); 125 | } 126 | 127 | //TODO : resolve RequestMapping(params="method=someMethod") 128 | // 包含参数 129 | if (pattern.contains("?")) { 130 | pattern = pattern.substring(0, pattern.indexOf("?")); 131 | } 132 | return pattern; 133 | } 134 | 135 | /* 将文本转为 Param */ 136 | @NotNull 137 | public static String textToRequestParam(String text) { 138 | //拼装param参数 139 | StringBuilder param = new StringBuilder(); 140 | 141 | Map paramMap = textToParamMap(text); 142 | 143 | if (paramMap != null && paramMap.size() > 0) { 144 | paramMap.forEach((s, o) -> param.append(s).append("=").append(o).append("&")); 145 | } 146 | 147 | String params = param.length() == 0 ? "" : param.deleteCharAt(param.length() - 1).toString(); 148 | 149 | return params; 150 | } 151 | 152 | 153 | /* 将文本转为 Param Map*/ 154 | @NotNull 155 | public static Map textToParamMap(String text) { 156 | Map paramMap = new HashMap<>(); 157 | //拼装param参数 158 | String paramText = text;//serviceInfo.getText(); 159 | String[] lines = paramText.split("\n"); 160 | 161 | for (String line : lines) { 162 | //合法参数键值对 (非//开头,且包含 : ) 163 | if (!line.startsWith("//") && line.contains(":")) { 164 | 165 | String[] prop = line.split(":"); 166 | 167 | if (prop.length > 1) { 168 | String key = prop[0].trim(); 169 | String value = prop[1].trim(); 170 | // value = line.substring() 171 | paramMap.put(key, value); 172 | } 173 | } 174 | } 175 | return paramMap; 176 | } 177 | 178 | 179 | 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/utils/ToolkitUtil.java.bak: -------------------------------------------------------------------------------- 1 | package com.zhaow.utils; 2 | 3 | 4 | import com.intellij.openapi.application.ApplicationManager; 5 | import com.intellij.openapi.application.ModalityState; 6 | import com.intellij.openapi.module.Module; 7 | import com.intellij.openapi.project.DumbService; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.startup.StartupManager; 10 | import com.intellij.psi.*; 11 | import com.intellij.psi.search.GlobalSearchScope; 12 | import com.intellij.util.DisposeAwareRunnable; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.net.URL; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | public class ToolkitUtil { 20 | public static void runWhenInitialized(final Project project, final Runnable r) { 21 | 22 | if (project.isDisposed()) return; 23 | 24 | if (isNoBackgroundMode()) { 25 | System.out.println(1); 26 | r.run(); 27 | return; 28 | } 29 | 30 | if (!project.isInitialized()) { 31 | StartupManager.getInstance(project).registerPostStartupActivity(DisposeAwareRunnable.create(r, project)); 32 | return; 33 | } 34 | 35 | /* System.out.println((DumbService.getInstance(project).isDumb())); 36 | if (DumbService.getInstance(project).isDumb()) { 37 | // return; 38 | runWhenInitialized(project,r); 39 | }*/ 40 | // runDumbAware(project, r); 41 | // invokeLater(project, r); 42 | ApplicationManager.getApplication().invokeAndWait(r); 43 | } 44 | 45 | 46 | public static void runWhenProjectIsReady(final Project project, final Runnable runnable) { 47 | 48 | // DumbService.getInstance(project).runWhenSmart(runnable); 49 | DumbService.getInstance(project).smartInvokeLater(runnable); 50 | // DumbService.getInstance(project).runReadActionInSmartMode(runnable); 51 | } 52 | 53 | 54 | public static boolean isNoBackgroundMode() { 55 | return (ApplicationManager.getApplication().isUnitTestMode() 56 | || ApplicationManager.getApplication().isHeadlessEnvironment()); 57 | } 58 | 59 | 60 | public static void runDumbAware(final Project project, final Runnable r) { 61 | if (DumbService.isDumbAware(r)) { 62 | r.run(); 63 | } 64 | else { 65 | DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project)); 66 | } 67 | } 68 | 69 | 70 | public static void invokeLater(Runnable r) { 71 | ApplicationManager.getApplication().invokeLater(r); 72 | } 73 | 74 | public static void invokeLater(Project p, Runnable r) { 75 | invokeLater(p, ModalityState.defaultModalityState(), r); 76 | } 77 | 78 | public static void invokeLater(final Project p, final ModalityState state, final Runnable r) { 79 | if (isNoBackgroundMode()) { 80 | r.run(); 81 | } 82 | else { 83 | ApplicationManager.getApplication().invokeLater(DisposeAwareRunnable.create(r, p), state); 84 | } 85 | } 86 | 87 | 88 | public static void invokeAndWait(final Project p, final ModalityState state, final Runnable r) { 89 | ApplicationManager.getApplication().invokeAndWait(DisposeAwareRunnable.create(r, p), state); 90 | 91 | } 92 | 93 | public static String formatHtmlImage(URL url) { 94 | return " "; 95 | } 96 | 97 | 98 | public static PsiClass findPsiClass(final String qualifiedName, final Module module, final Project project) { 99 | final GlobalSearchScope scope = module == null ? GlobalSearchScope.projectScope(project) : GlobalSearchScope.moduleWithDependenciesScope(module); 100 | return JavaPsiFacade.getInstance(project).findClass(qualifiedName, scope); 101 | } 102 | 103 | public static PsiPackage getContainingPackage(@NotNull PsiClass psiClass) { 104 | PsiDirectory directory = psiClass.getContainingFile().getContainingDirectory(); 105 | return directory == null ? null : JavaDirectoryService.getInstance().getPackage(directory); 106 | } 107 | 108 | public static void runWriteAction(@NotNull Runnable action) { 109 | ApplicationManager.getApplication().runWriteAction(action); 110 | } 111 | 112 | 113 | 114 | @NotNull 115 | public static String removeRedundancyMarkup(String pattern) { 116 | 117 | String localhostRegex = "(http(s?)://)?(localhost)(:\\d+)?"; 118 | String hostAndPortRegex = "(http(s?)://)?" + 119 | "( " + 120 | "([a-zA-Z0-9]([a-zA-Z0-9\\\\-]{0,61}[a-zA-Z0-9])?\\\\.)+[a-zA-Z]{2,6} |" + // domain 121 | "((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)" + // ip address 122 | ")" ; 123 | 124 | String localhost = "localhost"; 125 | if (pattern.contains(localhost)) { 126 | pattern = pattern.replaceFirst(localhostRegex,""); 127 | } 128 | 129 | if (pattern.contains("http:") || pattern.contains("https:") ) { // quick test if reg exp should be used 130 | pattern = pattern.replaceFirst(hostAndPortRegex, ""); 131 | } 132 | 133 | //TODO : resolve RequestMapping(params="method=someMethod") 134 | // 包含参数 135 | if (pattern.contains("?")) { 136 | pattern = pattern.substring(0, pattern.indexOf("?")); 137 | } 138 | return pattern; 139 | } 140 | 141 | /* 将文本转为 Param */ 142 | @NotNull 143 | public static String textToRequestParam(String text) { 144 | //拼装param参数 145 | StringBuilder param = new StringBuilder(); 146 | 147 | Map paramMap = textToParamMap(text); 148 | 149 | if (paramMap != null && paramMap.size() > 0) { 150 | paramMap.forEach((s, o) -> param.append(s).append("=").append(o).append("&")); 151 | } 152 | 153 | String params = param.length() == 0 ? "" : param.deleteCharAt(param.length() - 1).toString(); 154 | 155 | return params; 156 | } 157 | 158 | 159 | /* 将文本转为 Param Map*/ 160 | @NotNull 161 | public static Map textToParamMap(String text) { 162 | Map paramMap = new HashMap<>(); 163 | //拼装param参数 164 | String paramText = text;//serviceInfo.getText(); 165 | String[] lines = paramText.split("\n"); 166 | 167 | for (String line : lines) { 168 | //合法参数键值对 (非//开头,且包含 : ) 169 | if (!line.startsWith("//") && line.contains(":")) { 170 | 171 | String[] prop = line.split(":"); 172 | 173 | if (prop.length > 1) { 174 | String key = prop[0].trim(); 175 | String value = prop[1].trim(); 176 | // value = line.substring() 177 | paramMap.put(key, value); 178 | } 179 | } 180 | } 181 | return paramMap; 182 | } 183 | 184 | 185 | 186 | } 187 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigation/action/GotoRequestMappingAction.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigation.action; 2 | 3 | import com.intellij.featureStatistics.FeatureUsageTracker; 4 | import com.intellij.ide.actions.GotoActionBase; 5 | import com.intellij.ide.util.gotoByName.*; 6 | import com.intellij.navigation.ChooseByNameContributor; 7 | import com.intellij.openapi.actionSystem.AnActionEvent; 8 | import com.intellij.openapi.actionSystem.CommonDataKeys; 9 | import com.intellij.openapi.actionSystem.DataKeys; 10 | import com.intellij.openapi.actionSystem.LangDataKeys; 11 | import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx; 12 | import com.intellij.openapi.ide.CopyPasteManager; 13 | import com.intellij.openapi.project.DumbAware; 14 | import com.intellij.openapi.project.Project; 15 | import com.intellij.openapi.util.Pair; 16 | import com.intellij.psi.PsiElement; 17 | import com.zhaow.restful.method.HttpMethod; 18 | import org.jetbrains.annotations.NotNull; 19 | import org.jetbrains.annotations.Nullable; 20 | 21 | import javax.swing.*; 22 | import java.awt.datatransfer.DataFlavor; 23 | import java.util.Arrays; 24 | import java.util.List; 25 | 26 | 27 | public class GotoRequestMappingAction extends GotoActionBase implements DumbAware { 28 | public GotoRequestMappingAction() { 29 | } 30 | 31 | @Override 32 | protected void gotoActionPerformed(AnActionEvent e) { 33 | //进入导航 34 | Project project = e.getProject(); 35 | if (project == null) { return ;}; 36 | 37 | FeatureUsageTracker.getInstance().triggerFeatureUsed("navigation.popup.service"); 38 | 39 | ChooseByNameContributor[] chooseByNameContributors = { 40 | new GotoRequestMappingContributor(e.getData(LangDataKeys.MODULE))/*, 41 | new RequestMappingContributor()*/ 42 | }; 43 | 44 | final GotoRequestMappingModel model = new GotoRequestMappingModel(project, chooseByNameContributors); 45 | 46 | // GotoRequestMappingCallback callback = new GotoRequestMappingCallback(); 47 | 48 | GotoActionCallback callback = new GotoActionCallback() { 49 | @Override 50 | protected ChooseByNameFilter createFilter(@NotNull ChooseByNamePopup popup) { 51 | return new GotoRequestMappingFilter(popup, model, project); 52 | } 53 | 54 | @Override 55 | public void elementChosen(ChooseByNamePopup chooseByNamePopup, Object element) { 56 | if (element instanceof RestServiceItem) { 57 | RestServiceItem navigationItem = (RestServiceItem) element; 58 | if (navigationItem.canNavigate()) { 59 | navigationItem.navigate(true); 60 | } 61 | } 62 | } 63 | }; 64 | 65 | // this.showNavigationPopup(e, model, callback, false); 66 | GotoRequestMappingProvider provider = new GotoRequestMappingProvider(getPsiContext(e)); 67 | showNavigationPopup(e, model, callback, "Request Mapping Url matching pattern", true, true, (ChooseByNameItemProvider)provider); 68 | // showNavigationPopup(callback,"Request Mapping Url matching pattern",); 69 | 70 | } 71 | 72 | @Override 73 | protected void showNavigationPopup(AnActionEvent e, 74 | ChooseByNameModel model, 75 | final GotoActionCallback callback, 76 | @Nullable final String findUsagesTitle, 77 | boolean useSelectionFromEditor, 78 | final boolean allowMultipleSelection, 79 | final ChooseByNameItemProvider itemProvider) { 80 | final Project project = e.getData(CommonDataKeys.PROJECT); 81 | boolean mayRequestOpenInCurrentWindow = model.willOpenEditor() && FileEditorManagerEx.getInstanceEx(project).hasSplitOrUndockedWindows(); 82 | Pair start = getInitialText(useSelectionFromEditor, e); 83 | /*showNavigationPopup(callback, findUsagesTitle, 84 | ChooseByNamePopup.createPopup(project, model, itemProvider, start.first, 85 | mayRequestOpenInCurrentWindow, 86 | start.second), allowMultipleSelection);*/ 87 | 88 | String copiedURL = tryFindCopiedURL(); 89 | 90 | String predefinedText = start.first == null ? copiedURL : start.first; 91 | 92 | showNavigationPopup(callback, findUsagesTitle, 93 | RestServiceChooseByNamePopup.createPopup(project, model, itemProvider, predefinedText, 94 | mayRequestOpenInCurrentWindow, 95 | start.second), allowMultipleSelection); 96 | } 97 | 98 | private String tryFindCopiedURL() { 99 | String contents = CopyPasteManager.getInstance().getContents(DataFlavor.stringFlavor); 100 | if (contents == null) { 101 | return null; 102 | } 103 | 104 | contents = contents.trim(); 105 | if (contents.startsWith("http")) { 106 | if (contents.length() <= 120) { 107 | return contents; 108 | }else { 109 | return contents.substring(0, 120); 110 | } 111 | } 112 | 113 | return null; 114 | } 115 | 116 | /* 117 | private class GotoRequestMappingCallback extends GotoActionCallback{ 118 | // 定位选择文件 119 | @Override 120 | public void elementChosen(ChooseByNamePopup chooseByNamePopup, Object element) { 121 | if (element instanceof RestServiceItem) { 122 | RestServiceItem navigationItem = (RestServiceItem) element; 123 | if (navigationItem.canNavigate()) { 124 | navigationItem.navigate(true); 125 | } 126 | } 127 | } 128 | }*/ 129 | 130 | protected static class GotoRequestMappingFilter extends ChooseByNameFilter { 131 | GotoRequestMappingFilter(final ChooseByNamePopup popup, GotoRequestMappingModel model, final Project project) { 132 | super(popup, model, GotoRequestMappingConfiguration.getInstance(project), project); 133 | } 134 | 135 | @Override 136 | @NotNull 137 | protected List getAllFilterValues() { 138 | // List elements = new ArrayList<>(); 139 | /*elements.add(HttpMethod.GET); 140 | elements.add(HttpMethod.POST); 141 | elements.add(HttpMethod.DELETE); 142 | elements.add(HttpMethod.PATCH);*/ 143 | List elements = Arrays.asList(HttpMethod.values()); 144 | 145 | return elements; 146 | } 147 | 148 | @Override 149 | protected String textForFilterValue(@NotNull HttpMethod value) { 150 | return value.name(); 151 | } 152 | 153 | @Override 154 | protected Icon iconForFilterValue(@NotNull HttpMethod value) { 155 | // return value.getIcon(); 156 | return null; 157 | } 158 | } 159 | 160 | 161 | //找到文件 162 | private PsiElement getElement(PsiElement element, ChooseByNamePopup chooseByNamePopup) { 163 | return null; 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/navigator/RestServicesNavigator.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.navigator; 2 | 3 | import com.intellij.ide.util.treeView.TreeState; 4 | import com.intellij.openapi.actionSystem.AnActionEvent; 5 | import com.intellij.openapi.application.ApplicationManager; 6 | import com.intellij.openapi.components.*; 7 | import com.intellij.openapi.diagnostic.Logger; 8 | import com.intellij.openapi.project.Project; 9 | import com.intellij.openapi.util.WriteExternalException; 10 | import com.intellij.openapi.wm.ToolWindowAnchor; 11 | import com.intellij.openapi.wm.ex.ToolWindowEx; 12 | import com.intellij.openapi.wm.ex.ToolWindowManagerAdapter; 13 | import com.intellij.openapi.wm.ex.ToolWindowManagerEx; 14 | import com.intellij.ui.content.Content; 15 | import com.intellij.ui.content.ContentFactory; 16 | import com.intellij.ui.content.ContentManager; 17 | import com.intellij.ui.treeStructure.SimpleTree; 18 | import com.zhaow.restful.common.ToolkitIcons; 19 | import com.zhaow.utils.RestfulToolkitBundle; 20 | import com.zhaow.utils.ToolkitUtil; 21 | import org.jdom.Element; 22 | import org.jetbrains.annotations.Nullable; 23 | 24 | import javax.swing.*; 25 | import javax.swing.tree.TreeSelectionModel; 26 | import java.awt.*; 27 | import java.net.URL; 28 | 29 | @State(name = "RestServicesNavigator", storages = {@Storage(StoragePathMacros.WORKSPACE_FILE)}) 30 | public class RestServicesNavigator implements PersistentStateComponent, ProjectComponent { 31 | public static final Logger LOG = Logger.getInstance(RestServicesNavigator.class); 32 | 33 | public static final String TOOL_WINDOW_ID = "RestServices"; 34 | 35 | protected final Project myProject; 36 | 37 | private static final URL SYNC_ICON_URL = RestServicesNavigator.class.getResource("/actions/refresh.png"); 38 | 39 | RestServicesNavigatorState myState = new RestServicesNavigatorState(); 40 | 41 | private SimpleTree myTree; 42 | protected RestServiceStructure myStructure; 43 | private ToolWindowEx myToolWindow; 44 | private AnActionEvent anActionEvent; 45 | 46 | private RestServiceProjectsManager myProjectsManager; 47 | 48 | public RestServicesNavigator(Project myProject, RestServiceProjectsManager projectsManager) { 49 | this.myProject = myProject; 50 | myProjectsManager = projectsManager; 51 | } 52 | 53 | 54 | public static RestServicesNavigator getInstance(Project p) { 55 | return p.getComponent(RestServicesNavigator.class); 56 | } 57 | 58 | 59 | private void initTree() { 60 | myTree = new SimpleTree() { 61 | 62 | @Override 63 | protected void paintComponent(Graphics g) { 64 | super.paintComponent(g); 65 | 66 | final JLabel myLabel = new JLabel( 67 | RestfulToolkitBundle.message("toolkit.navigator.nothing.to.display", ToolkitUtil.formatHtmlImage(SYNC_ICON_URL))); 68 | 69 | if (myProject.isInitialized()) { 70 | return; 71 | } 72 | 73 | myLabel.setFont(getFont()); 74 | myLabel.setBackground(getBackground()); 75 | myLabel.setForeground(getForeground()); 76 | Rectangle bounds = getBounds(); 77 | Dimension size = myLabel.getPreferredSize(); 78 | myLabel.setBounds(0, 0, size.width, size.height); 79 | 80 | int x = (bounds.width - size.width) / 2; 81 | Graphics g2 = g.create(bounds.x + x, bounds.y + 20, bounds.width, bounds.height); 82 | try { 83 | myLabel.paint(g2); 84 | } finally { 85 | g2.dispose(); 86 | } 87 | } 88 | }; 89 | myTree.getEmptyText().clear(); 90 | 91 | myTree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION); 92 | } 93 | 94 | @Override 95 | public void initComponent() { 96 | listenForProjectsChanges(); 97 | ToolkitUtil.runWhenInitialized(myProject, () -> { 98 | if (myProject.isDisposed()) { 99 | return; 100 | } 101 | initToolWindow(); 102 | }); 103 | } 104 | 105 | public void atachEvent(AnActionEvent anActionEvent) { 106 | this.anActionEvent = anActionEvent; 107 | } 108 | 109 | private void initToolWindow() { 110 | 111 | final ToolWindowManagerEx manager = ToolWindowManagerEx.getInstanceEx(myProject); 112 | myToolWindow = (ToolWindowEx) manager.getToolWindow(TOOL_WINDOW_ID); 113 | if (myToolWindow != null) { 114 | return; 115 | } 116 | 117 | initTree(); 118 | 119 | myToolWindow = (ToolWindowEx) manager.registerToolWindow(TOOL_WINDOW_ID, false, ToolWindowAnchor.RIGHT, myProject, true); 120 | myToolWindow.setIcon(ToolkitIcons.SERVICE); 121 | 122 | JPanel panel = new RestServicesNavigatorPanel(myProject, myTree); 123 | final ContentFactory contentFactory = ServiceManager.getService(ContentFactory.class); 124 | final Content content = contentFactory.createContent(panel, "", false); 125 | ContentManager contentManager = myToolWindow.getContentManager(); 126 | contentManager.addContent(content); 127 | contentManager.setSelectedContent(content, false); 128 | 129 | final ToolWindowManagerAdapter listener = new ToolWindowManagerAdapter() { 130 | boolean wasVisible = false; 131 | 132 | @Override 133 | public void stateChanged() { 134 | if (myToolWindow.isDisposed()) { 135 | return; 136 | } 137 | boolean visible = myToolWindow.isVisible(); 138 | if (!visible || wasVisible) { 139 | return; 140 | } 141 | scheduleStructureUpdate(); 142 | wasVisible = true; 143 | } 144 | }; 145 | manager.addToolWindowManagerListener(listener, myProject); 146 | } 147 | 148 | 149 | public void scheduleStructureUpdate() { 150 | scheduleStructureRequest(() -> myStructure.update(anActionEvent)); 151 | 152 | } 153 | 154 | private void scheduleStructureRequest(final Runnable r) { 155 | 156 | if (myToolWindow == null) { 157 | return; 158 | } 159 | 160 | ToolkitUtil.runWhenProjectIsReady(myProject, () -> { 161 | if (!myToolWindow.isVisible()) { 162 | return; 163 | } 164 | 165 | boolean shouldCreate = myStructure == null; 166 | if (shouldCreate) { 167 | initStructure(); 168 | } 169 | 170 | r.run(); 171 | 172 | }); 173 | } 174 | 175 | private void initStructure() { 176 | myStructure = new RestServiceStructure(myProject, myProjectsManager, myTree); 177 | 178 | } 179 | 180 | // 监听项目controller 方法变化 181 | private void listenForProjectsChanges() { 182 | //todo : 183 | } 184 | 185 | @Nullable 186 | @Override 187 | public RestServicesNavigatorState getState() { 188 | ApplicationManager.getApplication().assertIsDispatchThread(); 189 | if (myStructure != null) { 190 | try { 191 | myState.treeState = new Element("root"); 192 | TreeState.createOn(myTree).writeExternal(myState.treeState); 193 | } catch (WriteExternalException e) { 194 | LOG.warn(e); 195 | } 196 | } 197 | return myState; 198 | } 199 | 200 | @Override 201 | public void loadState(RestServicesNavigatorState state) { 202 | myState = state; 203 | scheduleStructureUpdate(); 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | 参考 https://gitee.com/aiqinhai/generateGSDoc 在 alt enter 中添加 添加实现同名方法,并拷贝注释 2 | 3 | //// rest services 中添加 send request 4 | 5 | http://www.jianshu.com/p/ae90491f0c72 (codeGener.zip https://pan.baidu.com/s/1c1WEtMw) 添加 alt insert 6 | 7 | 8 | http://www.jianshu.com/nb/8816511 9 | IntelliJ平台SDK开发指南(翻译) 10 | 11 | ======================== 12 | post 访问 javased 查找代码 13 | 14 | https://www.programcreek.com/java-api-examples/index.php 15 | 16 | 17 | 18 | 19 | 20 | =================================== 21 | show rest services 22 | 右键添加refresh 23 | 24 | ----------------------------------- 25 | Rest Services 按模块--controller -- method 划分,get post 方法按图标标示 26 | 27 | 28 | ======================== 29 | post 访问 javased 查找代码 30 | 31 | https://www.programcreek.com/java-api-examples/index.php 32 | ============================== 33 | RestServiceWindow 结构 34 | splitPane 35 | jTextField 是否保留query输入框查询? 36 | jTree rest services 树状结构,0,单击在text区域显示service,1,双击跳转到代码位置,2,右键添加copy url,json ,postman 信息,apiview 参数等,3,右键发送请求,text区域编辑属性? 37 | jTextField url(Send button)发送请求,rqeust body,自动在header中添加Content-type = application/json,请求response结果怎么展示?动态添加一个tab或是param下隐藏一个response textarea 38 | jTextArea (Param) 文字区域显示服务信息,尤其request body 的json信息,彩蛋: 回车格式化,双击复制 39 | 40 | 直接jTree 筛选url 41 | 每个service跟节点显示servcie数量,restservieui中status意义不大 42 | 问题? 如何直接执行url,调用rest client plugin ?或者别的 43 | 44 | jTextArea 区域文本发生变更,进行提醒(右键发送请求,避免误伤) 45 | 46 | 搜索 如何动态改变split 元素的高度 ,可以,直接设置即可: splitPane.setDividerLocation(1.0/2.0); 47 | 48 | 49 | ============================= 50 | restful: 返回json, RestController 或者 Controller + 方法@ResponseBody 51 | 52 | =============================== 53 | 方法如何添加方法直接调用request请求,直接调用插件。 54 | 参考transelate 插件,或者 overflowstack 插件 55 | 56 | ---------------------------- 57 | 方法添加右键尝试执行请求(TryExecuteRequestService),分析方法名add、save等方法常识去掉主键(猜测id,实体+id),创建时间(creteTime,insertTime..),创建人(createUser,userId,accountId...) 58 | ;update为更新方法(参考spring事务过滤,可以做成可配置化) 59 | ============================= 60 | 彩蛋: 61 | 集成个推或环信,在url输入特定字符,可以接收消息?? 62 | 63 | 64 | ============================= 65 | json 加高亮 66 | 67 | ============= 68 | 参考StackInTheFlow 重绘ui 69 | 70 | 71 | =============== 72 | ReadHub 插件 (参考 StackInTheFlow 列表) 73 | 74 | 75 | ================= 76 | spring boot 模块右键添加执行 Run [模块名称] Module, 仿 eclipse 77 | 找到 包含 @SpringBootApplication 注解的类,PsiMethodUtil.findMainInClass(PsiClass) 78 | 79 | 80 | codegen: 81 | =========生成目录======== 82 | 83 | = ====生成dto 84 | 选择 Entity 参考 TreeJavaClassChooserDialog,ClassBrowser 85 | 86 | request mapping 可选 Include (Dependencies And )Libraries (Include non-project classes,只能通过module来加载,project没有library以来) 87 | GlobalSearchScope.moduleWithDependenciesAndLibrariesScope 88 | GlobalSearchScope.moduleRuntimeScope(module,false) 89 | GlobalSearchScope.moduleWithDependenciesAndLibrariesScope 90 | 91 | GlobalSearchScope.allScope(project); 所有scope 92 | GlobalSearchScope.allScope(everythingScope); 所有scope 93 | 94 | ===== 95 | 96 | 97 | ======================= 98 | 如何在输入完整url情况下, 99 | 1,后面的关键字如 http:/localhost:90/demo/只匹配demo并高亮, 100 | 2,匹配 PathVariable 形式的完整url路径 101 | 如:get http:/localhost:90/demo/1111 匹配 /demo/{demoId} 102 | 103 | 104 | 105 | ======================== 106 | controller 默认path约定规则,如paoding-rose,DemoController---> /demo 107 | 108 | 109 | 110 | 重写ChooseByNamePopup.getTransformedPattern 实现高亮部门pattern字段 111 | 112 | 113 | 集成到 Search Everywhere 114 | 115 | 貌似这是唯一的入口 116 | 117 | 118 | ===================== 119 | 如果接口使用 action=aAction 情况处理 120 | 121 | 122 | ======================= 123 | 跟匹配相关的几个方法, 124 | 1,GotoRequestMappingProvider extends DefaultChooseByNameItemProvider: 125 | filterElements 处理匹配项 126 | 127 | 2,Goto\RequestMappingModel extends FilteringGotoByModel implements CustomMatcherModel: 128 | matches 129 | removeModelSpecificMarkup,处理过滤项目, 具体用法跟,GotoRequestMappingProvider.filterElements 中处理匹配项有什么区别 130 | 131 | 3,RestServiceChooseByNamePopup extends ChooseByNamePopup 132 | transformPattern(String pattern) 跟渲染有关 133 | 134 | 135 | 1, RequestMappingContributor 提供数据 136 | 137 | 138 | ==========test: 139 | http://localhost:8082/v1/system/de/addDept?headSchoolId=demoData&campusType=demoData&deptName=demoData&hasSubDept=1 140 | 141 | http://localhost:8082/v1/system/pt/3243/addSubDept?parentDeptId=demoData&topDeptId=demoData 142 | 143 | 144 | 145 | PsiClass.isExtendList 146 | PsiUtil.getTopLevelClass 147 | com.intellij.psi.util.PsiUtil.getTopLevelClass(psiElement) 148 | 149 | 150 | findMergedAnnotationAttributes 151 | 152 | 153 | IconLoader.getIcon("/icons/SpringBoot.png") 154 | 155 | Run 'Spring Boot App' 156 | Debug 'Spring Boot App' 157 | 158 | 159 | PathUtil 160 | 161 | 162 | action: copy full com.zhaow.restful.runner.SpringBootConfigurationType 163 | 164 | ClassUtil 165 | 166 | ClassInheritorsSearch AllClassesSearch ClassesWithAnnotatedMembersSearch PsiShortNamesCache AnnotationTargetsSearch 167 | 168 | PsiManager.getInstance(project); 169 | 170 | 171 | 172 | ============ 173 | PsiDocumentManager.getInstance(project).commitAllDocuments(); 解决插件出现 different provider 问题 174 | ===============================Spring 5 webflux 175 | JavaFindUsagesHandler 176 | 177 | FindUsagesHelper.processUsagesInText 查找引用 Spring 5 webflux 可用 178 | 179 | MethodSignatureUtil.hasOverloads getOverloads 180 | PropertyUtil.getPropertyNameByGetter 181 | 182 | 183 | PsiConcatenationUtil.buildFormatString 转换json设置默认值可参考 184 | 185 | 186 | if (psi == null || !psi.isValid()) throw new PsiInvalidElementAccessException(psi); 判断psi是否有效 187 | 188 | 189 | PsiSearchHelper.SERVICE.getInstance() 190 | MethodChainsSearchUtil.getMethodWithMinNotPrimitiveParameters 191 | 192 | 193 | // service tree 显示正在加载 194 | // 点击某模块,只加载鼠标所在模块的服务? 195 | // 监听conroller变化 196 | // 研究spring requestmapping pattern,匹配真正的rest风格,pathvariable 197 | 判断是否为list: 198 | ((PsiClassReferenceType) psiFieldType).getReference().getReferenceNameElement().getText().contains("List") 199 | ((PsiClassReferenceType) psiFieldType).getCanonicalText().startwith(java.util.List) && psiFieldType.getSuperTypes() contains util.List 200 | 201 | 202 | JavaShortClassNameIndex.getInstance().get(shortClassName, project, GlobalSearchScope.moduleScope()) 203 | 204 | JavaShortClassNameIndex.getInstance().get("RetailPrice", project, GlobalSearchScope.projectScope(project)) 205 | 206 | JavaShortClassNameIndex.getInstance().get("RetailPrice", ((ModuleImpl) service.getModule()).myProject, GlobalSearchScope.moduleWithDependentsScope(service.module)) 207 | 208 | JavaShortClassNameIndex.getInstance().get("RetailPrice", , GlobalSearchScope.moduleWithDependenciesScope(service.module)) 209 | 210 | ======================= 211 | webflux: 212 | ((PsiMethodImpl) element).getReturnTypeElement() 返回值为 PsiTypeElement:RouterFunction 213 | ((PsiMethod)psiMethod).getReturnTypeElement().getText() 214 | ((PsiMethod)psiMethod).getReturnType().getCanonicalText() 215 | ((PsiMethod)psiMethod).getReturnTypeElement().getInnermostComponentReferenceElement().getQualifiedName() =="org.springframework.web.reactive.function.server.RouterFunction" 216 | 217 | =============================== 218 | 219 | 220 | ====================== 221 | # RestfulToolkit 222 | ## A toolkit for restful services development. 223 | 224 | * 1.*ONE STEP* to navigate to service declaration, support kotlin language. 225 | ( use: `Ctrl + \` or `Ctrl + Alt + N` ) 226 | * 2.Show rest service structure. 227 | * 3.A simple rest client tool. 228 | * 4.Add some useful functions at request method, 229 | "Generate&Copy Query Param", "Generate&Copy URL", etc. 230 | * 5.Other useful functions, "Convert to JSON" to java class,format json data 231 | *( *Windows*: `Ctrl + Enter`; *Mac*: `Command + Enter` ) . 232 | 233 | #### supported Spring framework (Spring MVC / Spring Boot) 234 | #### supported JAX-RS (dubbo 2.6+, dubbox, ) 235 | 236 | ------ 237 | ### 一套 Restful 服务开发辅助工具集。 238 | 239 | * 1.根据 URL 直接导航到对应的方法定义,支持 kotlin 语言。 ( `Ctrl \` or `Ctrl Alt N` ); 240 | * 2.提供了一个 Services tree 的显示窗口; 241 | * 3.一个简单的 Rest client 工具; 242 | * 4.在 Controller 方法上添加了 "复制生成 URL","复制方法参数","复制生成 JSON" (方法参数中存在 RequestBody 注解) 等几个功能; 243 | * 5.其他一些个人觉得有用的小功能, java 类上添加 "Convert to JSON" 功能,格式化 json 数据 ( *Windows*: `Ctrl + Enter`; *Mac*: `Command + Enter` )。 244 | 245 | #### 支持 Spring 体系 (Spring MVC / Spring Boot) 246 | #### 支持 JAX-RS (dubbo 2.6+, dubbox, ) 247 | ------------ 248 | 249 | @Consumes("application/json") 250 | // 设置接收数据格式 251 | @Produces("application/json") 252 | 253 | 254 | ============== 255 | 创建方法,自动添加注释; 256 | 复制到Service DAO, 能不能做成同步的(提示是否自动创建Service DAO 方法,记住选项) 257 | (定位 service dao,创建方法,不判断是否存在相同方法) 258 | 259 | http://www.jetbrains.org/intellij/sdk/docs/basics/psi_cookbook.html 260 | 261 | ================== 262 | RequstMapping: 263 | 1,继承 264 | 2,子类controller 未标注,继承父类 265 | 3,只匹配设置了 requestmapping 的方法 266 | 4, 267 | 268 | ============================ 269 | copy full url 270 | 271 | ========== 272 | gen http 273 | 274 | 275 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/spring/RequestMappingAnnotationHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common.spring; 2 | 3 | 4 | import com.intellij.psi.*; 5 | import com.zhaow.restful.annotations.PathMappingAnnotation; 6 | import com.zhaow.restful.annotations.SpringRequestMethodAnnotation; 7 | import com.zhaow.restful.common.PsiAnnotationHelper; 8 | import com.zhaow.restful.common.RestSupportedAnnotationHelper; 9 | import com.zhaow.restful.method.RequestPath; 10 | import org.apache.commons.lang.StringUtils; 11 | 12 | import java.util.ArrayList; 13 | import java.util.Arrays; 14 | import java.util.List; 15 | import java.util.stream.Collectors; 16 | 17 | public class RequestMappingAnnotationHelper implements RestSupportedAnnotationHelper { 18 | 19 | 20 | /** 21 | * 过滤所有注解 22 | * @param psiClass 23 | * @return 24 | */ 25 | public static List getRequestPaths(PsiClass psiClass) { 26 | PsiAnnotation[] annotations = psiClass.getModifierList().getAnnotations(); 27 | 28 | PsiAnnotation requestMappingAnnotation = null; 29 | List list = new ArrayList<>(); 30 | for (PsiAnnotation annotation : annotations) { 31 | for (SpringRequestMethodAnnotation mappingAnnotation : SpringRequestMethodAnnotation.values()) { 32 | if (annotation.getQualifiedName().equals(mappingAnnotation.getQualifiedName())) { 33 | requestMappingAnnotation = annotation; 34 | } 35 | } 36 | } 37 | 38 | if (requestMappingAnnotation != null) { 39 | List requestMappings = getRequestMappings(requestMappingAnnotation, ""); 40 | if (requestMappings.size() > 0) { 41 | list.addAll(requestMappings); 42 | } 43 | } else { 44 | // TODO : 继承 RequestMapping 45 | PsiClass superClass = psiClass.getSuperClass(); 46 | if (superClass != null && !superClass.getQualifiedName().equals("java.lang.Object")) { 47 | list = getRequestPaths(superClass); 48 | } else { 49 | list.add(new RequestPath("/", null)); 50 | } 51 | 52 | } 53 | 54 | return list; 55 | } 56 | 57 | public static String[] getRequestMappingValues(PsiClass psiClass) { 58 | PsiAnnotation[] annotations = psiClass.getModifierList().getAnnotations(); 59 | if (annotations == null) return null; 60 | 61 | for (PsiAnnotation annotation : annotations) { 62 | if (annotation.getQualifiedName().equals(SpringRequestMethodAnnotation.REQUEST_MAPPING.getQualifiedName())) { 63 | return getRequestMappingValues(annotation); 64 | } 65 | /* //fixme: mac 下 annotation.getQualifiedName() 不是完整路径 ? 66 | if (annotation.getQualifiedName().equals(requestMapping.getShortName())) { 67 | return getRequestMappingValues(annotation); 68 | }*/ 69 | } 70 | 71 | return new String[]{"/"}; 72 | } 73 | 74 | /** 75 | * @param annotation 76 | * @param defaultValue 77 | * @return 78 | */ 79 | private static List getRequestMappings(PsiAnnotation annotation, String defaultValue) { 80 | List mappingList = new ArrayList<>(); 81 | 82 | List methodList = PsiAnnotationHelper.getAnnotationAttributeValues(annotation, "method"); 83 | 84 | List pathList = PsiAnnotationHelper.getAnnotationAttributeValues(annotation, "value"); 85 | if (pathList.size() == 0) { 86 | pathList = PsiAnnotationHelper.getAnnotationAttributeValues(annotation, "path"); 87 | } 88 | 89 | // 没有设置 value,默认方法名 90 | if (pathList.size() == 0) { 91 | pathList.add(defaultValue); 92 | } 93 | 94 | // todo: 处理没有设置 value 或 path 的 RequestMapping 95 | 96 | // List finalPathList = pathList; 97 | // methodList.forEach(method-> finalPathList.forEach(path->mappingList.add(new RequestMapping(path,method)))); 98 | 99 | if (methodList.size() > 0) { 100 | for (String method : methodList) { 101 | for (String path : pathList) { 102 | mappingList.add(new RequestPath(path, method)); 103 | } 104 | } 105 | } else { 106 | for (String path : pathList) { 107 | mappingList.add(new RequestPath(path, null)); 108 | } 109 | } 110 | 111 | return mappingList; 112 | } 113 | 114 | /** 115 | * 过滤所有注解 116 | * 117 | * @param psiMethod 118 | * @return 119 | */ 120 | public static RequestPath[] getRequestPaths(PsiMethod psiMethod) { 121 | PsiAnnotation[] annotations = psiMethod.getModifierList().getAnnotations(); 122 | 123 | if (annotations == null) return null; 124 | List list = new ArrayList<>(); 125 | 126 | for (PsiAnnotation annotation : annotations) { 127 | for (SpringRequestMethodAnnotation mappingAnnotation : SpringRequestMethodAnnotation.values()) { 128 | // for (PathMappingAnnotation mappingAnnotation : PathMappingAnnotation.allPathMappingAnnotations) { 129 | if (mappingAnnotation.getQualifiedName().endsWith(annotation.getQualifiedName())) { 130 | 131 | // String defaultValue = psiMethod.getName(); 132 | String defaultValue = "/"; 133 | List requestMappings = getRequestMappings(annotation, defaultValue); 134 | if (requestMappings.size() > 0) { 135 | list.addAll(requestMappings); 136 | } 137 | } 138 | } 139 | } 140 | 141 | return list.toArray(new RequestPath[list.size()]); 142 | } 143 | 144 | 145 | private static String getRequestMappingValue(PsiAnnotation annotation) { 146 | String value = PsiAnnotationHelper.getAnnotationAttributeValue(annotation, "value"); 147 | 148 | // String value = psiAnnotationMemberValue.getText().replace("\"",""); 149 | // if(psiAnnotationMemberValue.) 150 | 151 | if (StringUtils.isEmpty(value)) 152 | value = PsiAnnotationHelper.getAnnotationAttributeValue(annotation, "path"); 153 | return value; 154 | } 155 | 156 | public static String[] getRequestMappingValues(PsiAnnotation annotation) { 157 | String[] values; 158 | //一个value class com.intellij.psi.impl.source.tree.java.PsiLiteralExpressionImpl 159 | //多个value class com.intellij.psi.impl.source.tree.java.PsiArrayInitializerMemberValueImpl 160 | PsiAnnotationMemberValue attributeValue = annotation.findDeclaredAttributeValue("value"); 161 | 162 | if (attributeValue instanceof PsiLiteralExpression) { 163 | 164 | return new String[]{((PsiLiteralExpression) attributeValue).getValue().toString()}; 165 | } 166 | if (attributeValue instanceof PsiArrayInitializerMemberValue) { 167 | PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue) attributeValue).getInitializers(); 168 | values = new String[initializers.length]; 169 | 170 | for (PsiAnnotationMemberValue initializer : initializers) { 171 | 172 | } 173 | 174 | for (int i = 0; i < initializers.length; i++) { 175 | values[i] = ((PsiLiteralExpression) (initializers[i])).getValue().toString(); 176 | } 177 | } 178 | 179 | return new String[]{}; 180 | } 181 | 182 | 183 | public static String getOneRequestMappingPath(PsiClass psiClass) { 184 | // todo: 有必要 处理 PostMapping,GetMapping 么? 185 | PsiAnnotation annotation = psiClass.getModifierList().findAnnotation(SpringRequestMethodAnnotation.REQUEST_MAPPING.getQualifiedName()); 186 | 187 | String path = null; 188 | if (annotation != null) { 189 | path = RequestMappingAnnotationHelper.getRequestMappingValue(annotation); 190 | } 191 | 192 | return path != null ? path : ""; 193 | } 194 | 195 | 196 | public static String getOneRequestMappingPath(PsiMethod psiMethod) { 197 | // System.out.println("psiMethod:::::::" + psiMethod); 198 | SpringRequestMethodAnnotation requestAnnotation = null; 199 | 200 | List springRequestAnnotations = Arrays.stream(SpringRequestMethodAnnotation.values()).filter(annotation -> 201 | psiMethod.getModifierList().findAnnotation(annotation.getQualifiedName()) != null 202 | ).collect(Collectors.toList()); 203 | 204 | /* if (springRequestAnnotations.size() == 0) { 205 | requestAnnotation = null; 206 | }*/ 207 | 208 | if (springRequestAnnotations.size() > 0) { 209 | requestAnnotation = springRequestAnnotations.get(0); 210 | } 211 | 212 | String mappingPath; 213 | if (requestAnnotation != null) { 214 | PsiAnnotation annotation = psiMethod.getModifierList().findAnnotation(requestAnnotation.getQualifiedName()); 215 | mappingPath = RequestMappingAnnotationHelper.getRequestMappingValue(annotation); 216 | } else { 217 | String methodName = psiMethod.getName(); 218 | mappingPath = StringUtils.uncapitalize(methodName); 219 | } 220 | 221 | return mappingPath; 222 | } 223 | 224 | 225 | } -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/common/RequestHelper.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.common; 2 | 3 | import com.zhaow.utils.JsonUtils; 4 | import org.apache.http.HttpEntity; 5 | import org.apache.http.client.ClientProtocolException; 6 | import org.apache.http.client.entity.UrlEncodedFormEntity; 7 | import org.apache.http.client.methods.*; 8 | import org.apache.http.entity.StringEntity; 9 | import org.apache.http.impl.client.CloseableHttpClient; 10 | import org.apache.http.impl.client.HttpClients; 11 | import org.apache.http.message.BasicNameValuePair; 12 | import org.apache.http.util.EntityUtils; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.io.IOException; 16 | import java.io.UnsupportedEncodingException; 17 | import java.nio.charset.Charset; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | 22 | public class RequestHelper { 23 | 24 | 25 | public static String request(String url, String method) { 26 | if (method == null) { 27 | return "method is null"; 28 | } 29 | if (!url.startsWith("http://") && !url.startsWith("https://")) { 30 | url = "http://" + url; 31 | } 32 | 33 | switch (method.toUpperCase()) { 34 | case "GET": return get(url); 35 | case "POST": return post(url); 36 | case "PUT": return put(url); 37 | case "DELETE": return delete(url); 38 | default:return "not supported method : "+method + "."; 39 | } 40 | 41 | } 42 | 43 | public static String get(String url) { 44 | CloseableHttpResponse response = null; 45 | CloseableHttpClient httpClient = HttpClients.createDefault(); 46 | HttpGet httpMethod = new HttpGet(completed(url)); 47 | String result = null; 48 | try { 49 | response = httpClient.execute(httpMethod); 50 | HttpEntity entity = response.getEntity(); 51 | 52 | result = toString(entity); 53 | // System.out.println(response.getStatusLine().getStatusCode()); 54 | } catch (UnsupportedEncodingException e) { 55 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 56 | e.printStackTrace(); 57 | } catch (ClientProtocolException e) { 58 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 59 | e.printStackTrace(); 60 | } catch (IOException e) { 61 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 62 | e.printStackTrace(); 63 | } finally { 64 | release(response, httpClient); 65 | } 66 | 67 | return result != null ? result : ""; 68 | } 69 | 70 | public static String post(String url) { 71 | List params = new ArrayList<>(); 72 | // params.add(new BasicNameValuePair("parameter2", "23456")); 73 | 74 | String result = null; 75 | 76 | CloseableHttpResponse response = null; 77 | CloseableHttpClient httpClient = HttpClients.createDefault(); 78 | try { 79 | HttpEntity httpEntity; 80 | httpEntity = new UrlEncodedFormEntity(params); 81 | //////////////////////////////////// 82 | 83 | HttpPost httpMethod = new HttpPost(completed(url)); 84 | httpMethod.setEntity(httpEntity); 85 | response = httpClient.execute(httpMethod); 86 | 87 | HttpEntity entity = response.getEntity(); 88 | result = toString(entity); 89 | // System.out.println(response.getStatusLine().getStatusCode()); 90 | } catch (UnsupportedEncodingException e) { 91 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 92 | e.printStackTrace(); 93 | } catch (ClientProtocolException e) { 94 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 95 | e.printStackTrace(); 96 | } catch (IOException e) { 97 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 98 | e.printStackTrace(); 99 | } finally { 100 | release(response, httpClient); 101 | } 102 | 103 | return result; 104 | } 105 | 106 | 107 | public static String put(String url) { 108 | String result; 109 | 110 | CloseableHttpResponse response = null; 111 | CloseableHttpClient httpClient = HttpClients.createDefault(); 112 | try { 113 | HttpPut httpMethod = new HttpPut(completed(url)); 114 | response = httpClient.execute(httpMethod); 115 | 116 | HttpEntity entity = response.getEntity(); 117 | result = toString(entity); 118 | // System.out.println(response.getStatusLine().getStatusCode()); 119 | } catch (UnsupportedEncodingException e) { 120 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 121 | e.printStackTrace(); 122 | } catch (ClientProtocolException e) { 123 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 124 | e.printStackTrace(); 125 | } catch (IOException e) { 126 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 127 | e.printStackTrace(); 128 | } finally { 129 | release(response, httpClient); 130 | } 131 | 132 | return result; 133 | } 134 | 135 | 136 | public static String delete(String url) { 137 | if (!url.startsWith("http://") && !url.startsWith("https://")) { 138 | url = "http://" + url; 139 | } 140 | 141 | String result ; 142 | 143 | CloseableHttpResponse response = null; 144 | CloseableHttpClient httpClient = HttpClients.createDefault(); 145 | try { 146 | HttpDelete httpMethod = new HttpDelete(url); 147 | response = httpClient.execute(httpMethod); 148 | 149 | HttpEntity entity = response.getEntity(); 150 | result = toString(entity); 151 | } catch (UnsupportedEncodingException e) { 152 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 153 | e.printStackTrace(); 154 | } catch (ClientProtocolException e) { 155 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 156 | e.printStackTrace(); 157 | } catch (IOException e) { 158 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 159 | e.printStackTrace(); 160 | } finally { 161 | release(response, httpClient); 162 | } 163 | 164 | return result; 165 | } 166 | 167 | 168 | public static String postRequestBodyWithJson(String url, String json) { 169 | 170 | CloseableHttpResponse response = null; 171 | CloseableHttpClient httpClient = HttpClients.createDefault(); 172 | 173 | HttpPost postMethod = new HttpPost(completed(url)); 174 | 175 | String result = null; 176 | try { 177 | StringEntity httpEntity = new StringEntity(json); 178 | 179 | httpEntity.setContentType("application/json"); 180 | httpEntity.setContentEncoding("UTF-8"); 181 | 182 | postMethod.addHeader("Content-type","application/json; charset=utf-8"); 183 | postMethod.setHeader("Accept", "application/json"); 184 | // postMethod.setEntity(new StringEntity(parameters, Charset.forName("UTF-8"))); 185 | postMethod.setEntity(httpEntity); //设置post请求实体 186 | 187 | response = httpClient.execute(postMethod); 188 | result = toString(response.getEntity()); 189 | 190 | } catch (UnsupportedEncodingException e) { 191 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 192 | // e.printStackTrace(); 193 | } catch (IOException e) { 194 | result = "There was an error accessing to URL: " + url + "\n\n" + e.toString(); 195 | // e.printStackTrace(); 196 | } finally { 197 | release(response, httpClient); 198 | } 199 | 200 | return result; 201 | } 202 | 203 | private static void release(CloseableHttpResponse response, CloseableHttpClient httpClient) { 204 | if (response != null) { 205 | try { 206 | response.close(); 207 | } catch (IOException e) { } 208 | } 209 | if (httpClient != null) { 210 | try { 211 | httpClient.close(); 212 | } catch (IOException e) { } 213 | } 214 | } 215 | 216 | private static String completed(String url) { 217 | if (!url.startsWith("http://") && !url.startsWith("https://")) { 218 | url = "http://" + url; 219 | } 220 | return url; 221 | } 222 | 223 | @NotNull 224 | private static String toString(HttpEntity entity) { 225 | String result = null; 226 | try { 227 | result = EntityUtils.toString(entity, Charset.forName("UTF-8")); 228 | 229 | } catch (IOException e) { 230 | e.printStackTrace(); 231 | } 232 | 233 | if(result != null && JsonUtils.isValidJson(result)) 234 | return JsonUtils.format(result); 235 | 236 | return ""; 237 | } 238 | 239 | 240 | } 241 | -------------------------------------------------------------------------------- /src/main/java/com/zhaow/restful/method/action/PropertiesHandler.java: -------------------------------------------------------------------------------- 1 | package com.zhaow.restful.method.action; 2 | 3 | 4 | import com.intellij.openapi.module.Module; 5 | import com.intellij.psi.PsiFile; 6 | import com.intellij.psi.search.FilenameIndex; 7 | import com.intellij.psi.search.GlobalSearchScope; 8 | import org.apache.commons.lang.StringUtils; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.yaml.snakeyaml.Yaml; 11 | 12 | import java.io.IOException; 13 | import java.io.StringReader; 14 | import java.util.*; 15 | // profile.active != null // YamlPropertySourceLoader extends PropertySourceLoader .load 16 | 17 | // PropertySourcesLoader.load 配置文件加载类 18 | // 路径location:[file:./config/, file:./, classpath:/config/, classpath:/] 19 | //文件name:bootstrap,application 20 | //后缀:[properties, xml, yml, yaml] 21 | //applicationConfig: [classpath:/application.yml]#prod 22 | 23 | // 如果存在 activeProfile spring.profiles.active 存在,判断是否存在 application-activeProfile. 文件, 24 | // 如果存在,判断是否存在设置,不存在则忽略 25 | //最终可能优先级 application.properties>application.yml>bootstrap.propertis>bootstrap.yml 26 | //路径:classpath:/(resource)>classpath:/config/ 27 | public class PropertiesHandler { 28 | 29 | public String[] getFileExtensions() { //优先级 30 | return new String[]{"properties", "yml"}; 31 | } 32 | 33 | public String[] getConfigFiles() { // 优先级 34 | return new String[]{"application", "bootstrap"}; 35 | } 36 | public List CONFIG_FILES = Arrays.asList("application", "bootstrap"); 37 | public List FILE_EXTENSIONS = Arrays.asList("properties", "yml"); 38 | 39 | String SPRING_PROFILE = "spring.profiles.active"; 40 | 41 | String placeholderPrefix = "${"; 42 | String valueSeparator = ":"; 43 | String placeholderSuffix = "}"; 44 | 45 | String activeProfile; 46 | 47 | Module module; 48 | 49 | public PropertiesHandler(Module module) { 50 | this.module = module; 51 | } 52 | 53 | public String getServerPort() { 54 | String port = null; 55 | String serverPortKey = "server.port"; 56 | 57 | activeProfile = findProfilePropertyValue(); 58 | 59 | // 60 | if (activeProfile != null) { 61 | port = findPropertyValue(serverPortKey, activeProfile); 62 | } 63 | if (port == null) { 64 | port = findPropertyValue(serverPortKey, null); 65 | } 66 | 67 | return port != null ? port : ""; 68 | } 69 | 70 | public String getProperty(String propertyKey) { 71 | String propertyValue = null; 72 | 73 | activeProfile = findProfilePropertyValue(); 74 | 75 | // 76 | if (activeProfile != null) { 77 | propertyValue = findPropertyValue(propertyKey, activeProfile); 78 | } 79 | if (propertyValue == null) { 80 | propertyValue = findPropertyValue(propertyKey, null); 81 | } 82 | 83 | return propertyValue != null ? propertyValue : ""; 84 | } 85 | 86 | 87 | 88 | /* try find spring.profiles.active value */ 89 | private String findProfilePropertyValue() { 90 | String activeProfile = findPropertyValue(SPRING_PROFILE, null); 91 | return activeProfile; 92 | } 93 | 94 | /* 暂时不考虑路径问题,默认找到的第一文件 */ 95 | private String findPropertyValue(String propertyKey,String activeProfile) { 96 | String value = null; 97 | String profile = activeProfile != null ? "-"+ activeProfile : ""; 98 | // 99 | for (String conf : getConfigFiles()) { 100 | for (String ext : getFileExtensions()) { 101 | // load spring config file 102 | String configFile = conf + profile + "." + ext; 103 | if (ext.equals("properties")) { 104 | Properties properties = loadProertiesFromConfigFile(configFile); 105 | if (properties != null) { 106 | Object valueObj = properties.getProperty(propertyKey); 107 | if (valueObj != null) { 108 | value = cleanPlaceholderIfExist((String)valueObj); 109 | return value; 110 | } 111 | } 112 | 113 | } else if(ext.equals("yml") || ext.equals("yaml")) { 114 | Map propertiesMap = getPropertiesMapFromYamlFile(configFile); 115 | if (propertiesMap != null) { 116 | Object valueObj = propertiesMap.get(propertyKey); 117 | if (valueObj == null) return null; 118 | 119 | if (valueObj instanceof String) { 120 | value = cleanPlaceholderIfExist((String)valueObj); 121 | }else{ 122 | value = valueObj.toString(); 123 | } 124 | return value; 125 | } 126 | } 127 | } 128 | } 129 | 130 | return value; 131 | } 132 | 133 | private Properties loadProertiesFromConfigFile(String configFile) { 134 | Properties properties = null; 135 | PsiFile applicationPropertiesFile = findPsiFileInModule(configFile); 136 | if (applicationPropertiesFile != null) { 137 | properties = loadPropertiesFromText(applicationPropertiesFile.getText()); 138 | } 139 | return properties; 140 | } 141 | 142 | @NotNull 143 | private Properties loadPropertiesFromText(String text) { 144 | Properties prop = new Properties(); 145 | try { 146 | prop.load(new StringReader(text)); 147 | } catch (IOException e) { 148 | e.printStackTrace(); 149 | } 150 | return prop; 151 | } 152 | 153 | public String getContextPath() { 154 | String key = "server.context-path"; 155 | String contextPath = null; 156 | 157 | activeProfile = findProfilePropertyValue(); 158 | 159 | // 160 | if (activeProfile != null) { 161 | contextPath = findPropertyValue(key, activeProfile); 162 | } 163 | if (contextPath == null) { 164 | contextPath = findPropertyValue(key, null); 165 | } 166 | 167 | return contextPath != null ? contextPath : ""; 168 | 169 | } 170 | 171 | private String cleanPlaceholderIfExist(String value) { 172 | // server.port=${PORT:8080} 173 | if (value != null && value.contains(placeholderPrefix) && value.contains(valueSeparator)) { 174 | String[] split = value.split(valueSeparator); 175 | 176 | 177 | if (split.length > 1) { 178 | value = split[1].replace(placeholderSuffix, ""); 179 | } 180 | // value = value.replace(placeholderPrefix,"").replace(placeholderSuffix,""); 181 | } 182 | return value; 183 | } 184 | 185 | 186 | private Map getPropertiesMapFromYamlFile(String configFile) { 187 | PsiFile applicationPropertiesFile = findPsiFileInModule(configFile); 188 | if (applicationPropertiesFile != null) { 189 | Yaml yaml = new Yaml(); 190 | 191 | String yamlText = applicationPropertiesFile.getText(); 192 | try { 193 | Map ymlPropertiesMap = (Map) yaml.load(yamlText); 194 | return getFlattenedMap(ymlPropertiesMap); 195 | } catch (Exception e) { // FIXME: spring 同一个文件中配置多个环境时; yaml 格式不规范,比如包含 “---“ 196 | 197 | return null; 198 | } 199 | 200 | // Object yamlProperty = getYamlProperty(key, ymlPropertiesMap); 201 | } 202 | return null; 203 | } 204 | 205 | 206 | private PsiFile findPsiFileInModule(String fileName) { 207 | PsiFile psiFile = null; 208 | PsiFile[] applicationProperties = FilenameIndex.getFilesByName(module.getProject(), 209 | fileName, 210 | GlobalSearchScope.moduleScope(module)); 211 | 212 | if (applicationProperties.length > 0) { 213 | psiFile = applicationProperties[0]; 214 | } 215 | 216 | return psiFile; 217 | } 218 | 219 | /** 220 | * ref: org.springframework.beans.factory.config.YamlProcessor 221 | */ 222 | protected final Map getFlattenedMap(Map source) { 223 | Map result = new LinkedHashMap(); 224 | this.buildFlattenedMap(result, source, null); 225 | return result; 226 | } 227 | 228 | private void buildFlattenedMap(Map result, Map source, String path) { 229 | Iterator iterator = source.entrySet().iterator(); 230 | 231 | while(true) { 232 | while(iterator.hasNext()) { 233 | Map.Entry entry = (Map.Entry)iterator.next(); 234 | String key = entry.getKey(); 235 | if (StringUtils.isNotBlank(path)) { 236 | if (key.startsWith("[")) { 237 | key = path + key; 238 | } else { 239 | key = path + '.' + key; 240 | } 241 | } 242 | 243 | Object value = entry.getValue(); 244 | if (value instanceof String) { 245 | result.put(key, value); 246 | } else if (value instanceof Map) { 247 | Map map = (Map)value; 248 | this.buildFlattenedMap(result, map, key); 249 | } else if (value instanceof Collection) { 250 | Collection collection = (Collection)value; 251 | int count = 0; 252 | Iterator var10 = collection.iterator(); 253 | 254 | while(var10.hasNext()) { 255 | Object object = var10.next(); 256 | this.buildFlattenedMap(result, Collections.singletonMap("[" + count++ + "]", object), key); 257 | } 258 | } else { 259 | result.put(key, value != null ? value : ""); 260 | } 261 | } 262 | 263 | return; 264 | } 265 | } 266 | 267 | } 268 | --------------------------------------------------------------------------------