作web插件,但大多数框架没有
我们需要使多个基于网络的项目具有许多共享功能。对此,某种插件系统将是一个很好的选择(作为复制粘贴材料的替代)。有些框架(如grails)可以选择制作web插件,但大多数框架没有,所以需要实现一些定制的插件。
首先,让我们定义所需的功能。“插件”:
- 应该简单地通过maven/ivy导入
- 如果使用依赖项注入容器,则应将所有类(自动或通过单行配置)注册到依赖项注入容器中。
- 应该是垂直的,即包含所有文件,从javascript、css和模板到控制器,再到服务层类。
- 不应要求从一个项目复制粘贴到另一个项目的复杂配置。
- 应该允许轻松开发和调试而不需要重新部署。
Java类被放入JAR文件并添加到lib目录中,因此添加到类路径中,因此这是简单的部分。但是我们需要将Web资源提取到相应的位置,在那里它们可以被代码的其他部分使用。有三种常用的方法:构建时提取、运行时提取和从类路径加载运行时。
最后一种方法需要一个控制器(或servlet),它从类路径(相应的JAR)加载资源,缓存它们,并为它们服务。这有几个明显的缺点,其中之一是在一个罐子中,它们在开发过程中很难被替换。使用类路径资源也很棘手,因为您事先不知道文件的名称。
另外两种方法非常相似。例如,grails使用构建时提取插件是一个zip文件,包含所有所需的资源,并在构建项目时将它们提取到相应的位置。这很好,但是它需要更多的配置(在我们的例子中是Maven),这也可能需要从一个项目复制到另一个项目。
所以我们选择了运行时提取方法。它在启动时发生--当加载应用程序时,某种类型的启动监听器(在本例中是带有@PostConstruct的Spring组件)遍历lib文件夹中的所有JAR文件,并从特定文件夹(例如“web”)中提取文件。因此,JAR文件的结构如下所示:
https://www.wenjuan.com/s/UZBZJvqIzyj/
com company pkg Foo.class Bar.class web plugin-name css main.css js foo.js bar.js images logo.png views foo.jsp bar.jsp
最终的结果是,在应用程序启动后,您可以从应用程序获得所有所需的Web资源,因此可以将它们包含在主应用程序的页面(视图)中。
https://m.douban.com/mip/note/824029022/
进行提取的代码相当简单(zip部分使用zip4j)。这可以是servlet上下文侦听器,而不是Springbean--没有任何区别。
https://www.douban.com/note/824029022/?_i=4479147XEgXAhZ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
/** * Component that locates modules (in the form of jar files) and extracts their web elements, if any, on startup * * @author Bozhidar */ @Component public class ModuleExtractor { private static final Logger logger = LoggerFactory.getLogger(ModuleExtractor. class ); @Inject private ServletContext ctx; @SuppressWarnings ( "unchecked" ) @PostConstruct public void init() { File lib = new File(ctx.getRealPath( "/WEB-INF/lib" )); File[] jars = lib.listFiles(); String targetPath = ctx.getRealPath( "/" ); String viewPath = "/WEB-INF/views" ; //that can be made configurable for (File jar : jars) { try { ZipFile file = new ZipFile(jar); for (FileHeader header : (List<FileHeader>) file.getFileHeaders()) { if (header.getFileName().startsWith( "web/" ) && !fileExists(header)) { // extract views in WEB-INF (inaccessible to the outside world) // all other files are extracted in the root of the application if (header.getFileName().contains( "/views/" )) { file.extractFile(header, targetPath + viewPath); } else { file.extractFile(header, targetPath); } } } } catch (ZipException ex) { logger.warn( "Error opening jar file and looking for a web-module in: " + jar, ex); } } } private boolean fileExists(FileHeader header) { return new File(ctx.getRealPath(header.getFileName())).exists(); } } |
因此,为了制作一个插件,您只需使用JAR打包生成一个Maven项目,并将其作为依赖项添加到您的主项目中,其他的一切都会得到处理。您可能需要注册ModuleExtractor
如果没有启用类路径扫描bean(或者您选择让它成为侦听器),那么就这样了。
https://greasyfork.org/en/scripts?set=547873
注意:这个解决方案的目标不是要成为一个解决所有问题的功能齐全的插件系统。它不支持版本控制、子模块等等。这就是为什么标题是“简单”的原因。但是你可以用它做很多事情,而且它的复杂度很低。
注2:Servlet3.0有一种本机方式,但它不允许动态更改资产。如果您不需要更改它们,也不需要保存和刷新,那么这可能是更好的选择。