从 cmd 使用 Maven [Servlet app] 启动 Tomcat 嵌入式服务器?
Start Tomcat embedded server using Maven [Servlet app] from cmd?
我的实习任务是查询一些 API。我必须通过不使用任何应用程序框架来做到这一点,即 Spring 或 Spring Boot.
两个学期前,我将 Servlet 编程作为一门课程。但是我忘记了大部分。
要求之一是能够从 cmd 启动应用程序。所以我决定从 Eclipse 创建简单的 Maven 项目(文件 -> 新建 -> Maven 项目)。此外,我添加了嵌入式 Tomcat 作为依赖项,因此只需使用 Maven 命令即可从 cmd 启动应用程序。
我的pom.xml
中有这个:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>AssignmentAppWeb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>AssignmentApp</name>
<description>Assignment App</description>
<properties>
<tomcat.version>8.0.48</tomcat.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>p.Main</mainClass>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>p.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
这是我的主class:
package p;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
public class Main {
public static void main(String[] args) throws LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("temp");
tomcat.setPort(8080);
String contextPath = "/";
String docBase = new File(".").getAbsolutePath();
Context context = tomcat.addContext(contextPath, docBase);
HttpServlet servlet = new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("<html><title>Welcome</title><body>");
writer.println("<h1>Have a Great Day!</h1>");
writer.println("</body></html>");
}
};
String servletName = "Servlet1";
String urlPattern = "/go";
tomcat.addServlet(contextPath, servletName, servlet);
context.addServletMappingDecoded(urlPattern, servletName);
tomcat.start();
tomcat.getServer().await();
}
}
这里是一般的项目结构:
如果我 cd
进入 target
,在 mvn clean instal
之后,然后 java -jar AssignmentAppWeb-0.0.1-SNAPSHOT.jar
,我得到这个错误:
C:\Users\Miljan\Desktop\FevoWS1\AssignmentAppWeb\target>java -jar AssignmentAppWeb-0.0.1-SNAPSHOT.jar
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/Servlet
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:650)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:632)
Caused by: java.lang.ClassNotFoundException: javax.servlet.Servlet
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 7 more
我做错了什么?我只需要通过 Servlet 添加几个控制器就可以了。不确定通过 web.xml
注册 servlet 是否比通过 Main
class 中的代码更正确。那么,如何启动嵌入式Tomact呢?
这个问题的问题是运行这个程序,Java需要Maven定义的所有运行时间依赖。在大多数项目中,这些内容太多太复杂而无法手动指定,主要是 IMO,因为传递依赖性。 Maven 作为我们的依赖管理器,提供了辅助工具。以下是我所知道的一些:
最简单的情况,Maven Exec 插件。如果您不介意 运行 通过 Maven 项目来调整您的程序。对于这种情况:
mvn exec:java -Dexec.mainClass=p.Main
Maven 程序集插件。该站点的描述非常重要:“ 使开发人员能够将项目输出合并到一个单独的可分发存档中,该存档还包含依赖项、模块、站点文档和其他文件”。这不是那么简单,但仍然非常简单。它由一个名为程序集描述符的文件配置,该文件精确定义了最终程序集中包含的内容。
带有 dependency:copy
或 dependency:copy-dependencies
的 Maven 依赖插件会将依赖 jar 复制到文件系统中的某个文件夹中。它当然可以包含传递依赖项并应用简单的转换,例如从 jar 文件中删除版本号。从那里您可以手动将它们包含在您的类路径中,或者让脚本为您完成。
Maven Shade 插件向前迈进了一步,将所有依赖项和应用程序代码重新打包到一个 jar 中,并可选择重命名其中的一些。
我的实习任务是查询一些 API。我必须通过不使用任何应用程序框架来做到这一点,即 Spring 或 Spring Boot.
两个学期前,我将 Servlet 编程作为一门课程。但是我忘记了大部分。
要求之一是能够从 cmd 启动应用程序。所以我决定从 Eclipse 创建简单的 Maven 项目(文件 -> 新建 -> Maven 项目)。此外,我添加了嵌入式 Tomcat 作为依赖项,因此只需使用 Maven 命令即可从 cmd 启动应用程序。
我的pom.xml
中有这个:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.company</groupId>
<artifactId>AssignmentAppWeb</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>AssignmentApp</name>
<description>Assignment App</description>
<properties>
<tomcat.version>8.0.48</tomcat.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<version>${tomcat.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-logging-juli</artifactId>
<version>${tomcat.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<programs>
<program>
<mainClass>p.Main</mainClass>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>p.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>
这是我的主class:
package p;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.catalina.Context;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.startup.Tomcat;
public class Main {
public static void main(String[] args) throws LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setBaseDir("temp");
tomcat.setPort(8080);
String contextPath = "/";
String docBase = new File(".").getAbsolutePath();
Context context = tomcat.addContext(contextPath, docBase);
HttpServlet servlet = new HttpServlet() {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.println("<html><title>Welcome</title><body>");
writer.println("<h1>Have a Great Day!</h1>");
writer.println("</body></html>");
}
};
String servletName = "Servlet1";
String urlPattern = "/go";
tomcat.addServlet(contextPath, servletName, servlet);
context.addServletMappingDecoded(urlPattern, servletName);
tomcat.start();
tomcat.getServer().await();
}
}
这里是一般的项目结构:
如果我 cd
进入 target
,在 mvn clean instal
之后,然后 java -jar AssignmentAppWeb-0.0.1-SNAPSHOT.jar
,我得到这个错误:
C:\Users\Miljan\Desktop\FevoWS1\AssignmentAppWeb\target>java -jar AssignmentAppWeb-0.0.1-SNAPSHOT.jar
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main" java.lang.NoClassDefFoundError: javax/servlet/Servlet
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.privateGetMethodRecursive(Class.java:3048)
at java.lang.Class.getMethod0(Class.java:3018)
at java.lang.Class.getMethod(Class.java:1784)
at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:650)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:632)
Caused by: java.lang.ClassNotFoundException: javax.servlet.Servlet
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
... 7 more
我做错了什么?我只需要通过 Servlet 添加几个控制器就可以了。不确定通过 web.xml
注册 servlet 是否比通过 Main
class 中的代码更正确。那么,如何启动嵌入式Tomact呢?
这个问题的问题是运行这个程序,Java需要Maven定义的所有运行时间依赖。在大多数项目中,这些内容太多太复杂而无法手动指定,主要是 IMO,因为传递依赖性。 Maven 作为我们的依赖管理器,提供了辅助工具。以下是我所知道的一些:
最简单的情况,Maven Exec 插件。如果您不介意 运行 通过 Maven 项目来调整您的程序。对于这种情况:
mvn exec:java -Dexec.mainClass=p.Main
Maven 程序集插件。该站点的描述非常重要:“ 使开发人员能够将项目输出合并到一个单独的可分发存档中,该存档还包含依赖项、模块、站点文档和其他文件”。这不是那么简单,但仍然非常简单。它由一个名为程序集描述符的文件配置,该文件精确定义了最终程序集中包含的内容。
带有
dependency:copy
或dependency:copy-dependencies
的 Maven 依赖插件会将依赖 jar 复制到文件系统中的某个文件夹中。它当然可以包含传递依赖项并应用简单的转换,例如从 jar 文件中删除版本号。从那里您可以手动将它们包含在您的类路径中,或者让脚本为您完成。Maven Shade 插件向前迈进了一步,将所有依赖项和应用程序代码重新打包到一个 jar 中,并可选择重命名其中的一些。