JavaWeb 笔记 03 (31 - 45)

Maven, 单元测试, Web 基础相关 (31 - 45)

提前声明:本文章仅作个人学习记录,不涉及商业用途。

内容记录于学习途中, 没有按分类进行总结, 可能存在错误或不完整之处。

视频地址

在线讲义地址

第一章 Maven

Maven 官网

一、概述

1. 构建生命周期 / 阶段

生命周期 描述
clean 清理项目
compile 编译项目
test 测试项目
package 打包项目

2. 项目对象模型 (POM)

<groupId>com.fallw</groupId>
<artifactId>maven-project01</artifactId>
<!-- 快照版本 -->
<version>1.0-SNAPSHOT</version>

<properties>
  <!-- 源代码 JDK 版本 -->
  <maven.compiler.source>21</maven.compiler.source>
  <!-- 字节码 JVM 版本 -->
  <maven.compiler.target>21</maven.compiler.target>
  <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

3. 项目依赖管理 (Dependency)

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.14.0</version>
</dependency>

依赖查找顺序:本地仓库 \(\leftrightarrow\) 远程仓库(私服)\(\leftrightarrow\) 中央仓库

二、Maven 配置

1. settings.xml

<!-- 56 行 本地仓库路径 -->
<localRepository>D:\Environment\apache-maven-3.9.14\repository</localRepository>

<!-- 162 行 私服地址 -->
<mirror>
  <id>alimaven</id>
  <name>aliyun maven</name>
  <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
  <mirrorOf>central</mirrorOf>
</mirror>

<!-- 229 行 默认 JDK 版本 -->
<profile>
  <id>jdk-21</id>
  <activation>
    <activeByDefault>true</activeByDefault>
    <jdk>21</jdk>
  </activation>
  <properties>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
    <maven.compiler.compilerVersion>21</maven.compiler.compilerVersion>
  </properties>
</profile>

2. IntelliJ IDEA 配置

全局配置
  1. Build Tools \(\rightarrow\) Maven \(\rightarrow\) Maven home directory, User settings file, Local repository
  2. Build Tools \(\rightarrow\) Maven \(\rightarrow\) Runner \(\rightarrow\) JRE
  3. Compiler \(\rightarrow\) Java Compiler \(\rightarrow\) Project bytecode version

三、依赖管理

1. 依赖配置

<!-- 依赖配置 -->
<dependencies>
  <dependency>...</dependency>
</dependencies>
<!-- 排除配置 -->
<exclusions>
  <exclusion>...</exclusion>
</exclusions>

2. 生命周期

Maven 中有三套相互独立的生命周期:

  • clean:清理项目,删除目标目录
  • default:默认生命周期,包含 compile、test、package 等阶段
  • site:生成项目站点文档
生命周期 命令 具体功能
clean mvn clean 删除项目目录下的 target 目录
compile mvn compile 编译项目源代码,生成 .class 文件
test mvn test 执行 test 下的测试类
package mvn package 将项目打包成一个 jar 包安装到本项目的 target
install mvn install 将项目安装到本地仓库

在同一套生命周期中,运行后面的阶段时,前面的阶段都会运行。

第二章 单元测试

一、测试概述

测试方式

测试方式 目的
白盒测试 验证代码与逻辑的正确性
黑盒测试 验证软件的功能与兼容性
灰盒测试 同时考虑白盒和黑盒测试

测试步骤

测试步骤 目的 测试方式
单元测试 检验项目代码的基本单位的正确性 白盒测试
集成测试 检验项目之间的协作是否符合预期 灰盒测试
系统测试 验证软件系统的正确性与性能 黑盒测试
验收测试 验证软件系统是否与客户需求一致 黑盒测试

二、JUnit

优点:

  1. 测试代码与源代码分开,便于维护。
  2. 一个测试方法执行失败,不会影响其他测试方法。
  3. 自动生成测试报告,红色失败,绿色成功。

1. pom.xml 引入 JUnit

<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <version>5.9.1</version>
  <scope>test</scope>
</dependency>

2. 测试类

// 单元测试类命名规范:XxxTest。
public class GetAgeTest {
  @Test
  // JUnit 测试方法必须声明为 public void。
  public void testGetAge(){
    Integer age = new UserService().getAge("110002200505091218");
    System.out.println(age);
  }
}

三、断言

1. Assertions 类

断言方法 描述
Assertions.assertEquals(Object exp,Object act, String msg) 断言两个值是否相等
Assertions.assertNotEquals(Object unexp,Object act, String msg) 断言两个值是否不相等
Assertions.assertTrue(boolean exp, String msg) 断言 boolean 值为 true
Assertions.assertFalse(boolean exp, String msg) 断言 boolean 值为 false
Assertions.assertNull(Object exp, String msg) 断言对象为 null
Assertions.assertNotNull(Object exp, String msg) 断言对象不为 null
Assertions.assertThrows(Class expType, Executable exp, String msg) 断言抛出指定异常

2. 常见注解

注解 描述 备注
@Test 标记测试方法
@ParameterizedTest 标记参数化测试方法 无需使用 @Test
@ValueSource 为参数化测试方法提供测试参数 @ParameterizedTest 一起使用
@DisplayName 为测试方法的显示名称 默认为类名、方法名
@BeforeEach 在每个测试方法之前执行 初始化资源
@AfterEach 在每个测试方法之后执行 释放资源
@BeforeAll 在所有测试方法之前执行 static 初始化资源,只执行一次
@AfterAll 在所有测试方法之后执行 static 释放资源,只执行一次

3. 依赖范围

<scope>test</scope>

依赖范围 main test package 范例
compile (default) Y Y Y log4j
test - Y - junit
provided Y Y - servlet-api
runtime - Y Y jdbc driver

4. 常见问题

IDEA 配置文件目录:C:\Users\fallw\AppData\Roaming\JetBrains

Maven 删除不完整依赖:del /s *.lastUpdated

使用 SpringBoot 4 时发生依赖冲突:安装最新版 IDEA(2025.3)。

第三章 Web 基础

一、SpringBoot Web

Spring 官网

1. SpringBoot Web

官方 Starters 文档

修改起步依赖:Generate... \(\rightarrow\) Edit Starters

阿里云脚手架:https://start.aliyun.com/

<!-- SpringBoot 4.0.5 -->
<!-- Web 开发  -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<!-- 单元测试 -->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-webmvc-test</artifactId>
  <scope>test</scope>
</dependency>

查询依赖版本:spring-boot-starter-parent \(\rightarrow\) spring-boot-dependencies \(\rightarrow\) ${lombok.version}

功能 说明
内嵌服务器 集成 Tomcat,运行 main 启动 Web 项目
Spring MVC 提供 @RestController 等注解处理 HTTP 请求
RESTFul 支持 自动配置 JSON 处理,把 Java 对象转为 JSON
参数绑定 将前端传递的参数映射到 Java 方法参数上

2. 常用注解

领域 注解 位置 写法与常用参数
核心控制器与映射 @RestController @RestController
@RequestMapping @RequestMapping("/api/orders")
方法 @RequestMapping(value = "/list", method = RequestMethod.GET)
@GetMapping 方法 @GetMapping("/{id}")
@PostMapping 方法 @PostMapping("/save")
@PutMapping 方法 @PutMapping("/update")
@DeleteMapping 方法 @DeleteMapping("/{id}")
参数接收 @PathVariable 方法参数 @PathVariable("id") Long id
@RequestParam 方法参数 @RequestParam(name="page", defaultValue="1") Integer p
@RequestBody 方法参数 @RequestBody UserDTO dto (接收JSON)
@RequestHeader 方法参数 @RequestHeader("Authorization") String token
响应与异常处理 @ResponseStatus 方法 @ResponseStatus(HttpStatus.CREATED)
@RestControllerAdvice @RestControllerAdvice (全局异常拦截)
@ExceptionHandler 方法 @ExceptionHandler(Exception.class)
跨域配置 @CrossOrigin 类 / 方法 @CrossOrigin(origins = "*")

二、HTTP (Hyper Text Transfer Protocol)

1. 特点

  1. 基于 TCP 协议
  2. 基于请求响应模型
  3. 无状态:多次请求不能共享数据、速度快

2. 请求协议

测试样例
@RestController
public class HelloController {
  @RequestMapping("/hello")
  public String hello(@RequestParam(value = "name", defaultValue = "world") String name) {
    return "hello, " + name;
  }
}
请求行
### HTTP Request Analysis
# @Method: GET
# @Path: /hello
# @Query-String: name=fallw
# @Protocol: HTTP/1.1

GET /hello?name=fallw HTTP/1.1
# [Request-Line] 定义请求方法、请求资源路径及协议版本
请求头
Host: 127.0.0.1:8080
# [Host] 指定目标服务器的域名或 IP 地址及端口号(HTTP/1.1 必须字段)

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
# [Content-Negotiation] 客户端可处理的媒体类型(MIME)及其权重优先级(q-factor)

Accept-Encoding: gzip, deflate, br, zstd
# [Content-Encoding] 客户端支持的内容压缩/编码算法列表

Accept-Language: zh-CN,zh-TW;q=0.9,zh;q=0.8,en-US;q=0.7,en;q=0.6
# [I18N] 客户端首选的自然语言及地区偏好

Connection: keep-alive
# [Connection-Management] 显式要求建立持久连接以复用 TCP 通道

Cookie: session-4a3fb776=eyJjc3Jm...; session-4a3fb776.sig=TytA...
# [State-Management] 客户端存储的键值对凭证,用于维持服务器端的会话状态

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 Edg/146.0.0.0
# [Client-Identification] 包含操作系统、浏览器内核及版本的软件代理标识

Upgrade-Insecure-Requests: 1
# [Security] 指示客户端偏好加密连接,并可处理服务器的 HTTPS 重定向

Sec-Fetch-Dest: document
Sec-Fetch-Mode: navigate
Sec-Fetch-Site: none
Sec-Fetch-User: ?1
# [Fetch-Metadata] 浏览器自动生成的请求上下文信息,用于服务端进行安全审计与 CSRF 防御

sec-ch-ua: "Chromium";v="146", "Not-A.Brand";v="24", "Microsoft Edge";v="146"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
# [Client-Hints] 现代浏览器提供的结构化用户代理信息,旨在减少指纹追踪并提高解析效率
请求体
// POST 请求,存放请求参数
{ "name": "fallw" }
请求数据格式
字段 描述
Host 请求的主机名
User-Agent 浏览器版本,Chrome 的标识类似 Mozail/5.0 ... Chrome/146,IE 的标识类似 Mozail/5.0(Windows NT ...) like Gecko
Accept 浏览器可接受资源类型, 如 text/*, */* 表示所有
Accept-Language 浏览器可接受语言,如 zh-CN
Accept-Encoding 浏览器可支持的压缩类型,例如 gzip, deflate
Content-Type 请求主体的请求类型 application/json
Content-Length 请求主体的大小(单位:字节)
请求元数据
分类 请求头 (Key) 取值 (Value) 技术定义与安全逻辑
Fetch Metadata
(请求来源元数据)
Sec-Fetch-Site same-origin 请求发起方与目标资源完全同源(协议、域名、端口一致)。信任度最高。
same-site 请求发起方与目标资源属于同一站点(二级域名相同)。常用于子域间跳转。
cross-site 请求由第三方站点发起。此类请求存在 CSRF 风险,服务端需校验 Token。
none 用户直接触发请求(如地址栏输入、书签点击、文件拖拽)。视为用户主动意图。
Fetch Metadata
(请求模式)
Sec-Fetch-Mode navigate 用于 HTML 文档的导航/跳转请求(点击链接、表单提交)。
cors 跨域资源共享请求(由 fetchXMLHttpRequest 发起)。
no-cors 非跨域模式,通常用于加载图片、脚本等静态资源。
websocket 专门用于 WebSocket 协议的握手请求。
Fetch Metadata
(目标类型)
Sec-Fetch-Dest document 请求的目标是完整的 HTML 文档(页面渲染)。
image / script / style 请求的目标是特定的静态资源文件。
empty 请求目标不涉及渲染(如 API 接口调用或预加载请求)。
交互标识 Sec-Fetch-User ?1 / ?0 标识请求是否由用户激活(如点击、按键)触发。?1 表示用户激活。
Client Hints
(客户端提示)
sec-ch-ua "Brand";v="Ver" 结构化的浏览器品牌与主要版本号,用于替代冗长的 User-Agent。
sec-ch-ua-mobile ?0 / ?1 布尔型标识。?1 代表移动端设备,?0 代表非移动端。
sec-ch-ua-platform "Windows" 操作系统名称。相较于 UA 字符串,格式更加固定,便于后端解析。

3. 请求获取 HttpSerletRequest

分类 方法 示例返回结果
请求基本信息 getMethod() GET
getScheme() http
getProtocol() HTTP/1.1
路径相关 getRequestURI() /hello
getRequestURL().toString() http://localhost:8080/hello
getContextPath() (根路径通常为空)
参数相关 getQueryString() name=fallw
getParameter("name") fallw
请求头相关 getHeader("User-Agent") Mozilla/5.0...
getCookies() Cookie[] (需遍历获取值)
网络属性 getRemoteAddr() 127.0.0.1
getLocalPort() 8080

4. 响应协议

响应行
HTTP/1.1 200
# [Status Line] 响应状态行:包含协议版本(HTTP/1.1)和状态码(200 OK,表示请求成功)
响应头
Content-Type: text/html;charset=UTF-8
# [Content-Type] 指定响应实体的媒体类型(HTML 文档)及字符编码(UTF-8),告知浏览器如何渲染内容

Content-Length: 12
# [Content-Length] 指示响应正文的字节长度(此处 "hello, fallw" 刚好 12 字节)

Date: Sat, 04 Apr 2026 09:35:38 GMT
# [Date] 服务器生成响应的具体 GMT 时间

Keep-Alive: timeout=60
# [Keep-Alive] 配合 keep-alive 连接使用,告知客户端该 TCP 连接可以保持空闲的时间(秒)

Connection: keep-alive
# [Connection] 决定当前事务完成后是否关闭网络连接(keep-alive 表示保持持久连接,以复用 TCP 链路)
响应体
hello, fallw
# [Response Body] 响应正文:服务器实际返回给客户端的数据内容
响应状态码
状态码 描述
1xx 响应中 - 临时状态码
2xx 成功 - 响应成功
3xx 重定向 - 临时重定向或永久重定向
4xx 客户端错误 - 错误请求
5xx 服务器错误 - 服务器内部错误

常用状态码

状态码 英文描述 解释
200 OK 客户端请求成功,即处理成功,这是我们最想看到的状态码
302 Found 指示所请求的资源已移动到由Location响应头给定的 URL,浏览器会自动重新访问到这个页面
304 Not Modified 告诉客户端,你请求的资源至上次取得后,服务端并未更改,你直接用你本地缓存吧。隐式重定向
307 Temporary Redirect 临时重定向,要求浏览器原封不动地(保持原请求方法和数据)向 Location 发送请求
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
403 Forbidden 服务器收到请求,但是拒绝提供服务,比如:没有权限访问相关资源
404 Not Found 请求资源不存在,一般是URL输入有误,或者网站资源被删除了
405 Method Not Allowed 请求方式有误,比如应该用GET请求方式的资源,用了POST
428 Precondition Required 服务器要求有条件的请求,告诉客户端要想访问该资源,必须携带特定的请求头
429 Too Many Requests 指示用户在给定时间内发送了太多请求(“限速”),配合 Retry-After(多长时间后可以请求)响应头一起使用
431 Request Header Fields Too Large 请求头太大,服务器不愿意处理请求,因为它的头部字段太大。请求可以在减少请求头域的大小后重新提交。
500 Internal Server Error 服务器发生不可预期的错误。服务器出异常了,赶紧看日志去吧
503 Service Unavailable 服务器尚未准备好处理请求,服务器刚刚启动,还未初始化好
307 临时重定向
HTTP/1.1 307 Temporary Redirect
# [Status Line] 临时重定向:告知客户端资源临时移动,但必须保留原始请求方法

Location: /new-temp-endpoint
# [Location] 指定目标新地址(浏览器会自动跳转至此)

Non-Authoritative Reason:
# 307 与 302 的区别:
# 302:允许浏览器将 POST 变更为 GET(历史遗留问题,行为不可控)
# 307:强制严谨,如果是 POST 请求,重定向后必须依然是 POST
响应数据格式
字段 描述
Content-Type 该响应内容的类型,如 text/html, application/json
Content-Length 该响应内容的长度(字节数)
Content-Encoding 该响应的压缩算法,如 gzip
Cache-Control 指定缓存控制策略,如 max-age=300
Set-Cookie 设置 Cookie

5. 响应获取

基于 Web 服务提供的 HttpServletResponse 获取响应
@RequestMapping("/response")
public void response(HttpServletResponse response) throws IOException {
  response.setStatus(401);                        // 响应状态码
  response.setHeader("name", "fallw");            // 响应体
  response.getWriter().write("response success"); // 响应体
}
分类 方法 示例代码或结果
状态码相关 setStatus(int sc) response.setStatus(200) (设置正常成功状态)
sendError(int sc, String msg) response.sendError(404, "Resource Not Found")
响应头相关 setHeader(String name, String value) response.setHeader("Cache-Control", "no-cache")
addCookie(Cookie cookie) Set-Cookie: user=fallw; Path=/ (在浏览器存入 Cookie)
setContentType(String type) text/html;charset=UTF-8 (告知浏览器解析格式)
正文内容相关 getWriter() PrintWriter (用于输出文本数据,如 HTML/JSON)
getOutputStream() ServletOutputStream (用于输出二进制数据,如图片)
重定向与转发 sendRedirect(String location) 302 / 307 (客户端自动跳转至新 URL)
encodeURL(String url) /hello;jsessionid=1A2B3C... (用于 URL 重写追踪会话)
网络属性/配置 setCharacterEncoding(String charset) UTF-8 (设置响应体的字符编码)
setContentLength(int len) Content-Length: 1024 (手动指定响应体大小)
基于 Spring 中提供的 ResponseEntity 获取响应
@RequestMapping("/response-entity")
public ResponseEntity<String> responseEntity() {
  return ResponseEntity
      .status(401)                      // 响应状态码
      .header("name", "fallw")          // 响应头
      .body("response-entity success"); // 响应体
}
posted @ 2026-03-19 23:01  fallw  阅读(15)  评论(0)    收藏  举报