mirror of
https://gitee.com/dcren/cloud-native-app-initializer.git
synced 2025-04-04 23:39:35 +08:00
optmize classpath content loader (#60)
This commit is contained in:
parent
033ab83006
commit
e509820542
14
README-zh.md
14
README-zh.md
@ -6,25 +6,23 @@
|
||||
## 文档
|
||||
- [如何自定义内容](docs/howToCustom-zh.md)
|
||||
- [代码贡献](docs/CONTRIBUTING-zh.md)
|
||||
|
||||
- [常见问题](docs/faq-zh.md)
|
||||
|
||||
## 代码结构
|
||||
这是一个源自于 Spring Initializr 构建的云原生应用脚手架项目,你可以直接体验该项目的功能通过 [start.aliyun.com](https://start.aliyun.com/) ,项目本身包含以下模块:
|
||||
* initializer-generator: 脚手架生成项目模块,在其中`io.spring.start.site`目录下引用了部分 [start.spring.io](https://start.spring.io/) 的基础代码。
|
||||
* initializer-page: 脚手架前端页面
|
||||
* initializer-start: 脚手架启动、打包入口模块
|
||||
|
||||
## 基于源代码运行
|
||||
请在本地 clone 该项目,并确保具备 Java 17 环境。
|
||||
|
||||
### 构建项目
|
||||
|
||||
首先,确保 python 在您的环境中已经安装。在项目根目录,执行以下命令,安装 Node 和 Yarn:
|
||||
由于前端是以源码的形式存储与本项目中,需要使用yarn进行编译后,成为当前项目的资源文件,才能被正确访问:
|
||||
```shell
|
||||
mvn compile -P install-yarn
|
||||
```
|
||||
在项目根目录,执行以下命令,将静态文件 Copy 到 `initializer-generator` 模块的 target 中:
|
||||
```shell
|
||||
mvn prepare-package
|
||||
mvn process-sources
|
||||
```
|
||||
此步骤执行后,编译后的前端文件,会被复制到 `initializer-page/target/classes/static` 目录下
|
||||
|
||||
### 启动项目
|
||||
进入`initializer-generator` 模块,执行以下命令启动应用:
|
||||
|
7
docs/faq-zh.md
Normal file
7
docs/faq-zh.md
Normal file
@ -0,0 +1,7 @@
|
||||
# 常见问题
|
||||
|
||||
## MAC 系统前端无法编译
|
||||
对于使用了 Arm 架构(即使用了 M1、M2 处理器)的 Mac 电脑,由于 node 安装包没有适配 Arm 架构的 release 包,需要通过环境变量的方式让 Maven 认为在 x64 系统下运行:
|
||||
```bash
|
||||
mvn clean package -Dos.arch=x64
|
||||
```
|
@ -16,45 +16,27 @@
|
||||
|
||||
package com.alibaba.initializer.core.template.loader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.FileVisitOption;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.alibaba.initializer.core.constants.ErrorCodeEnum;
|
||||
import com.alibaba.initializer.core.exception.BizRuntimeException;
|
||||
import com.alibaba.initializer.core.template.CodeTemplate;
|
||||
import com.alibaba.initializer.core.template.CodeTemplateRepo;
|
||||
import com.alibaba.initializer.core.template.CodeTemplateRepoLoader;
|
||||
import com.google.common.collect.Lists;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
|
||||
import static org.springframework.util.ResourceUtils.JAR_URL_SEPARATOR;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* load template file from classpath
|
||||
*
|
||||
@ -72,12 +54,13 @@ public class ClasspathTemplateLoader implements CodeTemplateRepoLoader {
|
||||
try {
|
||||
URI uri = new URI(uriStr);
|
||||
|
||||
Resource[] resources = resourceLoader.getResources(CLASSPAHT_PREFIX + uri.getPath());
|
||||
Path rootPath = Paths.get(uri.getPath());
|
||||
|
||||
Resource[] resources = resourceLoader.getResources(CLASSPAHT_PREFIX + rootPath + "/**");
|
||||
|
||||
List<CodeTemplate> templates = Arrays.stream(resources)
|
||||
.filter(Resource::exists)
|
||||
.map(this::scanTemplte)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(Resource::isReadable)
|
||||
.map(item -> toTemplate(item, rootPath))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return new CodeTemplateRepo(uri, templates);
|
||||
@ -86,99 +69,23 @@ public class ClasspathTemplateLoader implements CodeTemplateRepoLoader {
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private List<CodeTemplate> scanTemplte(Resource resource) {
|
||||
List<CodeTemplate> templates = Lists.newArrayList();
|
||||
private CodeTemplate toTemplate(Resource resource, Path scanRootPath) {
|
||||
|
||||
URL url = resource.getURL();
|
||||
try {
|
||||
URL url = resource.getURL();
|
||||
|
||||
if (ResourceUtils.isFileURL(url)) {
|
||||
visitFileSystem(templates::add, resource);
|
||||
} else if (ResourceUtils.isJarURL(url)) {
|
||||
visitJarSystem(templates::add, resource);
|
||||
}
|
||||
String urlFile = url.getFile();
|
||||
|
||||
return templates;
|
||||
}
|
||||
int separatorIndex = urlFile.lastIndexOf(JAR_URL_SEPARATOR);
|
||||
|
||||
private void visitFileSystem(TempFileVisitor visitor, Resource resource)
|
||||
throws IOException {
|
||||
if (!resource.isFile()) {
|
||||
return;
|
||||
}
|
||||
File rootFile = resource.getFile();
|
||||
Path scanRoot = Paths.get(rootFile.getAbsolutePath());
|
||||
Files.walkFileTree(scanRoot, EnumSet.of(FileVisitOption.FOLLOW_LINKS),
|
||||
Integer.MAX_VALUE, new FileVisitor<Path>() {
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir,
|
||||
BasicFileAttributes attrs) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path originPath,
|
||||
BasicFileAttributes attrs) {
|
||||
String fileName = originPath.getFileName().toString();
|
||||
|
||||
Path relativePath = originPath.subpath(scanRoot.getNameCount(),
|
||||
originPath.getNameCount());
|
||||
Path relativeFolderPath = relativePath.getNameCount() == 1
|
||||
? null
|
||||
: relativePath.subpath(0,
|
||||
relativePath.getNameCount() - 1);
|
||||
|
||||
visitor.visit(new CodeTemplate(relativeFolderPath, fileName) {
|
||||
@Override
|
||||
public Reader getReader() {
|
||||
try {
|
||||
return new FileReader(originPath.toFile());
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new BizRuntimeException(ErrorCodeEnum.SYSTEM_ERROR, "", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void visitJarSystem(TempFileVisitor visitor, Resource resource) throws IOException {
|
||||
URL url = resource.getURL();
|
||||
|
||||
URL jarUrl = ResourceUtils.extractJarFileURL(url);
|
||||
|
||||
JarFile jarFile = new JarFile(jarUrl.getFile());
|
||||
|
||||
Enumeration<JarEntry> entries = jarFile.entries();
|
||||
|
||||
String resourcePath = url.getFile();
|
||||
|
||||
// the scan root from jar file
|
||||
String scanRoot = resourcePath.substring(resourcePath.indexOf(JAR_URL_SEPARATOR) + JAR_URL_SEPARATOR.length());
|
||||
Path scanRootPath = Paths.get(scanRoot);
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
JarEntry entry = entries.nextElement();
|
||||
|
||||
// the full name of jar entry
|
||||
String entryName = entry.getName();
|
||||
if (!entryName.startsWith(scanRoot) || entry.isDirectory()) {
|
||||
continue;
|
||||
if (separatorIndex > -1) {
|
||||
urlFile = urlFile.substring(separatorIndex + 1);
|
||||
} else {
|
||||
String classpathPath = ClasspathTemplateLoader.class.getProtectionDomain().getCodeSource().getLocation().getPath();
|
||||
urlFile = urlFile.startsWith(classpathPath) ? urlFile.replace(classpathPath, "/") : urlFile;
|
||||
}
|
||||
|
||||
Path entryPath = Paths.get(entryName);
|
||||
Path entryPath = Paths.get(urlFile);
|
||||
String fileName = entryPath.getFileName().toString();
|
||||
|
||||
Path relativePath = entryPath.subpath(scanRootPath.getNameCount(), entryPath.getNameCount());
|
||||
@ -187,25 +94,17 @@ public class ClasspathTemplateLoader implements CodeTemplateRepoLoader {
|
||||
: relativePath.subpath(0,
|
||||
relativePath.getNameCount() - 1);
|
||||
|
||||
visitor.visit(new CodeTemplate(relativeFolderPath, fileName) {
|
||||
@Override
|
||||
public Reader getReader() {
|
||||
try {
|
||||
return new InputStreamReader(resourceLoader.getResource("classpath:/" + entryPath.toString()).getInputStream());
|
||||
} catch (IOException e) {
|
||||
throw new BizRuntimeException(ErrorCodeEnum.SYSTEM_ERROR, "load resource error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
return new CodeTemplate(relativeFolderPath, fileName) {
|
||||
@Override
|
||||
public Reader getReader() throws IOException {
|
||||
return new InputStreamReader(resource.getInputStream());
|
||||
}
|
||||
};
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TempFileVisitor {
|
||||
void visit(CodeTemplate template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocol() {
|
||||
return "classpath";
|
||||
|
@ -54,7 +54,7 @@
|
||||
<executions>
|
||||
<execution>
|
||||
<id>copy-base-web-resource</id>
|
||||
<phase>prepare-package</phase>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>copy-resources</goal>
|
||||
</goals>
|
||||
|
@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright 2022-2023 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.alibaba.initializer.start.web;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
@Controller
|
||||
public class CommonPages {
|
||||
|
||||
@Autowired
|
||||
private ResourceLoader resourceLoader;
|
||||
|
||||
@GetMapping({"/checkpreload.htm", "nginx_status"})
|
||||
@ResponseBody
|
||||
public String checkPreload() {
|
||||
return "success";
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user