发布于 

Java项目内置Jetty

想要在一个Java项目中自启动一个jetty容器,可以打开站点,显示自定义内容,而不需要引入jetty插件或者Ide支持或者类似tomcat那样启动。并且将项目打成jar包,可以在其他项目中引用。

在使用中碰到一些问题,主要是:

  • jetty包对jsp页面不支持,需要额外引入包,且去掉冲突包;
  • 当项目被打成jar包、被其他项目引用时,要注意jetty Server webAppContext的路径问题

现记录如下:

  1. 引入Jetty包:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-webapp</artifactId>
    <version>9.3.7.v20160115</version>
    </dependency>
    <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-servlet</artifactId>
    <version>9.3.7.v20160115</version>
    </dependency>

    是为了让jetty站点支持jsp和jstl,还需要引入:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <dependency>
    <groupId>org.eclipse.jetty</groupId>
    <artifactId>jetty-jsp</artifactId>
    <version>9.2.15.v20160210</version>
    <exclusions>
    <exclusion>
    <groupId>org.eclipse.jetty.orbit</groupId>
    <artifactId>javax.servlet.jsp.jstl</artifactId>
    </exclusion>
    </exclusions>
    </dependency>
    <dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>javax.servlet.jsp.jstl-api</artifactId>
    <version>1.2.1</version>
    </dependency>
  2. main文件夹下创建webapp文件夹,类似于标准web项目,创建webapp\WEB-INF\web.xml文件;由于项目使用了springMVC框架,所以resource文件夹下要创建applicationContext.xml文件,并引入相应的springMVC包,其他jsp/js/css/images等参考标准web项目目录。

  3. Main函数启动Jetty,加载web.xml:

    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
    private static final int port = 8080;          
    private static final String CONTEXT = "/";

    public static Server createServer(int port) throws MalformedURLException, URISyntaxException {
    Server server = new Server();
    server.setStopAtShutdown(true); //JVM退出时关闭Jetty

    ServerConnector connector = new ServerConnector(server);
    connector.setPort(port);
    connector.setReuseAddress(false); //重复启动Jetty居然报端口冲突
    server.setConnectors(new Connector[]{connector});

    WebAppContext webContext = new WebAppContext("src/main/webapp", CONTEXT);
    webContext.setDescriptor("src/main/webapp/WEB-INF/web.xml");
    webContext.setResourceBase("src/main/webapp");
    webContext.setClassLoader(ApiWebSite.class.getClassLoader());
    server.setHandler(webContext);
    return server;
    }

    public static void main(String[] args) throws Exception {
    Server server = ApiWebSite.createServer(ApiWebSite.port);
    try {
    server.stop();
    server.start();
    server.join();
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

完成其他spring bean代码和jsp代码编写,运行main函数,浏览器访问localhost:8080/index.htm(自己在web.xmlapplicationContext.xml配置)就可以访问web页面了。

但是

将项目打成jar包,在其他工程中引用,运行main函数,试图启动jetty站点时,WebAppContext的路径,会在当前项目的src目录下找,当然是找不到的,所以加载xml文件失败。需要对上面的内容做一点修改:

  1. web文件夹,从src目录移动到resources目录下,这样做的目的是为了打包时将网站内容也打进jar包(因为这不是一个标准的web工程);

  2. 修改代码:

    1
    2
    3
    WebAppContext webContext = new WebAppContext("webapp", CONTEXT);
    webContext.setBaseResource(Resource.newResource(new URL(ApiWebSite.class.getResource("/webapp/WEB-INF"), ".")));
    webContext.setClassLoader(ApiWebSite.class.getClassLoader());

    此时,webAppContext就会从依赖的jar包中找到配置文件的实际路径进行加载,而不是从当前项目的文件夹中找。

    要注意的是,这里没有setDescriptor("src/main/webapp/WEB-INF/web.xml")。因为在使用时,不管我怎么设置这个web.xml的地址,总是找不到。在丁哥帮助下,发现jetty源码中,如果不设置Descriptor,他会默认寻找webapp目录下的WEB-INF/web.xml文件:

    1
    2
    3
    4
    5
    6
    7
    8
    /**
    * @return the web.xml descriptor to use. If set to null, WEB-INF/web.xml is used if it exists.
    */
    @ManagedAttribute(value="standard web.xml descriptor", readonly=true)
    public String getDescriptor()
    {
    return _descriptor;
    }

    去掉webContext.setDescriptor(...);后,重新install,启动成功。