问题: 目前正在看jfinal,考虑使用webjars来管理静态资源,发现没有现成的实现方式,自己就抛砖引玉
解决方案:
需要添加如下依赖
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.webjars.npm</groupId> <artifactId>bootstrap</artifactId> <version>4.4.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.9</version> </dependency>
工具类:
package com.demo.common; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.JarURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.io.IOUtils; public class WebjarsUtil { public static void main(String[] args) throws Exception { /* 资源文件路径,不能以'/'字符字符开头 */ String resourcePath = "META-INF/resources/webjars/bootstrap/4.4.1/dist/css/bootstrap.min.css"; /* 获取ClassPath下的所有jar路径 */ String[] cps = System.getProperty("java.class.path").split(";"); for (String cp : cps) { if (!cp.endsWith(".jar")) { continue; } if (cp.indexOf("bootstrap")<0) { continue; } InputStream in = loadResourceFromJarFile(cp, resourcePath); if (in != null) { IOUtils.copy(in, new FileOutputStream(new File("aaa.txt"))); System.err.println(IOUtils.toString(in,Charset.forName("UTF-8"))); in.close(); } } /* 读取本地Jar文件 */ for (String cp : cps) { if (!cp.endsWith(".jar")) { continue; } InputStream in = loadResourceFromJarURL(cp, resourcePath); if (in != null) { //System.err.println(IOUtils.toString(in,Charset.forName("UTF-8"))); in.close(); } } /* 读取网络Jar文件 */ // InputStream in = loadResourceFromJarURL( // "http://localhost:8080/SpringStruts2Integration/struts2-spring-plugin-2.3.4.1.jar", resourcePath); // if (in != null) { // System.err.println(IOUtils.toString(in)); // in.close(); // } } /** * 读取Jar文件中的资源 * * @param jarPath 本地jar文件路径 * @param resPath 资源文件所在jar中的路径(不能以'/'字符开头) * @return 如果资源加载失败,返回null */ public static InputStream loadResourceFromJarFile(String jarPath, String resPath) { if (!jarPath.endsWith(".jar")) { return null; } try { JarFile jarFile = new JarFile(jarPath); JarEntry jarEntry = jarFile.getJarEntry(resPath); if (jarEntry == null) { return null; } System.out.println(jarPath); return jarFile.getInputStream(jarEntry); } catch (IOException e) { e.printStackTrace(); return null; } } /** * 读取Jar文件中的资源 * * @param jarUrl 本地jar文件或网络上(ttp://host:port/subpath/jarfile.jar)jar文件路径 * @param resPath 资源文件所在jar中的路径(不能以'/'字符开头) * @return 如果资源加载失败,返回null */ public static InputStream loadResourceFromJarURL(String jarUrl, String resPath) { if (!jarUrl.endsWith(".jar")) { return null; } URL url = null; if (jarUrl.startsWith("http://")) { try { url = new URL("jar:" + jarUrl + "!/"); } catch (MalformedURLException e) { e.printStackTrace(); return null; } } else { try { url = new URL("jar:file:/" + jarUrl + "!/"); } catch (MalformedURLException e) { e.printStackTrace(); return null; } } try { JarURLConnection jarURLConnection; jarURLConnection = (JarURLConnection) url.openConnection(); JarFile jarFile = jarURLConnection.getJarFile(); JarEntry jarEntry = jarFile.getJarEntry(resPath); if (jarEntry == null) { return null; } return jarFile.getInputStream(jarEntry); } catch (IOException e) { e.printStackTrace(); return null; } } }
Handler实现类
package com.demo.common; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.charset.Charset; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import com.jfinal.handler.Handler; public class MyHandler extends Handler{ @Override public void handle(String target, HttpServletRequest request, HttpServletResponse response, boolean[] isHandled) { if (target.contains("/webjars/")) { String resourcePath = StringUtils.substringAfter(target, "/webjars/"); resourcePath = "META-INF/resources/webjars/"+ resourcePath; /* 获取ClassPath下的所有jar路径 */ String[] cps = System.getProperty("java.class.path").split(";"); boolean findFlag = false; for (String cp : cps) { if (!cp.endsWith(".jar")) { continue; } try( InputStream in = WebjarsUtil.loadResourceFromJarFile(cp, resourcePath); ){ if(in!=null) { IOUtils.copy(in, response.getOutputStream()); findFlag = true; break; } } catch (IOException e) { System.out.println("cant get static resource : " + resourcePath + " from jar"); } } if(!findFlag) { //TODO 没有找到静态资源 response.setStatus(404); } isHandled[0] = true; }else { this.next.handle(target, request, response, isHandled); } } }
启动类:
package com.demo.common; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import com.demo.blog.BlogController; import com.demo.common.model._MappingKit; import com.demo.index.IndexController; import com.jfinal.config.Constants; import com.jfinal.config.Handlers; import com.jfinal.config.Interceptors; import com.jfinal.config.JFinalConfig; import com.jfinal.config.Plugins; import com.jfinal.config.Routes; import com.jfinal.kit.PathKit; import com.jfinal.kit.Prop; import com.jfinal.kit.PropKit; import com.jfinal.plugin.activerecord.ActiveRecordPlugin; import com.jfinal.plugin.druid.DruidPlugin; import com.jfinal.server.undertow.UndertowServer; import com.jfinal.template.Engine; /** * 本 demo 仅表达最为粗浅的 jfinal 用法,更为有价值的实用的企业级用法 * 详见 JFinal 俱乐部: http://jfinal.com/club * * API 引导式配置 */ public class DemoConfig extends JFinalConfig { static Prop p; /** * 启动入口,运行此 main 方法可以启动项目,此 main 方法可以放置在任意的 Class 类定义中,不一定要放于此 * @throws IOException * @throws URISyntaxException */ public static void main(String[] args) throws IOException, URISyntaxException { String path = PathKit.class.getResource("/").toURI().getPath(); String file = new File(path).getParentFile().getParentFile().getCanonicalPath(); System.out.println(file); path = getClassLoader().getResource("").toURI().getPath(); file = new File(path).getAbsolutePath(); System.out.println(file); UndertowServer.start(DemoConfig.class); } private static ClassLoader getClassLoader() { ClassLoader ret = Thread.currentThread().getContextClassLoader(); return ret != null ? ret : PathKit.class.getClassLoader(); } /** * PropKit.useFirstFound(...) 使用参数中从左到右最先被找到的配置文件 * 从左到右依次去找配置,找到则立即加载并立即返回,后续配置将被忽略 */ static void loadConfig() { if (p == null) { p = PropKit.useFirstFound("demo-config-pro.txt", "demo-config-dev.txt"); } } /** * 配置常量 */ public void configConstant(Constants me) { loadConfig(); me.setDevMode(p.getBoolean("devMode", false)); /** * 支持 Controller、Interceptor、Validator 之中使用 @Inject 注入业务层,并且自动实现 AOP * 注入动作支持任意深度并自动处理循环注入 */ me.setInjectDependency(true); // 配置对超类中的属性进行注入 me.setInjectSuperClass(true); } /** * 配置路由 */ public void configRoute(Routes me) { me.add("/", IndexController.class, "/index"); // 第三个参数为该Controller的视图存放路径 me.add("/blog", BlogController.class); // 第三个参数省略时默认与第一个参数值相同,在此即为 "/blog" } public void configEngine(Engine me) { me.addSharedFunction("/common/_layout.html"); me.addSharedFunction("/common/_paginate.html"); } /** * 配置插件 */ public void configPlugin(Plugins me) { // 配置 druid 数据库连接池插件 DruidPlugin druidPlugin = new DruidPlugin(p.get("jdbcUrl"), p.get("user"), p.get("password").trim()); me.add(druidPlugin); // 配置ActiveRecord插件 ActiveRecordPlugin arp = new ActiveRecordPlugin(druidPlugin); // 所有映射在 MappingKit 中自动化搞定 _MappingKit.mapping(arp); me.add(arp); } public static DruidPlugin createDruidPlugin() { loadConfig(); return new DruidPlugin(p.get("jdbcUrl"), p.get("user"), p.get("password").trim()); } /** * 配置全局拦截器 */ public void configInterceptor(Interceptors me) { } /** * 配置处理器 */ public void configHandler(Handlers me) { me.add(new MyHandler()); } }
layouthtml文件
#define layout() <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xml:lang="zh-CN" xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> <link href="/assets/css/manage.css" media="screen" rel="stylesheet" type="text/css" /> <script src="/assets/js/jquery-1.4.4.min.js" type="text/javascript" ></script> <link href="/webjars/bootstrap/4.4.1/dist/css/bootstrap.min.css" media="screen" rel="stylesheet" type="text/css"/> <link href="/webjars/bootstrap/4.4.1/dist/js/bootstrap.min.js" media="screen" rel="stylesheet" type="text/css"/> <link href="/webjars/bootstrap/4.4.1/dist/css/bootstrap.min.js" media="screen" rel="stylesheet" type="text/css"/> </head> <body> <div> <div> <div> <a href="http://www.jfinal.com" target="_blank">JFinal web framework</a> </div> <div id="nav"> <ul> <li><a href="/"><b>首页</b></a></li> <li><a href="/blog"><b>Blog管理</b></a></li> </ul> </div> </div> <div> #@main() </div> </div> </body> </html> #end
思路清晰,代码简洁,谢谢你的分享