Maven_HTTP_Tomcat详解

O泡李华 3

Maven + HTTP + Tomcat 详解

本章位置:第二阶段 Java 核心框架
前置知识:JavaSE、Servlet、JSP、MyBatis、Web CRUD
下一篇:MyBatis 进阶
学习目标:理解 Maven 的项目构建、HTTP 的请求响应模型、Tomcat 的部署运行机制,并掌握端口、Context Path、状态码、乱码、WAR 部署和 IDEA 配置。


一、为什么把 Maven、HTTP、Tomcat 放在一起学

Java Web 项目真正运行起来,可以看成:

Java 源码
↓
Maven 编译和打包
↓
WAR / exploded artifact
↓
Tomcat 部署
↓
浏览器发送 HTTP 请求
↓
Tomcat 找到 Servlet
↓
Servlet 处理请求
↓
HTTP 响应
↓
浏览器

三者分工:

Maven
负责项目构建和依赖管理

HTTP
负责客户端和服务器通信

Tomcat
负责接收 HTTP 并运行 Servlet

二、Maven 是什么

Maven 是 Java 常用的:

项目管理与构建工具

主要负责:

依赖管理
项目目录规范
编译
测试
打包
安装
发布

三、为什么需要 Maven

如果没有 Maven,使用 MyBatis、MySQL 驱动、JUnit、JSTL 等库时可能需要:

手工下载 jar
复制到 lib
配置 classpath
自己解决版本冲突

换电脑或者换项目后很容易出现:

jar 缺失
版本冲突
依赖路径错误

Maven 可以通过 pom.xml 自动管理。


四、Maven 项目坐标

一个 Maven 项目通常由:

groupId
artifactId
version

标识。

例如:

<groupId>com.example</groupId>
<artifactId>student-web</artifactId>
<version>1.0-SNAPSHOT</version>

其中:

groupId
组织、公司或项目组

artifactId
项目或模块名称

version
项目版本

五、SNAPSHOT

例如:

1.0-SNAPSHOT

表示:

当前是开发中的快照版本

正式发布时常见:

1.0.0
2.1.3

六、Maven 标准目录结构

project
│
├─ pom.xml
│
└─ src
   ├─ main
   │  ├─ java
   │  └─ resources
   │
   └─ test
      ├─ java
      └─ resources

传统 Web 项目还常有:

src/main/webapp

七、src/main/java

存放:

正式 Java 源代码

八、src/main/resources

存放:

properties
xml
Mapper XML
日志配置

编译后通常复制到:

target/classes

九、src/test/java

存放:

测试代码

十、pom.xml

pom.xml 是:

Project Object Model

它是 Maven 项目的核心配置。

常见内容:

项目坐标
依赖
插件
JDK 版本
编码
打包方式
模块

十一、基础 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.example</groupId>

    <artifactId>demo</artifactId>

    <version>1.0-SNAPSHOT</version>

</project>

十二、设置 JDK 17

推荐:

<properties>

    <maven.compiler.release>
        17
    </maven.compiler.release>

    <project.build.sourceEncoding>
        UTF-8
    </project.build.sourceEncoding>

</properties>

如果编译出现:

不支持发行版本 5

往往需要检查:

Maven 编译版本
IDEA Project SDK
Maven Runner JDK

十三、dependency

依赖写在:

<dependencies>

内部。

例如:

<dependency>

    <groupId>org.mybatis</groupId>

    <artifactId>mybatis</artifactId>

    <version>3.5.19</version>

</dependency>

十四、Maven scope

常见:

compile
provided
runtime
test

十五、compile

默认范围。

表示:

编译需要
运行也需要

例如:

MyBatis

十六、provided

表示:

编译需要
运行环境已经提供

典型:

Servlet API

因为 Tomcat 已经自带 Servlet API。


十七、test

只用于:

测试阶段

典型:

JUnit

十八、runtime

主要表示:

运行时需要

编译时不一定直接使用。


十九、本地 Maven 仓库

Windows 常见路径:

C:\Users\用户名\.m2\repository

Maven 下载的 jar 会保存在这里。


二十、远程仓库

如果本地仓库没有依赖:

Maven 会从远程仓库下载

常见:

Maven Central
公司私服
国内镜像

二十一、依赖下载失败

常见原因:

网络问题
版本不存在
settings.xml 错误
镜像配置错误
本地缓存损坏

IDEA 中可以尝试:

Reload All Maven Projects

二十二、Maven 生命周期

最常见命令:

clean
compile
test
package
install

二十三、mvn clean

mvn clean

删除:

target

清理旧构建结果。


二十四、mvn compile

mvn compile

编译:

src/main/java

生成:

target/classes

二十五、mvn test

mvn test

编译并执行:

测试代码

二十六、mvn package

mvn package

进行:

编译
测试
打包

Web 项目通常得到:

xxx.war

二十七、mvn install

mvn install

除了 package,还会:

把当前项目安装到本地 Maven 仓库

供其他项目依赖。


二十八、target 目录

构建后常见:

target/classes
target/test-classes
target/xxx.war

二十九、WAR 是什么

WAR:

Web Application Archive

传统 Servlet/JSP 项目通常:

<packaging>war</packaging>

然后交给:

Tomcat

部署。


三十、JAR 和 WAR

简单区分:

JAR
普通 Java 库或程序

WAR
传统 Java Web 应用

三十一、查看 Maven 依赖树

mvn dependency:tree

用于排查:

传递依赖
版本冲突
重复依赖

三十二、什么是传递依赖

例如:

项目 A
依赖 B

B
依赖 C

那么 A 可能自动获得:

C

这叫:

传递依赖

三十三、依赖冲突

如果:

A 依赖 X 1.0
B 依赖 X 2.0

最终 Maven 需要选择一个版本。

冲突可能导致:

ClassNotFoundException
NoSuchMethodError
运行结果异常

三十四、HTTP 是什么

HTTP:

HyperText Transfer Protocol

中文:

超文本传输协议

它规定:

客户端和服务器如何通信

三十五、HTTP 核心模型

客户端
发送 Request

服务器
返回 Response

浏览器访问:

http://localhost:8080/demo/hello

本质就是:

浏览器发送 HTTP 请求
Tomcat 返回 HTTP 响应

三十六、HTTP 请求组成

通常包括:

请求行
请求头
空行
请求体

三十七、请求行

例如:

GET /demo/student/list?pageNum=1 HTTP/1.1

其中:

GET
请求方法

/demo/student/list?pageNum=1
请求目标

HTTP/1.1
协议版本

三十八、HTTP 方法

常见:

GET
POST
PUT
PATCH
DELETE
HEAD
OPTIONS

三十九、GET

主要用于:

查询资源

例如:

列表
详情
搜索
分页

四十、POST

主要用于:

提交数据
创建资源
执行业务动作

例如:

新增
登录
表单提交

四十一、PUT / PATCH / DELETE

RESTful 中常见:

PUT
整体更新

PATCH
部分更新

DELETE
删除资源

四十二、请求头 Header

常见:

Host
User-Agent
Accept
Content-Type
Cookie
Authorization

四十三、Host

例如:

Host: localhost:8080

表示目标:

主机 + 端口

四十四、User-Agent

表示:

客户端信息

例如:

Chrome
Edge
手机浏览器

四十五、Accept

告诉服务器:

客户端希望接收什么类型

例如:

text/html
application/json

四十六、Content-Type

表示:

请求体或响应体的数据格式

常见:

application/x-www-form-urlencoded
multipart/form-data
application/json
text/html

四十七、普通表单

常见:

application/x-www-form-urlencoded

Servlet 可以:

request.getParameter(
        "username"
);

获取。


四十八、文件上传

常见:

multipart/form-data

四十九、JSON

前后端分离常见:

application/json

例如:

{
    "name": "张三",
    "age": 20
}

五十、Query String

例如:

/student/list?pageNum=2&keyword=java

其中:

pageNum=2
keyword=java

属于:

Query String Parameters

五十一、HTTP 响应组成

通常:

状态行
响应头
空行
响应体

五十二、状态行

例如:

HTTP/1.1 200 OK

五十三、常见状态码

200
成功

201
创建成功

204
成功,无响应体

302
临时重定向

304
缓存未修改

400
请求错误

401
未认证

403
无权限

404
资源不存在

405
请求方法不允许

500
服务器内部错误

502
网关错误

503
服务不可用

五十四、404

Java Web 中最常见原因:

项目没部署
Context Path 错
Servlet Mapping 错
URL 错
资源不存在

五十五、405

例如:

客户端发 POST

Servlet 却只实现:

doGet()

可能返回:

405 Method Not Allowed

五十六、500

表示服务器内部异常。

例如:

NullPointerException
SQL 异常
MyBatis 异常
Servlet 初始化失败
JSP JasperException

遇到 500:

优先看 Tomcat 控制台堆栈

五十七、HTTP 为什么叫无状态

每个 HTTP 请求本身:

相对独立

服务器不会仅凭一次请求天然知道:

你上一次是谁
你是否已经登录

所以通常通过:

Cookie
Session
Token

保持状态。


五十八、Cookie

服务器可以通过响应让浏览器保存 Cookie。

之后浏览器发送请求时:

自动带上 Cookie

五十九、Session 和 JSESSIONID

Tomcat 常使用:

JSESSIONID

作为 Session 标识。

流程:

服务器创建 Session
↓
返回 JSESSIONID Cookie
↓
浏览器保存
↓
下次请求带回
↓
Tomcat 找到对应 Session

六十、请求编码

旧式 Servlet 表单 POST:

request.setCharacterEncoding(
        "UTF-8"
);

必须在:

第一次 getParameter 之前

六十一、响应编码

response.setContentType(
        "text/html;charset=UTF-8"
);

要尽量在:

getWriter 之前

设置。


六十二、Tomcat 是什么

Tomcat 是:

Web 服务器
Servlet 容器

主要负责:

监听端口
接收 HTTP
解析请求
管理 Servlet
创建 request/response
调用 Servlet
返回 HTTP 响应

六十三、Tomcat 不是数据库

Tomcat
运行 Java Web

MySQL
保存业务数据

六十四、Tomcat 不是 JDK

JDK
Java 开发和运行环境

Tomcat
Servlet/JSP 容器

Tomcat 自己也需要:

Java 环境

才能运行。


六十五、CATALINA_HOME

表示:

Tomcat 安装目录

例如:

D:\apache-tomcat-8.5.65

六十六、CATALINA_BASE

表示:

当前 Tomcat 实例运行目录

IDEA 配置 Tomcat 后:

CATALINA_BASE
经常是 IDEA 自动生成的目录

这和 CATALINA_HOME 不同是正常的。


六十七、Tomcat 常见目录

bin
conf
lib
logs
temp
webapps
work

六十八、bin

包含:

startup.bat
shutdown.bat
catalina.bat

等脚本。


六十九、conf

包含:

server.xml
web.xml
context.xml
logging.properties

七十、lib

包含:

Tomcat 自己需要的 jar
Servlet API

七十一、logs

保存:

运行日志

七十二、webapps

独立 Tomcat 常用:

部署 WAR

七十三、work

JSP 被 Tomcat 翻译和编译后:

相关 Java / class

通常会出现在 work 目录。


七十四、server.xml

Tomcat 核心配置之一。

常见 Connector:

<Connector
        port="8080"
        protocol="HTTP/1.1"
        connectionTimeout="20000"
        redirectPort="8443"
        URIEncoding="UTF-8"
/>

七十五、port

port="8080"

表示:

Tomcat HTTP 监听 8080

浏览器:

http://localhost:8080

七十六、8080 被占用

如果出现:

Address already in use

说明:

8080 已有其他进程使用

Windows:

netstat -ano | findstr :8080

找到 PID。


七十七、查看 PID 对应进程

tasklist | findstr 进程号

确认是什么程序后,再决定是否关闭。


七十八、结束进程

taskkill /PID 进程号 /F

不要:

不确认进程就直接结束

七十九、修改 Tomcat 端口

可以改:

<Connector
        port="8081"
        protocol="HTTP/1.1"
/>

之后访问:

http://localhost:8081

八十、URIEncoding

正确拼写:

URIEncoding="UTF-8"

不要写成:

URIEconding

否则 Tomcat 会提示:

找不到匹配属性

八十一、Context Path

假设项目上下文:

/demo

Servlet:

@WebServlet(
        "/hello"
)

完整 URL:

http://localhost:8080/demo/hello

八十二、完整 URL 三部分

8080
端口

/demo
Context Path

/hello
Servlet Mapping

这三个经常被初学者混淆。


八十三、Tomcat 如何找到 Servlet

请求 /demo/hello
↓
找到 /demo Web 应用
↓
找到 /hello 映射
↓
找到 HelloServlet
↓
调用 service()
↓
分发 doGet / doPost

八十四、Tomcat 为什么叫 Servlet 容器

它负责:

创建 Servlet
管理生命周期
分发请求
管理 request/response
管理 Session
销毁 Servlet

八十五、Tomcat 8.5 和 Tomcat 10

这是必须注意的版本区别。

Tomcat 8.5 常见:

javax.servlet

Tomcat 10+:

jakarta.servlet

不要混用。


八十六、Servlet API 为什么用 provided

Tomcat 8.5 Maven 项目:

<dependency>

    <groupId>
        javax.servlet
    </groupId>

    <artifactId>
        javax.servlet-api
    </artifactId>

    <version>
        4.0.1
    </version>

    <scope>
        provided
    </scope>

</dependency>

因为运行时:

Tomcat 已经提供 Servlet API

八十七、IDEA 配置 Tomcat

一般:

Run
→ Edit Configurations
→ Tomcat Server
→ Local

然后设置:

Application Server
Deployment

八十八、Deployment

需要添加:

Artifact

例如:

student-web:war exploded

八十九、war exploded

表示:

以解压后的目录结构部署

开发阶段:

更新更方便

九十、Tomcat 启动成功不等于项目部署成功

Tomcat 可能:

正常监听 8080

但项目:

没有 Deployment

访问仍然:

404

九十一、Tomcat 控制台重点看什么

Tomcat version
CATALINA_HOME
CATALINA_BASE
端口
Deployment
Server startup
异常堆栈

九十二、404 排查顺序

1. Tomcat 是否启动

2. 端口是否正确

3. 项目是否部署

4. Context Path 是否正确

5. Servlet Mapping 是否正确

6. URL 是否正确

7. JSP 是否位于 WEB-INF

九十三、405 排查

请求 Method

form method

Servlet doGet/doPost

三者要对应。


九十四、500 排查

重点:

Tomcat 控制台
Caused by
Root Cause

不要只看浏览器的“500”。


九十五、JasperException

JSP 报:

JasperException

常见:

JSP 编译错误
JSP Java 脚本错误
标签库错误
运行时异常

重点看:

具体 JSP 行号

九十六、HTTP 与 Servlet 对应关系

HTTP:

GET
POST

HttpServlet:

doGet()
doPost()

Tomcat:

读取 HTTP Method
↓
调用 service()
↓
service 分发到 doGet/doPost

九十七、redirect 的 HTTP 本质

response.sendRedirect(
        "/login"
);

通常:

服务器返回 302
+
Location 响应头

浏览器:

重新发送一次请求

所以:

地址栏改变
request 也变了

九十八、forward 的本质

request
        .getRequestDispatcher(
                "/WEB-INF/views/a.jsp"
        )
        .forward(
                request,
                response
        );

是:

服务器内部转发

浏览器通常不知道。

所以:

地址栏不变
还是同一个 request

九十九、Maven 和 Tomcat 如何连接

Maven:

compile
↓
package
↓
WAR

Tomcat:

部署 WAR
↓
运行 Web Application

一百、IDEA 实际帮你做了什么

IDEA 配 Tomcat 后,大量步骤被自动完成:

编译
↓
生成 Artifact
↓
准备 war exploded
↓
启动 Tomcat
↓
部署 Web 项目

一百零一、为什么修改代码后没生效

可能:

编译失败
Artifact 没更新
Tomcat 没重新部署
浏览器缓存
修改的不是当前运行项目

一百零二、mvn clean 的意义

旧构建文件有问题时:

mvn clean

然后:

mvn package

重新构建。


一百零三、Maven 测试代码问题

如果 pom 中已经删除 JUnit:

src/test/java

中却还存在:

import org.junit.jupiter.api.Test;

执行 Maven 测试编译时仍然会报错。

所以:

依赖和代码必须匹配

一百零四、不要只删 dependency

如果测试代码仍然需要 JUnit:

就不能只把依赖删除

要么:

恢复依赖

要么:

删除/修改测试代码

一百零五、浏览器 F12 Network

必须掌握:

F12
→ Network

重点查看:

Request URL
Request Method
Status Code
Query String
Form Data
Request Payload
Request Headers
Response Headers
Response

一百零六、Java Web 排错三件套

浏览器 Network
看 HTTP

Tomcat 控制台
看服务端异常

MyBatis 日志
看 SQL

一百零七、完整排错路线

浏览器
↓
URL
↓
Method
↓
Status Code
↓
Tomcat
↓
Deployment
↓
Servlet
↓
Request 参数
↓
Service
↓
Mapper
↓
SQL
↓
Response / JSP

不要:

一报错就所有代码一起改

一百零八、练习 1:Maven 生命周期

依次执行:

mvn clean
mvn compile
mvn package

观察:

target

目录变化。


一百零九、练习 2:依赖树

mvn dependency:tree

找出:

MyBatis
MySQL Driver
JSTL

一百一十、练习 3:GET 请求

创建:

/hello

浏览器访问。

F12 查看:

GET
200

一百一十一、练习 4:POST 请求

创建:

login.html

提交:

POST /login

在 Network 查看:

Form Data

一百一十二、练习 5:404

故意访问错误地址:

/demo/abc-not-exist

观察:

404

然后按排错顺序定位。


一百一十三、练习 6:405

Servlet 只写:

doGet()

使用 POST 请求。

观察:

405

一百一十四、练习 7:500

Servlet 中临时:

throw new RuntimeException(
        "测试异常"
);

观察:

浏览器 500
Tomcat 控制台异常

一百一十五、练习 8:redirect

response.sendRedirect(
        request.getContextPath()
                + "/hello"
);

Network 观察:

302
↓
第二次 GET

一百一十六、练习 9:Context Path

假设:

端口 8080
Context Path /demo
Servlet /hello

手工写出完整:

http://localhost:8080/demo/hello

一百一十七、练习 10:端口冲突

PowerShell:

netstat -ano | findstr :8080

找到 PID 后:

tasklist | findstr PID

确认占用程序。


一百一十八、练习 11:乱码

分别测试:

GET 中文参数
POST 中文表单
响应中文

理解:

URIEncoding
request.setCharacterEncoding
response.setContentType

分别解决什么。


一百一十九、必须掌握 Maven

pom.xml
groupId
artifactId
version
dependency
scope
repository
clean
compile
test
package
install
dependency:tree
WAR

一百二十、必须掌握 HTTP

Request
Response
Method
URL
Header
Body
Query String
Content-Type
Cookie
Session
Status Code

一百二十一、必须掌握 Tomcat

Servlet Container
CATALINA_HOME
CATALINA_BASE
server.xml
Connector
port
Context Path
Deployment
Artifact
war
war exploded

一百二十二、必须回答的问题

学完以后应该能够回答:

1. Maven 是什么?

2. pom.xml 有什么作用?

3. groupId、artifactId、version 是什么?

4. compile、provided、test 有什么区别?

5. mvn clean、compile、package、install 分别做什么?

6. WAR 是什么?

7. HTTP 是什么?

8. Request 和 Response 分别由什么组成?

9. GET 和 POST 有什么区别?

10. Content-Type 是什么?

11. Cookie 和 Session 是什么关系?

12. 为什么 HTTP 是无状态协议?

13. 200、302、404、405、500 分别是什么?

14. Tomcat 是什么?

15. Tomcat 为什么叫 Servlet 容器?

16. CATALINA_HOME 和 CATALINA_BASE 有什么区别?

17. Context Path 是什么?

18. 8080 被占用怎么查?

19. Tomcat 8.5 和 Tomcat 10 的 servlet 包有什么区别?

20. 为什么 Servlet API 使用 provided?

21. war 和 war exploded 有什么区别?

22. redirect 为什么地址栏变化?

23. forward 为什么地址栏不变?

24. 项目启动后 404 应该怎么排查?

25. Java Web 出错应该按照什么顺序排查?

一百二十三、知识结构

Java Web
│
├─ Maven
│   ├─ POM
│   ├─ Dependency
│   ├─ Scope
│   ├─ Repository
│   ├─ Lifecycle
│   └─ WAR
│
├─ HTTP
│   ├─ Request
│   ├─ Response
│   ├─ Method
│   ├─ Header
│   ├─ Body
│   ├─ Cookie
│   └─ Status
│
└─ Tomcat
    ├─ Connector
    ├─ Port
    ├─ Context
    ├─ Deployment
    ├─ Servlet Container
    ├─ CATALINA_HOME
    └─ CATALINA_BASE

一百二十四、三者完整关系

Java 源码
↓
Maven
↓
compile
↓
package
↓
WAR
↓
Tomcat
↓
部署 Web App
↓
浏览器
↓
HTTP Request
↓
Tomcat Connector
↓
Servlet
↓
HTTP Response
↓
浏览器

这是本章最重要的一张图。


一百二十五、本章总结

Maven 解决:

项目怎么构建
依赖怎么管理
项目怎么打包

HTTP 解决:

浏览器和服务器如何通信

Tomcat 解决:

谁接收 HTTP
谁运行 Servlet
谁管理 Web 应用

Maven 必须掌握:

pom.xml
dependency
scope
clean
compile
package
WAR

HTTP 必须掌握:

Method
URL
Header
Body
Content-Type
Cookie
Status Code

Tomcat 必须掌握:

port
Context Path
Deployment
CATALINA_HOME
CATALINA_BASE
server.xml
Connector

排错顺序:

浏览器
↓
HTTP
↓
Tomcat
↓
Servlet
↓
Service
↓
Mapper
↓
数据库

按照课程表,下一篇进入:

MyBatis 进阶

重点会继续学习:

动态 SQL
复杂 resultMap
一对一
一对多
缓存
批处理
插件
执行流程