SpringBoot 目标是简化开发和部署,web方面则使用嵌入式web容器来替代依赖外部容器的部署方式。


      在JavaWeb 领域,现在有了多种页面渲染技术可选,如velocity,freemarker等。并且还有绝对的前后端分离思想的影响,多年过去了,JSP技术的应用虽然有所下降,但仍然广泛。许多遗留系统还是JSP开发的。JSP的支持还是tomcat做的比较好,其他如jetty啥的要么不支持jsp要么Springboot没支持他们,SpringBoot对内嵌web容器的支持默认也是用tomcat。但tomcat对web资源的处理上写死了要使用文件目录,对于打包成jar包的SpringBoot应用来说,显然不行,也有的人打包成war,然后还是部署到tomcat上,这样我认为违反了SpringBoot的初衷,这样一来,等于否定了嵌入式容器,而且程序员还要处理嵌入式环境和外部tomcat环境的不同带来的问题。


 本文目地是为使用jar包部署带有jsp的SpringBoot应用提供一个解决方案。

思路也很简单,就是把资源打包进jar,然后main方法里面运行应用之前把资源拷贝到外部文件。


1) 把web资源目录打包进jar

  其实就是放在classpath目录, 如果是普通java应用,可以放在src目录。如果是maven项目可以配置资源处理:

<!-- 打包时将jsp文件拷贝到META-INF目录下 -->
            <resource>
                <directory>src/main/webapp</directory>
                <targetPath>META-INF/resources</targetPath>
                <includes>
                    <include>**/**</include>
                </includes>
            </resource>
2) main()方法里面拷贝资源到外部文件

public static void main(String[] args) {
		// 为了让SpringBoot支持jsp,在jar包环境下需要把jsp解压到src/main/webapp/目录下
		boolean override = "true".equals(System.getProperty("cleanOnstart", "true"));
                Class<?> bootClass = MyApplication.class;// main()方法所在的类
               copyResourceIfInJar(bootClass,"META-INF/resources","src/main/webapp",override);
		SpringApplication.run(bootClass, args);
	}
拷贝的方法,利用 spring 的 resource 神器

private static void copyResourceIfInJar(Class<?> clazz, String resPreffix, String targetDir, boolean override) {
		String cls = clazz.getSimpleName() + ".class";
		URL url = clazz.getResource(cls);
		if (url == null) {
			System.err.println("不可思议的可能.");
			return;
		}
		if ("file".equals(url.getProtocol())) {
			// 本地开发环境,忽略
			System.out.println("ignore when local dev.");
			return;
		}
		File webRootFile = new File(targetDir);
		if (webRootFile.exists()) {
			File oldFolder;
			if (!webRootFile.isDirectory()) {
				webRootFile.delete();
				webRootFile.mkdir();
			} else if (override && webRootFile.renameTo(oldFolder = new File(targetDir + "-" + UUID.randomUUID()))) {
				webRootFile.mkdirs();
				oldFolder.deleteOnExit();
			} else if (!override) {
				System.out.println("lazy return when not override.");
				return;
			}
		} else {
			webRootFile.mkdirs();
		}
		// 目录准备完毕,开始解压和复制
		PathMatchingResourcePatternResolver searcher = new PathMatchingResourcePatternResolver(clazz.getClassLoader());
		try {
			Resource[] webResources = searcher.getResources(resPreffix + (resPreffix.endsWith("/") ? "**" : "/**"));
			if (webResources != null && webResources.length > 0) {
				for (Resource resource : webResources) {
					String desc = resource.getDescription();
					String uri = desc.substring(desc.indexOf(resPreffix) + resPreffix.length(), desc.lastIndexOf(']'));
					File tar = new File(targetDir, uri);
					if (uri.endsWith("/")) {
						tar.mkdirs();
						continue;
					}
					if (!tar.getParentFile().exists()) {
						tar.getParentFile().mkdirs();
					}
					FileCopyUtils.copy(resource.getInputStream(), new FileOutputStream(tar));
				}
			} else {
				System.err.println("Resource Not Found in path:" + resPreffix);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐