基于spring initilaizr快速搭建项目体系

基于spring initilaizr快速搭建项目体系

任何一家试图尝试微服务的公司都会碰到一个问题,那就是应用太多,灵活的应用带来的问题是数量多并难以规范。我们会采用代码规范来解决这个问题,但不可避免的需要在规范的搭建项目上花费更多的时间。因此这里产生了两个问题,第一如何快速的搭建项目,第二如何搭建符合自己规范的项目。

说到如何快速的搭建项目,我相信所有人的第一反应都应该是springboot,以简化Spring应用的搭建和开发过程为目的设计的springboot可以快速的完成一个项目的初始化并选择自己需要的功能组件。使用IDEA的用户可以通过Spring Initializr来连接springboot服务器便捷完成项目的搭建。同时Spring Initializr也支持本地自建服务器来完成搭建过程。

本文以Spring
initializr(https://github.com/spring-io/initializr.git) 0.5.0-RELEASE为基础展示如何快速的搭建一个符合自己规范的项目。

当clone了代码以后,发现项目包含以下几层目录。

—initializr-actuator
—initializr-docs
—initializr-generator
—initializr-service
—initializr-web

然后我们需要将项目启动起来,在根目录下执行./mvnw clean install完成核心的编译,然后到initializr-service目录下执行…/mvnw clean install 完成service层的编译,最后执行java -jar
target/initializr-service.jar –server.port=8031 启动服务器,当展示下图的时候,就完成了第一次的启动了。
运行结果
这个时候就可以通过Spring Initializr完成第一个项目搭建了,但是通过这种形式搭建的项目模型是一个单模型项目,对于企业开发来说太单薄了。因此我们需要自动动手,增加一个新的模式支持多模块项目。

从代码的角度,发现这个项目的逻辑很简单。如图

在这里插入图片描述

因此,我们需要做的就是新增一个项目类型,当生成新的目录层次的时候可以根据我们的要求来生成。检查代码可以发现创建目录这件事是由io.spring.initializr.generator.ProjectGenerator这个类负责的。当请求的项目类型为POM项目进来的时候会调用generateProjectStructure方法来生成目录结构,因此我们只要重写generateProjectStructure方法就可以完成我们自己的项目目录了,

public class MyProjectGenerator extends
ProjectGenerator {
 
private static final Logger log =
LoggerFactory.getLogger(MyProjectGenerator.class);
 
@Autowired
private TemplateRenderer templateRenderer = new TemplateRenderer();
 
@Override
protected Map<String, Object> resolveModel( ProjectRequest
request){
 
Map<String,Object> model = super.resolveModel(request);
model.put("managerModuleArtifactId",request.getName()+"-manager");
model.put("mavenParentArtifactId", request.getName());
model.put("mavenParentVersion", request.getVersion());
model.put("mavenParentGroupId", request.getGroupId());

return model;
}
 
@Override
protected File generateProjectStructure(ProjectRequest request,  Map<String, Object> model) {
       
File rootDir;
try {
            rootDir =
File.createTempFile("tmp", "", getTemporaryDirectory());
}catch (IOException e) {
throw new
IllegalStateException("Cannot create temp dir", e);
}
addTempFile(rootDir.getName(), rootDir);
rootDir.delete();
rootDir.mkdirs();

File dir = initializerProjectDir(rootDir, request);
generateGitIgnore(dir, request);
 
String pom = new String(doGenerateMavenProjectPom(model));
writeText(new File(dir, "pom.xml"), pom);
generatorModule(dir, request, model);

log.info("rootDir -->{}", rootDir);
return rootDir;
}
   
private void generatorModule(File dir, ProjectRequest request,
Map<String, Object> model){
 
File managerDir = new File(dir,
request.getName()+"-manager");
managerDir.mkdirs();
String pom = new String(doGenerateModelDalPom(model));
writeText(new File(managerDir, "pom.xml"), pom);
 
String codeLocation = request.getLanguage();
       
File src = new File(new File(new File(managerDir,
"src/main/" + codeLocation),request.getPackageName().replace(".", "/")),
"manager");
src.mkdirs();
       
//写入demo文件内容
write(new File(src, request.getApplicationName() +
"Manager.java"),
"myProject/ManagerApplication.java", model);
   
}

   
private byte[] doGenerateModelDalPom(Map<String, Object> model){
     
return templateRenderer.process("myProject/module-pom.xml",
model).getBytes();
   
}
}

创建MyProjectGenerator继承ProjectGenerator,然后重新generateProjectStructure,这样就能在临时目录下生成自己需要的项目结构了,然后通过重写resolveModel将自定义pom属性传递给模板文件,这里就是myProject/module-pom.xml就可以了。

接下来就是需要如何把自己需要的项目类型和依赖传递过来,在initializr-server的resources目录下有个application.yml 这个就是直接从idea看到的界面了。

在type目录下新增一个自己的项目就可以了

types:
- name: myProject
id: my-project
description: Generate a myProject Maven based project archive
sts-id: myProject.zip
tags:
build: maven
format: project
default: true
action: /myProject.zip

另外还可以新增一些dependencies,这样就可以在界面上看到自己的项目和需要选择的依赖项了。

最后需要增加接收到自定义请求之后的处理控制。在MainController中增加

public
MainController(InitializrMetadataProvider metadataProvider,TemplateRenderer templateRenderer,ResourceUrlProvider resourceUrlProvider, ProjectGenerator projectGenerator, MyProjectGenerator myProjectGenerator, DependencyMetadataProvider dependencyMetadataProvider) {
              super(metadataProvider, resourceUrlProvider);
              this.projectGenerator = projectGenerator;
              this.myProjectGenerator = myProjectGenerator;
              this.dependencyMetadataProvider = dependencyMetadataProvider;
              this.commandLineHelpGenerator = new CommandLineHelpGenerator(templateRenderer);
       }

@RequestMapping("/myProject.zip")
@ResponseBody
public
ResponseEntity<byte[]> springBestpayZip(BasicProjectRequest basicRequest)  throws IOException {
              ProjectRequest request = (ProjectRequest) basicRequest;
              File dir = myProjectGenerator.generateProjectStructure(request);
              File download = myProjectGenerator.createDistributionFile(dir, ".zip");
              String wrapperScript = getWrapperScript(request);
              new File(dir, wrapperScript).setExecutable(true);
              Zip zip = new Zip();
              zip.setProject(new Project());
              zip.setDefaultexcludes(false);
              ZipFileSet set = new ZipFileSet();
              set.setDir(dir);
              set.setFileMode("755");
              set.setIncludes(wrapperScript);
              set.setDefaultexcludes(false);
              zip.addFileset(set);
              set = new ZipFileSet();
              set.setDir(dir);
              set.setIncludes("**,");
              set.setExcludes(wrapperScript);
              set.setDefaultexcludes(false);
              zip.addFileset(set);
              zip.setDestFile(download.getCanonicalFile());
              zip.execute();

              ResponseEntity<byte[]> result =  upload(download, dir,generateFileName(request, "zip"), "application/zip");
              return result;

       }

并需要在InitializrAutoConfiguration中新增

 @Bean
 @ConditionalOnMissingBean
 public BestpayProjectGenerator bestpayProjectGenerator(){
              return new BestpayProjectGenerator();
}

并修改

@Bean
@ConditionalOnMissingBean
public
MainController initializrMainController( InitializrMetadataProvider
 metadataProvider,TemplateRenderer 
templateRenderer,ResourceUrlProvider
 resourceUrlProvider,ProjectGenerator
 projectGenerator, BestpayProjectGenerator bestpayProjectGenerator,DependencyMetadataProvider
 dependencyMetadataProvider) {
 	 return new MainController(metadataProvider, templateRenderer, resourceUrlProvider, 
projectGenerator,bestpayProjectGenerator, dependencyMetadataProvider);
}

当测试的时候的时候会发现会报清理临时文件报错,文件没有清理掉,检查代码的时候会发现是由于MyProjectGenerator在执行upload方法的时候调用了projectGenerator的清理方法cleanTempFiles,由于临时文件对象是作为一个私有属性导致,myProjectGenerator在执行清理的时候会为null。因此需要myProjectGenerator执行自己的cleanTempFiles方法。将upload方法中的cleanTempFiles移除,在mainController在执行完对应的上传之后,显示的执行一次cleanTempFiles方法

@RequestMapping("/myProject.zip")
@ResponseBody
public 
ResponseEntity<byte[]> springBestpayZip(BasicProjectRequest
basicRequest)throws
IOException {
              ProjectRequest
request = (ProjectRequest) basicRequest;
              File
dir = myProjectGenerator.generateProjectStructure(request);
 
              File
download = myProjectGenerator.createDistributionFile(dir, ".zip");
 
              String
wrapperScript = getWrapperScript(request);
              new
File(dir, wrapperScript).setExecutable(true);
              Zip
zip = new Zip();
              zip.setProject(new
Project());
              zip.setDefaultexcludes(false);
              ZipFileSet
set = new ZipFileSet();
              set.setDir(dir);
              set.setFileMode("755");
              set.setIncludes(wrapperScript);
              set.setDefaultexcludes(false);
              zip.addFileset(set);
              set
= new ZipFileSet();
              set.setDir(dir);
              set.setIncludes("**,");
              set.setExcludes(wrapperScript);
              set.setDefaultexcludes(false);
              zip.addFileset(set);
              zip.setDestFile(download.getCanonicalFile());
              zip.execute();
              ResponseEntity<byte[]>
result =  upload(download, dir,
generateFileName(request, "zip"), "application/zip");
              myProjectGenerator.cleanTempFiles(dir);
              return
result;
       }

至此其他人就可以连接你的服务,根据选择生成符合自己规范的项目结构了。

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值