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 extends RestServiceStructure.BaseSimpleNode> 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 extends RestServiceStructure.BaseSimpleNode> 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 extends RestServiceStructure.BaseSimpleNode> 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 |
--------------------------------------------------------------------------------