[maven] maven 创建 web 项目并嵌套项目

maven maven 创建 web 项目并嵌套项目

这里主要就创建另外一个 web 项目,并且创建一个 parent 项目比较方便的管理一下两个子项目。

maven web 项目

web 创建和 quickstart 的过程是差不多的,只不过这里换乘 webapp,配置方便的话可以搞的东西挺多的......这里就搞 servlet,上古版本的东西了。

create new web application

创建新的 maven 项目这里就换成 webapp,创建后的项目,pom 也会不太一样:

bash 复制代码
❯ tree productweb
productweb
├── pom.xml
├── src
│   └── main
│       └── webapp
│           ├── WEB-INF
│           │   └── web.xml
│           └── index.jsp
└── target
    ├── classes
    ├── m2e-wtp
    │   └── web-resources
    │       └── META-INF
    │           ├── MANIFEST.MF
    │           └── maven
    │               └── com.goldenaarcher.product
    │                   └── productweb
    │                       ├── pom.properties
    │                       └── pom.xml
    └── test-classes

14 directories, 6 files

❯ cat productweb/pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.goldenaarcher.product</groupId>
  <artifactId>productweb</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>productweb Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.7</maven.compiler.source>
    <maven.compiler.target>1.7</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

  <build>
    <finalName>productweb</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

简单的过一下 pom 的配置:

  • 如 pom 显示的一样,这里打包的包是 war 而不是 jar。
  • finalName 这个选项设置会重写默认的项目名

这时候项目还是没有办法运行的,因为目前项目没有服务器,所以这个时候需要完成服务器相关的配置。

  1. eclipse 中添加 tomcat

    完成这一步项目就不会报错,可以正常 build

    这个也可以通过直接在 pom 里面设置,这里是直接配置本地已经下载好的 tomcat

    具体步骤就是在项目属性里面选择 targeted runtime:

    如果 tomcat 的配置像在之前的笔记 Mac 中安装 tomcat 及 Eclipse 配置 Tomcat 提过的一样已经搞好了,也可以通过 tomcat 进行修改:

  2. 添加 servlet 的依赖

    依赖如下:

    xml 复制代码
        <dependency>
          <groupId>org.apache.geronimo.specs</groupId>
          <artifactId>geronimo-servlet_3.0_spec</artifactId>
          <version>1.0</version>
          <scope>provided</scope>
        </dependency>

两个都配置好了就可以运行 mvn clean install 了:

bash 复制代码
[[1;34mINFO[m] [1m--- [0;32mmaven-war-plugin:3.2.2:war[m [1m(default-war)[m @ [36mproductweb[0;1m ---[m
[[1;34mINFO[m] Packaging webapp
[[1;34mINFO[m] Assembling webapp [productweb] in [/Users/usr/study/maven/productweb/target/productweb]
[[1;34mINFO[m] Processing war project
[[1;34mINFO[m] Copying webapp resources [/Users/usr/study/maven/productweb/src/main/webapp]
[[1;34mINFO[m] Webapp assembled in [24 msecs]
[[1;34mINFO[m] Building war: /Users/usr/study/maven/productweb/target/productweb.war
[[1;34mINFO[m]
[[1;34mINFO[m] [1m--- [0;32mmaven-install-plugin:2.5.2:install[m [1m(default-install)[m @ [36mproductweb[0;1m ---[m
[[1;34mINFO[m] Installing /Users/usr/study/maven/productweb/target/productweb.war to /Users/usr/.m2/repository/com/goldenaarcher/product/productweb/0.0.1-SNAPSHOT/productweb-0.0.1-SNAPSHOT.war
[[1;34mINFO[m] Installing /Users/usr/study/maven/productweb/pom.xml to /Users/usr/.m2/repository/com/goldenaarcher/product/productweb/0.0.1-SNAPSHOT/productweb-0.0.1-SNAPSHOT.pom
[[1;34mINFO[m] [1m------------------------------------------------------------------------[m
[[1;34mINFO[m] [1;32mBUILD SUCCESS[m
[[1;34mINFO[m] [1m------------------------------------------------------------------------[m
[[1;34mINFO[m] Total time:  1.631 s
[[1;34mINFO[m] Finished at: 2023-09-11T21:12:28-04:00
[[1;34mINFO[m] [1m------------------------------------------------------------------------[m

注意这里 war 就已经打包好了

准备工作

maven 创建项目的时候,可能会漏结构,所以需要确认一下结构。Maven resource folder isn't created 中提到的是资源文件夹没有创建,不过我这里是连 java 都瘸了......所以说,如果 main 没有三个文件夹,就需要创建缺失的文件夹,,随后更新一下 maven 项目,此时结构如下:

bash 复制代码
❯ cd productweb
❯ mkdir src/main/java
❯ mkdir src/main/resources
❯ tree .
.
├── pom.xml
├── src
│   └── main
│       ├── java
│       ├── resources
│       └── webapp
│           ├── WEB-INF
│           │   └── web.xml
│           └── index.jsp
└── target
    ├── classes
    ├── m2e-wtp
    │   └── web-resources
    │       └── META-INF
    │           ├── MANIFEST.MF
    │           └── maven
    │               └── com.goldenaarcher.product
    │                   └── productweb
    │                       ├── pom.properties
    │                       └── pom.xml
    ├── maven-archiver
    │   └── pom.properties
    ├── productweb
    │   ├── META-INF
    │   ├── WEB-INF
    │   │   ├── classes
    │   │   └── web.xml
    │   └── index.jsp
    ├── productweb.war
    └── test-classes

21 directories, 10 files

resources 还是挺重要的,一些资源的同步就靠这个文件夹。

创建 servlets

创建产品 servlet

这里点击项目右键选择创建新的 servlet,现在这个年代已经不是热门选项了,有可能需要到 more 里面去找:

下一步提供 servlet 的名称:

选择 URL mapping:

完成创建:

完成后的结构如下:

bash 复制代码
❯ tree src/main/java
src/main/java
└── com
    └── goldenaarcher
        └── product
            └── servlets
                └── CreateProductServlet.java

5 directories, 1 file

servlet 的文件内容为:

java 复制代码
package com.goldenaarcher.product.servlets;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class CreateProductServlet
 */
public class CreateProductServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public CreateProductServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

}
展示产品 servlet

也是右键新建生成一个 servlet,这里选择 doGet,然后生成一个空的 java 模板。

关于 mapping

这个跟自动生成有关系,有可能是通过注解 @WebServlet 实现,或者是通过 webapp/WEB-INF 下的 web.xml 实现 mapping,eclipse 自动生成 xml 文件:

xml 复制代码
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
  	<servlet-name>CreateProductServlet</servlet-name>
  	<display-name>CreateProductServlet</display-name>
  	<description></description>
  	<servlet-class>com.goldenaarcher.product.servlets.CreateProductServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>CreateProductServlet</servlet-name>
  	<url-pattern>/CreateProductServlet</url-pattern>
  </servlet-mapping>
</web-app>

stack overflow 上也有一个回答解释了 mapping 的问题: Not getting automatically web.xml file while creating servlet in Eclipse Juno 4.2

简单的说就是,@WebServlet("/CreateProductServlet") 可以代替这几行代码:

xml 复制代码
  <servlet>
  	<servlet-name>CreateProductServlet</servlet-name>
  	<display-name>CreateProductServlet</display-name>
  	<description></description>
  	<servlet-class>com.goldenaarcher.product.servlets.CreateProductServlet</servlet-class>
  </servlet>
  <servlet-mapping>
  	<servlet-name>CreateProductServlet</servlet-name>
  	<url-pattern>/CreateProductServlet</url-pattern>
  </servlet-mapping>

两种配置可以同时存在,但是同一个 servelet 不能被 map 两次,否则会运行失败。

tomecat 10 更新

tomcat10 的包从 javax.servlet.jsp 变成了 jakarta.servlet.jsp,所以要下载对应的新 dependency

xml 复制代码
		<!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
		<dependency>
			<groupId>jakarta.servlet</groupId>
			<artifactId>jakarta.servlet-api</artifactId>
			<version>6.0.0</version>
			<scope>provided</scope>
		</dependency>

创建 HTML

这个页面就是创建产品的页面,它的目录为 src/main/webapp 完整代码如下:

html 复制代码
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Create Product</title>
    <style>
      div {
        display: flex;
      }

      input {
        display: block;
      }
    </style>
  </head>
  <body>
    <h3>Enter Product Details:</h3>
    <form method="post" action="CreateProductServlet">
      <div>Product Id: <input name="id" /></div>
      <div>Product Name: <input name="name" /></div>
      <div>Product Description: <input name="description" /></div>
      <div>Product Price: <input name="price" /></div>
      <div>
        <input type="submit" />
      </div>
    </form>
  </body>
</html>

此时的结构为:

bash 复制代码
❯ tree src
src
└── main
    ├── java
    │   └── com
    │       └── goldenaarcher
    │           └── product
    │               └── servlets
    │                   ├── CreateProductServlet.java
    │                   └── DisplayProductDetailsServelet.java
    ├── resources
    └── webapp
        ├── WEB-INF
        │   └── web.xml
        ├── index.jsp
        └── product.html

10 directories, 5 files

运行项目

这回直接在 tomcat 上进行运行,这时候页面显示如下:

下一步要做的,就是把 product service 和 product web 两个项目连起来,实现一个可以运行的页面。

多模块项目

为了方便管理,主要这样可以只用跑一次 maven 相关的指令。

清理结构

我这里创建了一个新的文件夹,然后把两个 product 相关的文件夹搬进去了。这个可以用 GUI 也可以用命令行。

调整完了结构如下:

bash 复制代码
❯ tree -L 3
.
├── pom.xml
├── productservices
│   ├── pom.xml
│   ├── src
│   │   ├── main
│   │   └── test
│   └── target
│       ├── classes
│       ├── generated-sources
│       ├── generated-test-sources
│       ├── maven-archiver
│       ├── maven-status
│       ├── productservices-1.0.jar
│       ├── surefire-reports
│       └── test-classes
└── productweb
    ├── pom.xml
    ├── src
    │   └── main
    └── target
        ├── classes
        ├── generated-sources
        ├── m2e-wtp
        ├── maven-archiver
        ├── maven-status
        ├── productweb
        └── productweb.war

23 directories, 5 files

新增&修改 pom 文件

总共需要修改 3 个 pom 文件

新增 parent 文件夹下的 pom

创建 parent 文件夹下的 pom 文件:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.goldenaarcher.product</groupId>
	<artifactId>productparent</artifactId>
	<version>1.0</version>
	<packaging>pom</packaging>

	<name>productparent</name>
	<!-- FIXME change it to the project's website -->
	<url>http://www.example.com</url>

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<modules>
		<module>productservices</module>
		<module>productweb</module>
	</modules>
</project>

这里主要需要注意的就是亮点:

  1. packaging 的格式是 pom
  2. modules 下包含所有的子项目
更新子项目的 pom

更新 parent 下的部分都是共同的,所有子项目都要重新定义一下父项目

productservices pom
xml 复制代码
	<parent>
		<groupId>com.goldenaarcher.product</groupId>
		<artifactId>productparent</artifactId>
		<version>1.0</version>
	</parent>

	<artifactId>productservices</artifactId>
	<name>productservices</name>
	<!-- FIXME change it to the project's website -->
	<url>http://www.example.com</url>
productweb pom

除了 parent,web 这里海需要更新 dependency,因为 web 需要调用 service 中的 bo 去实现具体功能。

xml 复制代码
	<parent>
		<groupId>com.goldenaarcher.product</groupId>
		<artifactId>productparent</artifactId>
		<version>1.0</version>
	</parent>

	<artifactId>productweb</artifactId>
	<packaging>war</packaging>

	<name>productweb Maven Webapp</name>
	<!-- FIXME change it to the project's website -->
	<url>http://www.example.com</url>

	<dependencies>
    <!-- 省略其他 -->
		<dependency>
			<groupId>com.goldenaarcher.product</groupId>
			<artifactId>productservices</artifactId>
			<version>1.0</version>
		</dependency>
	</dependencies>

servelt 的 java 实现

这里主要实现的就是从 request 中获取数据,传到 bo 中实现功能即可

实现 CreateProductServlet

这里会从 THML 中获取对应的数据,调用 bo 里的 create 创建一个 product

java 复制代码
package com.goldenaarcher.product.servlets;

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 com.goldenaarcher.product.bo.ProductBO;
import com.goldenaarcher.product.bo.ProductBOImpl;
import com.goldenaarcher.product.dto.Product;

/**
 * Servlet implementation class CreateProductServlet
 */
public class CreateProductServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		Integer id = Integer.parseInt( request.getParameter("id"));
		String name = request.getParameter("name");
		String desc = request.getParameter("description");
		Integer price = Integer.parseInt( request.getParameter("price"));

		Product product = new Product();
		product.setId(id);
		product.setDescription(desc);
		product.setName(name);
		product.setPrice(price);

		ProductBO bo = new ProductBOImpl();
		bo.create(product);

		PrintWriter out = response.getWriter();
		out.print("product created");
	}

}

实现 DisplayProductDetailsServelet

因为这里需要从 query param 中获取 id,所以如果没提供 query param 就会抛出 parse 异常

java 复制代码
package com.goldenaarcher.product.servlets;

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 com.goldenaarcher.product.bo.ProductBO;
import com.goldenaarcher.product.bo.ProductBOImpl;
import com.goldenaarcher.product.dto.Product;

/**
 * Servlet implementation class DisplayProductDetailsServelet
 */
public class DisplayProductDetailsServelet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ProductBO bo = new ProductBOImpl();
		Product product = bo.findProduct(Integer.parseInt(request.getParameter("id")));

		PrintWriter out = response.getWriter();
		out.print("Product details: ");
		out.print("Product ID: " + product.getId());
		out.print("Product Name: " + product.getName());
		out.print("Product Description: " + product.getDescription());
		out.print("Product Price: " + product.getPrice());
	}

}

最终创建和运行

这里会把 build install 拆分成几个部分简单解释一下

reactor

reactor 指的是 maven 能够根据项目的依赖,调整打包顺序的能力,maven 会根据其依赖关系调整打包的顺序。

bash 复制代码
❯ mvn clean install
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] productparent                                                      [pom]
[INFO] productservices                                                    [jar]
[INFO] productweb Maven Webapp                                            [war]
[INFO]
[INFO] --------------< com.goldenaarcher.product:productparent >---------------
[INFO] Building productparent 1.0                                         [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ productparent ---
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ productparent ---
[INFO] Installing /Users/usr/study/maven/parent/pom.xml to /Users/usr/.m2/repository/com/goldenaarcher/product/productparent/1.0/productparent-1.0.pom
打包子项目

这里 maven 会将 service 的项目打包到 m2 的文件夹中让其他的项目使用,这里 web 就需要调用 service 中的内容。

bash 复制代码
[INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ productservices ---
[INFO] Building jar: /Users/usr/study/maven/parent/productservices/target/productservices-1.0.jar
[INFO]
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ productservices ---
[INFO] Installing /Users/usr/study/maven/parent/productservices/target/productservices-1.0.jar to /Users/usr/.m2/repository/com/goldenaarcher/product/productservices/1.0/productservices-1.0.jar
[INFO] Installing /Users/usr/study/maven/parent/productservices/pom.xml to /Users/usr/.m2/repository/com/goldenaarcher/product/productservices/1.0/productservices-1.0.pom
[INFO]

其他项目打包部分与其他的 maven 差不多,这里不多赘述。

这里的功能实现完了,war 也打包完了,可以直接放到服务器上运行。本质上来说,war 中的内容和 target 中的 productweb 结构是一样的,前者是后者的压缩版。

最终运行结果

依旧是在 eclipse 中的 tomcat 运行服务器,所有的功能都实现了,最终的运行结果如下:

CSS 会不太一样,我笔记里改了一点 CSS。

相关推荐
Csvn1 小时前
OpenSpec 详细使用教程
前端
方也_arkling1 小时前
【Java-Day08】static / final / 枚举
java·开发语言
橙淮1 小时前
Spring Bean作用域与生命周期全解析
java·spring
Chengbei112 小时前
一站式源码安全检测工具、云安全 / APP / 小程序源码敏感信息递归多层目录扫描AK、JWT、手机号、身份证等敏感信息
java·开发语言·安全·web安全·网络安全·系统安全·安全架构
llz_1122 小时前
web-第一次课后作业
java·开发语言·idea
之歆2 小时前
Day19_LESS 完全指南——从入门到工程实践
前端·css·less
秋92 小时前
Java项目运行5天左右自动宕机:系统性定位与解决方案
java·开发语言·python
小江的记录本2 小时前
【JVM虚拟机】垃圾回收GC:垃圾收集器:CMS:核心原理、回收流程、优缺点、废弃原因(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·spring·面试·maven
DIY源码阁2 小时前
JavaSwing学生成绩管理系统 - MySQL版
java·数据库·mysql·eclipse
云水一下3 小时前
HTML5 从入门到精通:实战收官——从零搭建完整静态网站,综合运用所有知识
前端·html5