玖叶教程网

前端编程开发入门

自定义Spring Initializr WebUI(自定义水印相机)

自定义Spring Start

缘由

  1. Maven渐渐老去

提到Java构建工具,经验丰富、聪明绝顶的开发者肯定是ANT、Maven、Gradle三连了。这里多扯一句,侠义的ANT只是构建工具,缺少依赖管理能力,必须加上它在Apache的好兄弟Ivy,联体才能发挥巨大威力。

不过,由于冗长的xml看的人昏昏欲睡,一点都不OOP。于是Apache家族的小兄弟Maven跳出来,提出了构建生命周期、仓库等概念,模块支持套娃,而且提供脚手架,码农盖房子就越来越快了。

java大家庭越来越繁荣,maven也如日中天。不过,由于在Maven中自定义任务实在不便,而且不能增量构建确实挺java,Gradle就开始发起攻击了。spring家族就渐渐开始上了Gradle的炕。哪知,Gradle犹抱琵琶半遮面下竟然有颗不小的麻子——Gradle没有脚手架。

  1. Spring补锅

不得已Spring家族做了个Spring Initializr,做完之后想不能只有CLI,要支持IDE,还要支持WebUI。

可不知当时哪只猫在发情期还怎么得,咖啡味道不行,导致Spring Start的开发语言使用了javascript。我估计咖啡里肯定有别的东西,不然用js就算了,还引入了node,差点就把我的老年电脑给炸死了。

刚上来,mvn test就编译出错,感情spring-initializr依赖没有安装到中央仓库?不急,自己本地有代码,想着在spring-initializr项目下先mvn install到本地,结果,测试代码不过。我可没那工夫改测试代码,直接“mvn clean install -DskipTests”安装再说。

然后回到spring-start继续,又发现安装node和yarn的frontend-maven-plugin存在问题,我amd64架构的win10 32位系统下载的node无法运行。想起之前安装过heroku,他用的就是node。于是把heroku的node复制到start.spring.io client模块下,并把要执行安装node和yarn的地方注释掉。

接着,又是下载依赖时提示ESOCKETTIMEOUT。好吧,那座众所周知的墙把速度限制到了10年前,那把“yarn build”的npmRegistryURL配置改成taobao(https://registry.npm.taobao.org)的吧。

然后,又提示node-gpy不存在,我可bilibili吧,node-gpy在node_modules/.bin下执行是ok的!简而言之,折腾一圈下来的体验就是“老子不伺候了”。

自己动手,丰衣足食

  1. 初窥设计

访问https://start.spring.io/ ,随便选些依赖,然后尝试generate和explore,发现都是请求“/starter.zip”(包括explore弹出框的download),示例请求如下:

https://start.spring.io/starter.zip?type=maven-project&language=java&bootVersion=2.4.2.RELEASE&baseDir=demo&groupId=com.example&artifactId=demo&name=demo&description=Demo%20project%20for%20Spring%20Boot&packageName=com.example.demo&packaging=jar&javaVersion=11&dependencies=lombok,web

查看starter源代码,可以看到三个子模块start-site-verification默认是没有被激活的,可以不管。剩下的start-client多是js代码,也先不看了。留下的start-site里有个StartApplication,懂Spring Boot的不用看就知道干什么的。

在web目录下有个HomeController,代码一眼就能看懂,就是跳转个到index.html。可这个模块根本没有这个文件,那大概率是前后分离,前端代码在start-client。在start-client的static目录下确实存在index.html,但内容根本就没引入js,估计是前端打包做成了单页面形式,或者将其它js打包进来。

由于我个人非专业前端,代码大概能看懂,可是要想改动就比较容易崩盘,于是直接把spring的页面下载下来,看能不能动点手脚吧。下载完后我就比较懵了,大屏大屏的未经格式化的css和svg,浏览器本地打开出错,generate和explore按钮完全没有响应。

只能祭出开发者工具栏,刷新一下,发现首页后的请求有一个是" https://start.spring.io/metadata/client ",接着是“ https://www.google-analytics.com/j/collect ”。Google分析的脚本就完全可以不看了,回到spring initializr源码,搜下第一个请求,发现在initializr-web模块下的ProjectMetadataController。分析start-site,发现它运行时依赖start-client,而start-client有配置maven-resources-plugin,将public目录下的资源复制到输出目录下的classes/static子目录下。public目录估计是webpack或者node/yarn构建后的输出目录,暂时这么看。

  1. 重构

从前面得到的信息,我们可以做规划了。spring initializr完全可以重用,甚至可以把spring-start的部分代码放到initializr-web里去,但为了避免步子迈的太大扯着蛋,我们还是先把start-client的代码重写到start-site。

    • PoC

可以把下载的html改名成index.html,并把引用的js目录组织好,都放src/main/resources/static下,暂时不管字体下载报错问题,看看能否正常运行。

正常运行后,到start.spring.io,把缺失的字体下载下来,放到src/main/resources/static/fonts下,重启,观察字体是否能够正确下载。

字体下载正常后,发现有请求start.spring.io跨站失败的,发现是PWA用到的manifest指向了网站。我们生成项目代码模板一般都是台式电脑或者笔记本,想着干脆去掉。于是在index.html找到它,删除掉。

重启,访问无任何异常后,尝试直接生成或者浏览后下载,均可正常使用。

All is well!

# 对于想直接使用的朋友,请通过链接下载: 
https://github.com/iMinusMinus/start.spring.io/releases/download/PoC/start-site-exec.jar 
    • 小步重构

index.html内容经过压缩了,引用的字体文件也被版本化了,引用的js可能被压缩合并了。我们可以首先格式化html代码,然后从html分离出css,接着将字体文件还原成原始名称(甚至需要添加回start-client里的字体,作为我们未覆盖情形的资源),之后尽可能匹配到未压缩的js,最后配置一个可选的混淆压缩过程来减少前端资源体积。

从start.spring.io利用浏览器格式化index.html,替换原先的html,没有困难。

index.html里的css就不好分离了,先跳过。

index.html里并没有引入字体,内容也少得可怜,看来是引入的js生成了内容。

先可以通过字体文件名搜索js。Easy,很快能定位到对应的js,作为一个混淆压缩的js,替换字体文件名还是相对简单,但是要还原js,就不好办了。

到start-client下看js内容,发现基本是使用React代码。

任务失败!

    • 个性化

简单的,每个企业有自身的技术偏好,比如不使用Kotlin和Groovy,只是用Java8,对于一些固定搭配,需要定制选项与默认值。

搜索下Groovy,可以发现它是在application.yml里定义的,通过增删相应配置与重设default属性就可以做到。

每个企业有自己的开发体系,比如有自己的框架,有自己固定的搭配方案,我们需要在依赖上进行定制化。如果刚才查看application.yml仔细的话,我们能发现依赖也是在此定义的:

initializr: 
  dependecies: 
    - name: spring-cloud-iamwhatiam # 可以对已存在的类型做编辑,也可以为自己企业单独增加类型 
       content: 
         - name: iamwhatiam-web # name展示在前端界面上,建议使用pom.xml中的project.name 
            id: iamwhatiam-web # web已经被spring web使用,建议使用pom.xml中的project.artifactId 
            description: Build Web using iamwhatiam framework # 描述会展示在前端界面上 
            facets: # initializr的ProjectContributor会用到facets信息,比如WebFoldersContributor在存在web这个facets时,会创建“src/main/resources/templates”和“src/main/resources/static”目录 
              - web 
              - json 
            links: 
              - rel: guide # 链接类型,比如guide指向使用示例,reference指向参考手册 
                href: http://iamwhatiam.ml/guide/framework description: 链接描述简短描述信息 
         - name: example 
            id: example 
            description: 单独管理版本示例 
            compatibilityRange: "[2.1.2, 2.5.0]" 
            mappings: 
              - compatibilityRange: "[2.1.2, 2.3.0)" 
                version: 1.0.0 
              - compatibilityRange: "[2.3.0, 2.5.0]" 
                version: 1.1.0 

由于框架版本不一定支持所有版本的Spring Boot,每个库都指明版本依赖又比较麻烦,我们可以统一配置。

# application.yml 
initializr: 
  env: 
    boms: 
      spring-cloud-iamwhatiam: 
        groupId: ml.iamwhatiam 
        artifactId: cloud-framework 
        versionProperty: spring-cloud-iamwhatiam.version 
        additionalBoms: [ spring-cloud ] # 可选,此处依赖会作为dependencyManagement一部分 
        mappings: # 指定范围内的spring boot版本,以及对应依赖的版本 
          - compatibilityRange: "[2.2.0, 2.4.4)" 
            version: 2.2.1.RELEASE

除此之外,每个企业采用的架构风格不一样,是传统的MVC,还是解决复杂业务场景又众说纷纭的DDD?我们需要对模块以及目录/包进行定制化。
此处方案见下回分晓。

发表评论:

控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言