JavaWeb学习笔记

Maven

Maven 不仅仅是一个构建工具,它是 Java 项目的管家。它通过标准化的方式解决了“Jar 包地狱”和构建流程混乱的问题。

JavaWeb 学习笔记-image

Maven 核心概述

Maven 的核心设计理念可以归纳为三点:

  • 约定优于配置:Maven 强制规定了标准的项目目录结构(如 src/main/java 放源码,src/test/java 放测试代码),减少了开发者的决策成本。

  • 依赖管理:这是 Maven 最强大的功能。它通过中央仓库机制,自动下载、管理项目所需的第三方库(Jar 包),并解决版本冲突。

  • 构建生命周期:提供了一套标准的构建流程(编译、测试、打包、部署),确保在任何环境下(Windows, Linux, Mac)构建结果的一致性。

核心概念:POM

项目对象模型是 Maven 的基石。项目中的所有配置(依赖、插件、构建目标)都集中在 pom.xml 文件中描述。

Maven 安装与环境配置

为了确保下载速度和环境稳定性,请务必完成以下配置步骤。

下载与解压

  • 下载:apache-maven-3.9.4-bin.zip

  • 解压:建议解压到无中文、无空格的路径,例如 D:\develop\apache-maven-3.9.4

核心配置 (conf/settings.xml)

这是 Maven 的“大脑”,我们需要修改它来适配本地环境。

配置本地仓库

默认情况下,Maven 会将下载的 Jar 包存放在 C:\Users\用户名\.m2\repository。为了防止 C 盘爆红,建议修改到指定目录。

<!-- 在 <settings> 标签内添加或修改 localRepository -->
<localRepository>D:\develop\apache-maven-3.9.4\mvn_repo</localRepository>

配置阿里云镜像

Maven 的中央仓库在国外,下载速度极慢。配置阿里云镜像可以将下载速度提升数倍。

<mirrors>
  <mirror>
    <id>alimaven</id>
    <name>aliyun maven</name>
    <!-- 阿里云公共仓库地址 -->
    <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
    <!-- 拦截 central 仓库的请求,重定向到阿里云 -->
    <mirrorOf>central</mirrorOf>
  </mirror>
</mirrors>

配置环境变量

为了让系统在命令行中识别 mvn 命令:

  • 新建系统变量:MAVEN_HOME = D:\develop\apache-maven-3.9.4

  • 编辑 Path 变量:添加 %MAVEN_HOME%\bin

验证安装

在命令行输入 mvn -v,若显示版本信息则安装成功。

IDEA 集成与项目创建

IntelliJ IDEA 内置了 Maven 支持,但为了版本兼容,通常建议使用我们刚刚安装的自定义 Maven

配置 IDEA 的 Maven 环境

  1. 打开 File -> Settings (或 Preferences)。

  2. 导航至 Build, Execution, Deployment -> Build Tools -> Maven

  1. Maven home path: 选择 Bundled (Maven 3) 旁边的下拉菜单,选择 Use Maven home path 并指向你的安装目录。

  2. User settings file: 确保指向你刚才修改过的 conf/settings.xml

创建 Maven 项目

  1. New Project -> 选择 Maven

  2. GroupId: 组织标识,通常是公司或组织的域名反转(如 com.example)。

  1. ArtifactId: 项目标识,即项目名称(如 my-app)。

  2. Version: 项目版本,通常为 1.0-SNAPSHOT(快照版)。

Maven 坐标

在 Maven 世界中,任何一个 Jar 包都通过“坐标”来唯一标识。你在 pom.xml 中引入依赖时,就是在填写这个坐标:

元素 说明 示例
groupId 所属组织/公司 org.springframework
artifactId 具体模块/项目名 spring-web
version 版本号 5.3.1

依赖管理

pom.xml<dependencies> 标签中添加依赖。

基本依赖

<dependencies>
    <!-- 引入 JUnit 用于单元测试 -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope> <!-- 作用域:仅在测试时生效 -->
    </dependency>
</dependencies>

排除依赖

有时,引入的 A 依赖会自动引入 B 依赖(传递性依赖),但你可能不需要 B,或者 B 的版本与你现有的冲突。这时需要排除:

<dependency>
    <groupId>org.example</groupId>
    <artifactId>project-A</artifactId>
    <version>1.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.unwanted</groupId>
            <artifactId>project-B</artifactId>
        </exclusion>
    </exclusions>
</dependency>

Maven 生命周期

Maven 的运行是基于一套标准的生命周期。当你执行后面的阶段时,前面的阶段会自动执行。

三大内置生命周期

  1. clean:清理工作。

    • mvn clean:删除 target 目录(包含编译后的 class 文件和打包文件)。
  2. default (核心):构建工作的核心。

    • mvn compile:编译源代码。

    • mvn test:运行单元测试。

    • mvn package:打包(生成 JAR 或 WAR)。

    • mvn install:将包安装到本地仓库,供其他项目使用。

  1. site:生成项目文档和报告。

实战命令

最常用的组合拳:mvn clean install

含义:先清理旧文件,重新编译、测试、打包,最后安装到本地仓库。

单元测试

Maven 默认集成了 Surefire 插件来运行单元测试。

测试分类

  • 白盒测试:关注代码内部逻辑。通常指开发人员编写的 JUnit 测试,覆盖率高。

  • 黑盒测试:关注功能输入输出,不关心内部实现。

  • 灰盒测试:介于两者之间。

Maven 中的测试规范

Maven 对测试代码有默认约定:

  • 测试类名必须以 Test 结尾(如 UserServiceTest)。

  • 测试方法必须使用 @Test 注解。

  • 测试代码位于 src/test/java 目录下。

当执行 mvn test 时,Maven 会自动扫描并运行这些测试。如果测试失败,构建过程会立即停止并报错,这保证了代码质量。

Web 基础

Web 基础与入门程序

Web 开发本质上是处理静态资源(HTML, CSS, JS)和动态资源(Java/Spring)。SpringBoot 极大地简化了动态资源的开发流程。

入门案例解析

在 SpringBoot 中,我们通过 Controller 层来接收浏览器请求。

package com.yu;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// @RestController = @Controller + @ResponseBody
// 意味着该类的所有方法返回的数据直接写入响应体,而不是跳转页面
@RestController
public class HelloController {
    
    // @RequestMapping 可以处理所有类型的 HTTP 请求
    @RequestMapping("/hello")
    public String hello(String name){
        // SpringMVC 会自动将请求参数中的 name 值注入到这里
        System.out.println("接收到的参数: " + name);
        return "Hello " + name;
    }
}

关键点@RestController 是构建 RESTful API 的核心注解,它省去了手动编写 JSON 转换代码的麻烦(通过 HttpMessageConverter 自动完成)。

HTTP 协议详解

HTTP 是 Web 通信的基石。理解请求与响应的结构对于调试接口至关重要。

请求数据

一个标准的 HTTP 请求由三部分组成:

  • 请求行:包含请求方法(GET/POST)、URL 路径和协议版本。

  • 请求头:包含元数据,如 User-Agent, Content-Type, Cookie 等。

  • 请求体:POST 请求中携带的具体数据(如 JSON 字符串或表单数据)。

获取请求数据

虽然可以使用原生的 HttpServletRequest 对象获取数据,但在实际开发中,我们更多使用 SpringMVC 的注解(如 @RequestParam@RequestBody)。以下是原生方式的演示:

package com.yu;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Arrays;

@RestController
public class RequestController {

    @RequestMapping("/request")
    public String request(HttpServletRequest request){
        // 1. 获取请求行信息
        String method = request.getMethod(); // GET, POST 等
        String url = request.getRequestURL().toString(); // 完整 URL
        String protocol = request.getProtocol(); // HTTP/1.1
        
        // 2. 获取请求参数 (主要针对 GET 参数或表单 POST)
        String name = request.getParameter("name");
        String age = request.getParameter("age");
        
        // 3. 获取 Cookie
        String cookie = Arrays.toString(request.getCookies());
        
        System.out.println(String.format("Method:%s, URL:%s, Name:%s", method, url, name));
        return "OK";
    }
}

响应数据

服务器处理完请求后,返回 HTTP 响应,同样包含三部分:

  • 响应行:协议版本、状态码(200, 404, 500)、状态消息。

  • 响应头:Content-Type, Content-Length, Server 等。

  • 响应体:返回给客户端的实际内容(HTML, JSON, 图片流等)。

设置响应数据的两种方式

package com.yu;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;

@RestController
public class ResponseController {

    // 方式一:使用原生 HttpServletResponse 对象(底层操作,较繁琐)
    @RequestMapping("/response")
    public void response(HttpServletResponse response) throws IOException {
        response.setStatus(200); // 设置状态码
        response.setHeader("Custom-Header", "ityu"); // 设置响应头
        response.getWriter().write("<h1>hello response</h1>"); // 写入响应体
    }

    // 方式二:使用 ResponseEntity(推荐,链式调用,优雅)
    @RequestMapping("/response2")
    public ResponseEntity<String> response2() {
        return ResponseEntity
                .status(201) // 状态码
                .header("Custom-Header", "ityu2") // 响应头
                .body("<h1>hello response</h1>"); // 响应体
    }
}

SpringBoot Web 案例:用户列表

这是一个典型的业务场景:读取数据并返回。这里演示了如何读取类路径下的资源文件并解析。

实体类

使用 Lombok 简化代码。

package com.yu.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Integer id;
    private String username;
    private String password;
    private String name;
    private Integer age;
    private LocalDateTime updateTime;
}

控制层逻辑

使用 Hutool 工具类简化 IO 操作,使用 Stream 流处理数据。

package com.yu.controller;

import cn.hutool.core.io.IoUtil;
import com.yu.pojo.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;

@RestController
public class UserController {

    @RequestMapping("/list")
    public List<User> list(){
        // 1. 加载资源文件 (user.txt 位于 resources 目录下)
        InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt");
        
        // 2. 读取所有行
        ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8, new ArrayList<>());
        
        // 3. 解析数据 (流式处理)
        List<User> userList = lines.stream().map(line -> {
            String[] parts = line.split(",");
            // 假设 txt 格式为: id,username,password,name,age,time
            Integer id = Integer.parseInt(parts[0]);
            String username = parts[1];
            String password = parts[2];
            String name = parts[3];
            Integer age = Integer.parseInt(parts[4]);
            LocalDateTime updateTime = LocalDateTime.parse(parts[5], DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
            return new User(id, username, password, name, age, updateTime);
        }).toList();
        
        // 4. 返回 JSON 数据
        return userList;
    }
}

分层解耦与架构设计

随着项目复杂度增加,代码维护变得困难。三层架构是解决这一问题的标准方案。

为什么要分层?

  • 高内聚,低耦合:每一层只关注自己的职责。

  • 便于维护与扩展:修改数据库不影响前端接口,修改业务逻辑不影响数据库操作。

三层架构职责

层级 注解 职责
Controller @Controller / @RestController 接收请求参数,调用 Service,返回响应结果。
Service @Service 处理业务逻辑(计算、校验),调用 DAO。
DAO @Repository / @Mapper 与数据库交互,执行 CRUD 操作。

控制反转与依赖注入

分层之后,层与层之间需要调用(例如 Controller 调用 Service)。如果直接在类中 new Service(),会导致代码耦合度过高。Spring 通过 IOC 和 DI 解决了这个问题。

核心概念

  • IOC:将对象的创建权交给 Spring 容器,而不是由程序员手动 new

  • DI:Spring 容器在运行时,自动将依赖的对象注入到组件中。

  • Bean:被 Spring 容器管理的对象。

实现思路

  1. 声明 Bean:在类上添加注解(@Component@Service@Controller@Repository)。

  2. 依赖注入:在需要使用的地方,通过 @Autowired 注入接口。

IOC 注解详解

虽然 @Component 是通用注解,但在 Web 开发中我们通常使用专用注解:

  • @Controller:用于控制层。

  • @Service:用于业务层。

  • @Repository:用于持久层。

注意:启动类(@SpringBootApplication)默认只扫描当前包及其子包。因此,确保你的组件类在启动类的子包路径下。

DI 注入方式与冲突解决

注入方式

  • 属性注入(推荐):直接在字段上加 @Autowired

  • 构造器注入:通过构造函数注入(Lombok 的 @RequiredArgsConstructor 可以简化此过程)。

  • Setter 注入:通过 set 方法注入。

解决类型冲突

当一个接口有多个实现类时,@Autowired(按类型注入)会报错。

@Service
public class UserServiceImpl1 implements UserService { ... }

@Service
@Primary // 1. 指定默认实现
public class UserServiceImpl2 implements UserService { ... }

// 在 Controller 中
@RestController
public class UserController {
    
    @Autowired // 此时会注入 UserServiceImpl2
    private UserService userService;

    // 2. 或者使用 @Qualifier 指定具体的 Bean 名称
    @Autowired
    @Qualifier("userServiceImpl1")
    private UserService anotherService;
}

@Autowired vs @Resource

特性 @Autowired (Spring) @Resource (Java 标准)
来源 Spring 框架提供 JDK (javax.annotation) 提供
注入规则 默认按类型注入 默认按名称注入
配合使用 常配合 @Qualifier 指定名称 可直接通过 name 属性指定

MySQL

SQL 语言分类详解

SQL(结构化查询语言)是用于管理关系数据库的标准语言。根据其功能,SQL 语句通常被分为四大类:DDLDMLDQLDCL

DDL - 数据定义语言

Data Definition Language (数据定义语言)

DDL 用于定义和管理数据库中的结构模式。它操作的是数据库对象的“骨架”,而不是其中的数据。

  • 核心作用: 创建、修改、删除数据库、表、索引、视图等对象。

  • 常用命令CREATEALTERDROPTRUNCATE

  • 关键特性

    • 操作对象: 数据库结构(如表、字段)。

    • 事务性: DDL 语句执行后会自动提交,通常无法通过 ROLLBACK 命令回滚。

    • 类比: 就像装修房子,决定哪里是墙,哪里是门,一旦敲定,改动成本较高。

常用命令示例

  1. CREATE (创建): 用于创建新的数据库或表。
-- 创建一个名为 'mydb' 的数据库
CREATE DATABASE mydb;

-- 在 'mydb' 中创建一个名为 'users' 的表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT, -- 主键,自增
    username VARCHAR(50) NOT NULL,     -- 用户名,非空
    email VARCHAR(100),                -- 邮箱
    age INT                            -- 年龄
);
  1. ALTER (修改): 用于修改现有表的结构。
-- 在 'users' 表中添加一个新字段 'phone'
ALTER TABLE users ADD COLUMN phone VARCHAR(20);

-- 修改 'age' 字段的数据类型
ALTER TABLE users MODIFY COLUMN age SMALLINT;
  1. DROP (删除): 用于删除整个数据库或表。
-- 删除 'users' 表,表结构和数据都将丢失
DROP TABLE users;
  1. TRUNCATE (清空): 用于快速清空表中的所有数据,但保留表结构。
-- 清空 'users' 表的所有记录,并重置自增主键
TRUNCATE TABLE users;

注意TRUNCATE 是 DDL 命令,执行速度快且不可回滚。而 DELETE FROM users; 是 DML 命令,可以带 WHERE 条件,且可以回滚。

DML - 数据操作语言

Data Manipulation Language (数据操作语言)

DML 用于对数据库表中的数据进行操作。

  • 核心作用: 对表中的记录进行增、删、改。

  • 常用命令INSERTUPDATEDELETE

  • 关键特性

    • 操作对象: 表中的数据行。

    • 事务性: DML 操作默认不会自动提交,可以在事务中使用 COMMIT 确认更改或使用 ROLLBACK 撤销更改。

    • 类比: 就像在装修好的房间里,往柜子里放东西、拿走东西或更换东西。

常用命令示例

  1. INSERT (插入): 向表中添加新记录。
-- 插入一条新记录
INSERT INTO users (username, email, age) VALUES ('Alice', 'alice@example.com', 25);

-- 批量插入多条记录
INSERT INTO users (username, email, age) VALUES 
('Bob', 'bob@example.com', 30),
('Charlie', 'charlie@example.com', 28);
  1. UPDATE (更新): 修改表中已存在的记录。
-- 将 'Alice' 的年龄修改为 26
UPDATE users SET age = 26 WHERE username = 'Alice';

警告: 执行 UPDATE 时务必加上 WHERE 子句,否则会更新表中的所有记录。

  1. DELETE (删除): 从表中移除记录。
-- 删除 'Bob' 的记录
DELETE FROM users WHERE username = 'Bob';

警告: 执行 DELETE 时也务必加上 WHERE 子句,否则会删除表中的所有记录。

DQL - 数据查询语言

Data Query Language (数据查询语言)

DQL 的核心就是 SELECT 语句,用于从数据库中检索数据。

  • 核心作用: 查询和获取数据。

  • 常用命令SELECT

  • 关键特性

    • 操作对象: 读取数据,不修改数据。

    • 事务性SELECT 语句本身不修改数据,因此不涉及事务提交或回滚。

    • 类比: 就像在房间里查找你需要的东西。

常用命令示例

-- 查询所有用户的所有信息
SELECT * FROM users;

-- 查询所有用户的用户名和邮箱
SELECT username, email FROM users;

-- 查询年龄大于 25 岁的用户
SELECT * FROM users WHERE age > 25;

-- 查询并按年龄降序排列
SELECT * FROM users ORDER BY age DESC;

DCL - 数据控制语言

Data Control Language (数据控制语言)

DCL 用于控制数据库的访问权限和安全性。

  • 核心作用: 管理数据库用户和权限。

  • 常用命令GRANTREVOKE

  • 关键特性

    • 操作对象: 用户账户和权限。

    • 事务性: DCL 语句执行后通常也会自动提交

    • 类比: 就像给不同的人分配不同房间的钥匙,决定谁能进、谁能看、谁能改。

常用命令示例

  1. GRANT (授权): 授予用户特定的权限。
-- 授予用户 'reader' 对 'users' 表的查询权限
GRANT SELECT ON mydb.users TO 'reader'@'localhost';

-- 授予用户 'editor' 对 'users' 表的查询和修改权限
GRANT SELECT, UPDATE ON mydb.users TO 'editor'@'localhost';
  1. REVOKE (撤销权限): 撤销之前授予用户的权限。
-- 撤销用户 'editor' 对 'users' 表的修改权限
REVOKE UPDATE ON mydb.users FROM 'editor'@'localhost';
posted @ 2026-04-01 10:46  Exungsh💫  阅读(21)  评论(0)    收藏  举报