Browse Source

在jar中为只读模式、兼容spring boot

mxd 4 years ago
parent
commit
73796960d2

+ 46 - 32
src/main/java/org/ssssssss/magicapi/adapter/ResourceAdapter.java

@@ -3,6 +3,7 @@ package org.ssssssss.magicapi.adapter;
 import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 import org.springframework.util.ResourceUtils;
 import org.ssssssss.magicapi.utils.IoUtils;
+import org.ssssssss.magicapi.utils.PathUtils;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -21,6 +22,8 @@ public abstract class ResourceAdapter {
 
 	private static PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
 
+	private static final String SPRING_BOOT_CLASS_PATH = "BOOT-INF/classes/";
+
 	public static Resource getResource(String location) throws IOException {
 		if (location == null) {
 			return null;
@@ -30,7 +33,7 @@ public abstract class ResourceAdapter {
 			resource = resolver.getResource(location);
 			if (resource.exists()) {
 				return resolveResource(resource, true);
-			}else {
+			} else {
 				throw new FileNotFoundException(String.format("%s not found", resource.getDescription()));
 			}
 		} else {
@@ -43,20 +46,19 @@ public abstract class ResourceAdapter {
 	}
 
 	private static Resource resolveResource(org.springframework.core.io.Resource resource, boolean readonly) throws IOException {
-		URL url = resource.getURL();
+		URL url = resource.getURI().toURL();
 		if (url.getProtocol().equals(ResourceUtils.URL_PROTOCOL_JAR)) {
 			JarURLConnection connection = (JarURLConnection) url.openConnection();
-			String entryName = connection.getEntryName();
+			boolean springBootClassPath = connection.getClass().getName().equals("org.springframework.boot.loader.jar.JarURLConnection");
+			String entryName = (springBootClassPath ? SPRING_BOOT_CLASS_PATH : "") + connection.getEntryName();
 			JarFile jarFile = connection.getJarFile();
-			return new JarResource(jarFile, entryName, jarFile.getEntry(entryName), jarFile.stream()
-					.filter(it -> it.getName().startsWith(entryName))
-					.collect(Collectors.toList()));
+			List<JarEntry> entries = jarFile.stream().filter(it -> it.getName().startsWith(entryName)).collect(Collectors.toList());
+			return new JarResource(jarFile, entryName, entries, springBootClassPath);
 		} else {
 			return new FileResource(resource.getFile(), readonly);
 		}
 	}
 
-
 	private static class FileResource implements Resource {
 
 		private File file;
@@ -80,7 +82,7 @@ public abstract class ResourceAdapter {
 
 		@Override
 		public boolean delete() {
-			return IoUtils.delete(this.file);
+			return !readonly() && IoUtils.delete(this.file);
 		}
 
 		@Override
@@ -90,7 +92,7 @@ public abstract class ResourceAdapter {
 
 		@Override
 		public boolean mkdir() {
-			return this.file.mkdirs();
+			return !readonly() && this.file.mkdirs();
 		}
 
 		@Override
@@ -100,10 +102,12 @@ public abstract class ResourceAdapter {
 
 		@Override
 		public boolean renameTo(Resource resource) {
-			File target = ((FileResource) resource).file;
-			if (this.file.renameTo(target)) {
-				this.file = target;
-				return true;
+			if (!this.readonly()) {
+				File target = ((FileResource) resource).file;
+				if (this.file.renameTo(target)) {
+					this.file = target;
+					return true;
+				}
 			}
 			return false;
 		}
@@ -136,21 +140,21 @@ public abstract class ResourceAdapter {
 
 		@Override
 		public boolean write(byte[] bytes) {
-			return IoUtils.write(this.file, bytes);
+			return !readonly() && IoUtils.write(this.file, bytes);
 		}
 
 		@Override
 		public boolean write(String content) {
-			return IoUtils.write(this.file, content);
+			return !readonly() && IoUtils.write(this.file, content);
 		}
 
 		@Override
 		public List<Resource> files(String suffix) {
-			return IoUtils.files(this.file, suffix).stream().map(it -> new FileResource(it,this.readonly)).collect(Collectors.toList());
+			return IoUtils.files(this.file, suffix).stream().map(it -> new FileResource(it, this.readonly)).collect(Collectors.toList());
 		}
 
 		@Override
-		public String getAbsolutePath(){
+		public String getAbsolutePath() {
 			return this.file.getAbsolutePath();
 		}
 
@@ -172,15 +176,18 @@ public abstract class ResourceAdapter {
 
 		private JarResource parent = this;
 
-		public JarResource(JarFile jarFile, String entryName, ZipEntry entry, List<JarEntry> entries) {
+		private boolean inSpringBoot;
+
+		public JarResource(JarFile jarFile, String entryName, List<JarEntry> entries, boolean inSpringBoot) {
 			this.jarFile = jarFile;
 			this.entryName = entryName;
-			this.entry = entry;
+			this.inSpringBoot = inSpringBoot;
+			this.entry = getEntry(this.entryName);
 			this.entries = entries;
 		}
 
-		public JarResource(JarFile jarFile, String entryName, ZipEntry entry, List<JarEntry> entries, JarResource parent) {
-			this(jarFile, entryName, entry, entries);
+		public JarResource(JarFile jarFile, String entryName, List<JarEntry> entries, JarResource parent, boolean inSpringBoot) {
+			this(jarFile, entryName, entries, inSpringBoot);
 			this.parent = parent;
 		}
 
@@ -208,11 +215,20 @@ public abstract class ResourceAdapter {
 			return this.entry != null;
 		}
 
+		protected ZipEntry getEntry(String name) {
+			if (inSpringBoot && name.startsWith(SPRING_BOOT_CLASS_PATH)) {
+				name = name.substring(SPRING_BOOT_CLASS_PATH.length());
+			}
+			return this.jarFile.getEntry(name);
+		}
+
 		@Override
 		public Resource getResource(String name) {
-			String entryName = this.entryName + "/" + name;
-			String prefix = this.entryName + "/";
-			return new JarResource(this.jarFile, entryName, this.jarFile.getEntry(entryName), entries.stream().filter(it -> it.getName().startsWith(prefix)).collect(Collectors.toList()),this);
+			String entryName = PathUtils.replaceSlash(this.entryName + "/" + name);
+			String prefix = PathUtils.replaceSlash(entryName + "/");
+			return new JarResource(this.jarFile, entryName, entries.stream()
+					.filter(it -> it.getName().startsWith(prefix))
+					.collect(Collectors.toList()), this, this.inSpringBoot);
 		}
 
 		@Override
@@ -228,26 +244,24 @@ public abstract class ResourceAdapter {
 
 		@Override
 		public List<Resource> dirs() {
-			List<Resource> resources = resources();
-			resources.stream().filter(Resource::isDirectory).map(Resource::dirs).forEach(resources::addAll);
-			return resources;
+			return resources().stream().filter(Resource::isDirectory).collect(Collectors.toList());
 		}
 
 		@Override
 		public List<Resource> files(String suffix) {
 			return this.entries.stream().filter(it -> it.getName().endsWith(suffix))
-					.map(entry -> new JarResource(jarFile, entry.getName(), entry, Collections.emptyList()))
+					.map(entry -> new JarResource(jarFile, entry.getName(), Collections.emptyList(), this.inSpringBoot))
 					.collect(Collectors.toList());
 		}
 
 		@Override
 		public List<Resource> resources() {
-			String prefix = this.entryName + "/";
+			String prefix = PathUtils.replaceSlash(this.entryName + "/");
 			return entries.stream()
 					.filter(it -> it.getName().startsWith(prefix))
-					.map(entry -> new JarResource(jarFile, entry.getName(), entry, entries.stream()
-							.filter(item -> item.getName().startsWith(entry.getName() + "/"))
-							.collect(Collectors.toList()))
+					.map(entry -> new JarResource(jarFile, entry.getName(), entries.stream()
+							.filter(item -> item.getName().startsWith(PathUtils.replaceSlash(entry.getName() + "/")))
+							.collect(Collectors.toList()), this.inSpringBoot)
 					)
 					.collect(Collectors.toList());
 		}

+ 11 - 0
src/main/java/org/ssssssss/magicapi/config/MagicConfiguration.java

@@ -1,6 +1,7 @@
 package org.ssssssss.magicapi.config;
 
 import org.springframework.http.converter.HttpMessageConverter;
+import org.ssssssss.magicapi.adapter.Resource;
 import org.ssssssss.magicapi.controller.RequestHandler;
 import org.ssssssss.magicapi.interceptor.RequestInterceptor;
 import org.ssssssss.magicapi.provider.ApiServiceProvider;
@@ -75,6 +76,8 @@ public class MagicConfiguration {
 	 */
 	private ResultProvider resultProvider;
 
+	private Resource workspace;
+
 	private List<HttpMessageConverter<?>> httpMessageConverters = new ArrayList<>();
 
 	/**
@@ -208,6 +211,14 @@ public class MagicConfiguration {
 		this.editorConfig = editorConfig;
 	}
 
+	public Resource getWorkspace() {
+		return workspace;
+	}
+
+	public void setWorkspace(Resource workspace) {
+		this.workspace = workspace;
+	}
+
 	/**
 	 * 打印banner
 	 */

+ 1 - 2
src/main/java/org/ssssssss/magicapi/config/MappingHandlerMapping.java

@@ -123,11 +123,10 @@ public class MappingHandlerMapping {
 	 * @param requestMapping 请求路径
 	 */
 	private static String buildMappingKey(String requestMethod, String requestMapping) {
-
 		if (!StringUtils.isEmpty(requestMapping) && !requestMapping.startsWith("/")) {
 			requestMapping = "/" + requestMapping;
 		}
-		return requestMethod.toUpperCase() + ":" + requestMapping;
+		return Objects.toString(requestMethod, "GET").toUpperCase() + ":" + requestMapping;
 	}
 
 	public void setRequestMappingHandlerMapping(RequestMappingHandlerMapping requestMappingHandlerMapping) {

+ 9 - 0
src/main/java/org/ssssssss/magicapi/controller/MagicAPIController.java

@@ -37,6 +37,9 @@ public class MagicAPIController extends MagicController {
 	@RequestMapping("/delete")
 	@ResponseBody
 	public JsonBean<Boolean> delete(String id, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法删除");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
 			return new JsonBean<>(-10, "无权限执行删除方法");
 		}
@@ -91,6 +94,9 @@ public class MagicAPIController extends MagicController {
 	@RequestMapping("/api/move")
 	@ResponseBody
 	public JsonBean<Boolean> apiMove(String id, String groupId, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法移动");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
 			return new JsonBean<>(-10, "无权限执行保存方法");
 		}
@@ -120,6 +126,9 @@ public class MagicAPIController extends MagicController {
 	@RequestMapping("/save")
 	@ResponseBody
 	public JsonBean<String> save(HttpServletRequest request, ApiInfo info) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法保存");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
 			return new JsonBean<>(-10, "无权限执行保存方法");
 		}

+ 9 - 0
src/main/java/org/ssssssss/magicapi/controller/MagicFunctionController.java

@@ -53,6 +53,9 @@ public class MagicFunctionController extends MagicController {
 	@RequestMapping("/function/move")
 	@ResponseBody
 	public JsonBean<Boolean> move(String id, String groupId, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法移动");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
 			return new JsonBean<>(-10, "无权限执行移动函数");
 		}
@@ -75,6 +78,9 @@ public class MagicFunctionController extends MagicController {
 	@RequestMapping("/function/save")
 	@ResponseBody
 	public JsonBean<String> save(FunctionInfo functionInfo, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法保存");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
 			return new JsonBean<>(-10, "无权限执行保存方法");
 		}
@@ -117,6 +123,9 @@ public class MagicFunctionController extends MagicController {
 	@RequestMapping("/function/delete")
 	@ResponseBody
 	public JsonBean<Boolean> delete(String id, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法删除");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
 			return new JsonBean<>(-10, "无权限执行删除方法");
 		}

+ 9 - 0
src/main/java/org/ssssssss/magicapi/controller/MagicGroupController.java

@@ -34,6 +34,9 @@ public class MagicGroupController extends MagicController {
 	@RequestMapping("/group/delete")
 	@ResponseBody
 	public JsonBean<Boolean> deleteGroup(String groupId, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法删除");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.DELETE)) {
 			return new JsonBean<>(-10, "无权限执行删除方法");
 		}
@@ -81,6 +84,9 @@ public class MagicGroupController extends MagicController {
 	@RequestMapping("/group/update")
 	@ResponseBody
 	public synchronized JsonBean<Boolean> groupUpdate(Group group, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法修改");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
 			return new JsonBean<>(-10, "无权限执行删除方法");
 		}
@@ -138,6 +144,9 @@ public class MagicGroupController extends MagicController {
 	@RequestMapping("/group/create")
 	@ResponseBody
 	public JsonBean<String> createGroup(Group group, HttpServletRequest request) {
+		if(configuration.getWorkspace().readonly()){
+			return new JsonBean<>(0, "当前为只读模式,无法创建");
+		}
 		if (!allowVisit(request, RequestInterceptor.Authorization.SAVE)) {
 			return new JsonBean<>(-10, "无权限执行保存方法");
 		}

+ 1 - 1
src/main/java/org/ssssssss/magicapi/model/ApiInfo.java

@@ -15,7 +15,7 @@ public class ApiInfo extends MagicEntity{
 	/**
 	 * 请求方法
 	 */
-	private String method;
+	private String method = "GET";
 
 	/**
 	 * 请求路径

+ 2 - 1
src/main/java/org/ssssssss/magicapi/provider/StoreServiceProvider.java

@@ -4,6 +4,7 @@ import org.ssssssss.magicapi.adapter.Resource;
 import org.ssssssss.magicapi.model.MagicEntity;
 import org.ssssssss.magicapi.utils.JsonUtils;
 
+import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -183,7 +184,7 @@ public abstract class StoreServiceProvider<T extends MagicEntity> {
 	}
 
 	public T deserialize(byte[] data){
-		String content = new String(data);
+		String content = new String(data, StandardCharsets.UTF_8);
 		int index = content.indexOf(separator);
 		if (index > -1) {
 			T info = JsonUtils.readValue(content.substring(0, index), clazz);

+ 0 - 4
src/main/java/org/ssssssss/magicapi/utils/ClassScanner.java

@@ -169,8 +169,4 @@ public class ClassScanner {
 	private static boolean isClass(String className) {
 		return className.endsWith(".class") && !className.contains("$");
 	}
-
-	public static void main(String[] args) throws URISyntaxException {
-		scan().stream().filter(s -> s.startsWith("java.lang")).sorted().forEach(System.out::println);
-	}
 }

+ 10 - 9
src/main/java/org/ssssssss/magicapi/utils/IoUtils.java

@@ -1,6 +1,7 @@
 package org.ssssssss.magicapi.utils;
 
 import java.io.*;
+import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.List;
@@ -35,7 +36,7 @@ public class IoUtils {
 					list.addAll(subDirs(false, files[i]));
 				}
 			}
-			if(!isRoot){
+			if (!isRoot) {
 				list.add(file);
 			}
 		}
@@ -51,7 +52,7 @@ public class IoUtils {
 	}
 
 	public static String string(File file) {
-		return new String(bytes(file));
+		return new String(bytes(file), StandardCharsets.UTF_8);
 	}
 
 	public static byte[] bytes(InputStream inputStream) {
@@ -59,8 +60,8 @@ public class IoUtils {
 			ByteArrayOutputStream baos = new ByteArrayOutputStream();
 			byte[] buf = new byte[4096];
 			int len = -1;
-			while((len = inputStream.read(buf,0,buf.length)) != -1){
-				baos.write(buf,0,len);
+			while ((len = inputStream.read(buf, 0, buf.length)) != -1) {
+				baos.write(buf, 0, len);
 			}
 			return baos.toByteArray();
 		} catch (IOException e) {
@@ -69,19 +70,19 @@ public class IoUtils {
 	}
 
 	public static String string(InputStream inputStream) {
-		try(BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))){
+		try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
 			StringBuilder result = new StringBuilder();
 			String line;
 			boolean flag = false;
 			while ((line = reader.readLine()) != null) {
-				if(flag){
+				if (flag) {
 					result.append("\r\n");
 				}
 				result.append(line);
 				flag = true;
 			}
 			return result.toString();
-		}catch(IOException e){
+		} catch (IOException e) {
 			return "";
 		}
 	}
@@ -103,7 +104,7 @@ public class IoUtils {
 	}
 
 	public static boolean delete(File file) {
-		if(file == null){
+		if (file == null) {
 			return true;
 		}
 		if (file.isDirectory()) {
@@ -116,7 +117,7 @@ public class IoUtils {
 				}
 			}
 		}
-		if(!file.exists()){
+		if (!file.exists()) {
 			return true;
 		}
 		return file.delete();