关于Jfinal项目如何使用内置Jetty打成Jar运行

首先说明本分享只适用于maven项目,grandle项目部分插件有所不同。

1.核心引用

<dependency>
    <groupId>com.jfinal</groupId>
    <artifactId>jetty-server</artifactId>
    <version>8.1.8</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>com.jfinal</groupId>
    <artifactId>jfinal</artifactId>
    <version>3.2</version>
</dependency>

maven插件
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>2.3.2</version>
        <configuration>
            <source>1.8</source>
            <target>1.8</target>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <configuration>
            <skip>true</skip>
        </configuration>
    </plugin>
    <plugin><!--核心打成jar包插件-->
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.6</version>
        <configuration>
            <archive>
                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>top.jkhaled.App</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
            <execution>
                <id>copy-dependencies</id>
                <phase>package</phase>
                <goals>
                    <goal>copy-dependencies</goal>
                </goals>
                <configuration>
                    <outputDirectory>${project.build.directory}/lib</outputDirectory>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>

2.把原来在webapp目录的内容全部放在resources目录下

image.png

3.编写启动类

public class App {
    /**
     * 用于在 IDEA 中,通过创建 main 方法的方式启动项目,不支持热加载
     * 本方法存在的意义在于此方法启动的速度比 maven 下的 jetty 插件要快得多
     * <p>
     * 注意:不支持热加载。建议通过 Ctrl + F5 快捷键,来快速重新启动项目,速度并不会比 eclipse 下的热加载慢多少
     * 实际操作中是先通过按 Alt + 5 打开 debug 窗口,才能按 Ctrl + F5 重启项目
     */
    public static void main(String[] args) {
        /**
         * 特别注意:IDEA 之下建议的启动方式,仅比 eclipse 之下少了最后一个参数
         */
        String baseBath = String.valueOf(App.class.getProtectionDomain().getCodeSource().getLocation());
        String classPath, webRootPath, jarPath;
        if (StrKit.notBlank(baseBath) && baseBath.contains("file:/")) {
            // 获取运行操作系统的运行方式  window和linux的细微区别
            boolean windows = System.getProperties().getProperty("os.name").contains("Windows");
            System.out.println(System.getProperties().getProperty("os.name"));
            jarPath = (windows ? "" : "/") + baseBath.substring("file:/".length());
            classPath = (windows ? "" : "/") + jarPath.substring(0, jarPath.lastIndexOf("/")) + "/class-path";
            System.out.println("jarPath:" + jarPath);
            System.out.println("classPath:" + classPath);
            webRootPath = classPath;
            ZipUtil.unzip(jarPath, classPath);
            // 这两步是核心指定 webapp目录和classpath目录
            PathKit.setWebRootPath(webRootPath);
            PathKit.setRootClassPath(classPath);
            // eclipse 启动是4个参数    
            JFinal.start(webRootPath, 1996, "/");
        } else {
            throw new RuntimeException("你丫的路径不对!");
        }
    }
}

5.maven jar 插件中指定这个类为启动类

                <manifest>
                    <addClasspath>true</addClasspath>
                    <classpathPrefix>lib/</classpathPrefix>
                    <mainClass>top.jkhaled.App</mainClass>
                </manifest>

6.执行 mvn install

7.执行 java -jar target/xxxxxx.jar

image.png

启动成功

image.png

访问一个请求成功


备注:

 ZipUtil.unzip(jarPath, classPath);

这个地方用到了 Hutool的解压包,大家可以使用自己解压zip的包。

评论区

马小酱

2017-09-27 09:47

感谢分享,有时间要学习一下。

JFinal

2017-09-27 10:21

这个分享太赞了,有不少人问过,但貌似没人成功过,收藏、点赞以后有需求就用上

另外,你的模板是用的什么,如果是用的 jfinal template engine,有没有设置:
engine.setSourceFactory(new ClassPathSourceFactory());

djs19960601

2017-09-27 19:01

@JFinal 刚试了下如果是 jfinal template engine的话确实也要设置为engine.setSourceFactory(new ClassPathSourceFactory());我们这项目是前后分离的JFinal提供API,所以之前没考虑过这个问题。还是谢谢波总提醒

djs19960601

2017-09-27 19:04

@马小酱 嗯,这个有点忘了说了,就是开发时候的启动类和jar包运行的启动类不能是同一个启动类,开发还是 JFinal.start("man/java/resource", 80, "/");就够了

JFinal

2017-09-27 21:33

@djs19960601 打成 jar 以后是怎么启动的项目? 通过 java -jar .... 启动的? 入口方法是哪个?

djs19960601

2017-09-28 09:17

@JFinal 是 java -jar 启动,入口就是我上面写的那个App类的main方法

JFinal

2017-09-28 21:56

@djs19960601 这就很清楚了,感谢你的分享,我也收藏了这个贴子,以后用得着

简单代码

2017-10-12 17:51

@djs19960601
请教
1 如果不将webAPP目录放到resources目录下,打包的jar是不是不能运行?
2 最终项目仍然是解压后运行的吗?不能放在jar中运行是吗?我看到你用了一个解压工具。

谢谢!@JFinal

djs19960601

2017-10-12 19:19

@简单代码 不放在webapp也行 你要修改 PathKit.setWebRootPath(webRootPath);为你指定的webapp路径,PathKit.setRootClassPath(classPath);设置为你的编译后的class路径,只要这两个设置正确了也不用解压,我打包解压的目的是不用手动去操作这个路径问题,这样比较好移植,个人想法,现在想想也不太好,后期会想办法能完全用java配置代替这个找不到web.xml的问题,静候佳音,谢谢参与讨论

JFinal

2017-10-13 11:17

@djs19960601 如果要打成 jar 包来运行,建议将 webRootPath 这个参数拿出来当成配置项,与 jdbcUrl 连接一样当成配置

djs19960601

2017-10-17 12:43

@JFinal 嗯 写成配置项 ,然后系统内置缺省为classPath怎么样

aaaaaaa

2017-11-17 05:53

有成功跑起来的么?折腾了2个小时。还是没起来
Exception in thread "main" java.lang.NoClassDefFoundError: org/mortbay/log/Log

djs19960601

2017-11-21 08:54

@aaaaaaa 兄弟你这是哪一行报的错联系我QQ1193032532,我帮你看看

说忘了

2017-12-13 11:10

补充ZipUtil 的依赖
《dependency》
《groupId》 com.xiaoleilu《/groupId》
《artifactId》hutool-all《/artifactId》
《version》3.2.2《/version》
《/dependency》
感谢djs 的帮助

JFinal

2017-12-13 11:35

@说忘了 用的 《》 符号,非常机智,感谢你的分享 ^_^

袁小猴

2018-01-31 19:16

无法支持WebJars。。。

哈哈一小人

2018-02-28 12:44

我打包成功运行成功后,无法访问,报404是怎么回事@djs19960601

哈哈一小人

2018-02-28 13:47

@哈哈一小人 已解决,把wabapp中的资源文件放错地方了

幽兰

2018-03-21 15:25

[ERROR]-[Thread: main]-[com.jfinal.kit.LogKit.error()]: java.lang.NullPointerException
java.lang.RuntimeException: java.lang.NullPointerException
你好,打包之后运行报这个错,是什么原因呢?@JFinal

青峰大辉

2018-04-16 14:39

@哈哈一小人 我也是404,具体放错地方是什么意思

东线战场

2018-04-25 20:15

我的web文件夹没有被打包进去,这个怎么办,我的项目结构用的idea默认的web项目的,后期改用maven管理jar包,才接触maven不太会玩

djs19960601

2018-04-26 09:00

@东线战场 打包的时候要把webapp 目录下的所有内容全部放到resources下面

cc_cc

2018-04-28 10:00

@JFinal @djs19960601 折腾了一天搞这个,这个分享中提到的时解压jar包,然后设置webRootPath和RootClassPath。一直想能不能不解压直接设置为jar包里面的路径,一直不行,然后网上看到有人提到jetty可能不支持设置这个路径位jar包里面,需要为文件路径。麻烦请求可以不解压设置这两个路径不?

djs19960601

2018-04-28 10:16

@cc_cc 只用设置webRootPath 就行了, RootClassPath本身就包含jar包本身的

cc_cc

2018-05-04 13:32

@djs19960601 恩,试了下。确实不需要setWebRootPath也可以。但是还是那个问题就是不解压的话读取不到webRootPath里面的web.xml,可以解压吗?