day11 部门管理实战

day11

计划

  1. 前后端分离开发规范与REST风格
  2. 工程搭建与基础代码结构
  3. 部门管理CRUD功能实现
  4. 参数接收方式详解
  5. MyBatis结果映射与驼峰命名
  6. Nginx部署与前后端联调
  7. Logback日志技术

笔记

1.前后端分离开发

前后端分离

将工程拆分为前端工程和后端工程,各自独立开发、独立部署。前端通过异步请求获取数据,后端根据接口文档提供数据。

开发流程
  1. 需求分析 → 理解产品原型和需求文档
  2. 接口定义 → 查阅接口文档,明确地址、参数、响应
  3. 前后端并行开发 → 各自按接口文档实现
  4. 接口测试 → 使用Apifox/Postman等工具测试后端接口
  5. 前后端联调 → 前端请求后端接口,验证整体功能

2.RESTful风格

传统URL vs RESTful
操作 传统URL RESTful URL
查询 /user/getById?id=1 GET /users/1 GET
新增 /user/saveUser POST /users POST
修改 /user/updateUser POST /users PUT
删除 /user/deleteUser?id=1 GET /users/1 DELETE
RESTful核心规则
  • URL定位资源:使用名词复数形式(如/depts/emps
  • HTTP动词描述操作:GET查询、POST新增、PUT修改、DELETE删除
  • 一句话总结:通过URL定位资源,通过HTTP请求方式描述操作

3.工程搭建

依赖引入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
application.yml配置
1
2
3
4
5
6
7
8
9
10
11
12
13
spring:
application:
name: tlias-web-management
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/tlias
username: root
password: 1234

mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
包结构
1
2
3
4
5
6
com.zhang
├── controller/ # 控制层:接收请求、响应结果
├── service/ # 业务层:业务逻辑
│ └── impl/ # 业务实现类
├── mapper/ # 数据访问层:执行SQL
└── pojo/ # 实体类

4.统一响应结果Result

1
2
3
4
5
6
7
8
9
10
@Data
public class Result {
private Integer code; // 1成功,0失败
private String msg; // 提示信息
private Object data; // 响应数据

public static Result success() { ... } // 无数据返回
public static Result success(Object data) { ... } // 有数据返回
public static Result error(String msg) { ... } // 返回错误信息
}

5.部门管理CRUD

5.1 查询部门列表

Controller:

1
2
3
4
5
@GetMapping("/depts")
public Result list(){
ArrayList<Dept> data = deptService.findAll();
return Result.success(data);
}

**Service:**调用Mapper查询所有部门。

Mapper:

1
2
@Select("select id, name, create_time, update_time from dept")
ArrayList<Dept> findAll();
5.2 删除部门(根据ID)

请求方式: DELETE
请求路径: /depts?id=1

1
2
3
4
5
@DeleteMapping("/depts")
public Result deleteById(Integer id){
deptService.deleteById(id);
return Result.success();
}

Mapper:

1
2
@Delete("delete from dept where id=#{id}")
void deleteById(Integer id);
5.3 新增部门

请求方式: POST
请求路径: /depts
请求参数: JSON格式 {"name":"研发部"}

1
2
3
4
5
@PostMapping("/depts")
public Result insert(@RequestBody Dept dept){
deptService.insert(dept);
return Result.success();
}

**Service:**补全createTime和updateTime

1
2
3
4
5
public void insert(Dept dept) {
dept.setCreateTime(LocalDateTime.now());
dept.setUpdateTime(LocalDateTime.now());
deptMapper.insert(dept);
}

Mapper:

1
2
@Insert("insert into dept(name,create_time,update_time) values(#{name},#{createTime},#{updateTime})")
void insert(Dept dept);
5.4 根据ID查询部门

请求方式: GET
请求路径: /depts/1(路径参数)

1
2
3
4
5
@GetMapping("/depts/{id}")
public Result getById(@PathVariable("id") Integer id){
Dept dept = deptService.getById(id);
return Result.success(dept);
}
5.5 修改部门

请求方式: PUT
请求路径: /depts
请求参数: JSON格式 {"id":1,"name":"研发部"}

1
2
3
4
5
@PutMapping("/depts")
public Result update(@RequestBody Dept dept){
deptService.update(dept);
return Result.success();
}

**Service:**更新updateTime

1
2
3
4
public void update(Dept dept) {
dept.setUpdateTime(LocalDateTime.now());
deptMapper.update(dept);
}

6.参数接收方式

6.1 简单参数接收
方式 代码示例 说明
HttpServletRequest request.getParameter("id") 繁琐,需手动转换,不推荐
@RequestParam @RequestParam("id") Integer id 指定参数名,推荐
形参同名 Integer id(参数名与形参名一致时) 最简洁,推荐
1
2
3
4
5
// 方式一:@RequestParam
public Result delete(@RequestParam("id") Integer id)

// 方式二:省略注解(参数名与形参名一致)
public Result delete(Integer id)
6.2 JSON参数接收

使用@RequestBody注解,Spring自动将JSON数据反序列化为Java对象。

1
public Result save(@RequestBody Dept dept)

注意:JSON的key必须与实体类的属性名一致。

6.3 路径参数接收

使用@PathVariable注解,从URL路径中获取参数。

1
2
@GetMapping("/depts/{id}")
public Result getById(@PathVariable("id") Integer id)

7.请求方式映射注解

注解 对应请求方式 用途
@GetMapping GET 查询数据
@PostMapping POST 新增数据
@PutMapping PUT 修改数据
@DeleteMapping DELETE 删除数据
@RequestMapping 所有方式 可通过method属性限定

推荐:使用@GetMapping等衍生注解,比@RequestMapping更简洁、语义更清晰。

类级别@RequestMapping

将公共路径抽取到类上,方法上的路径与类上的路径拼接形成完整请求路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RequestMapping("/depts")
@RestController
public class DeptController {

@GetMapping // 完整路径:/depts
public Result list() { ... }

@DeleteMapping // 完整路径:/depts
public Result delete(Integer id) { ... }

@PostMapping // 完整路径:/depts
public Result insert(@RequestBody Dept dept) { ... }

@GetMapping("/{id}") // 完整路径:/depts/{id}
public Result getById(@PathVariable Integer id) { ... }

@PutMapping // 完整路径:/depts
public Result update(@RequestBody Dept dept) { ... }
}

8.MyBatis结果映射

问题:属性名与字段名不一致

实体类属性(createTime)与数据库字段(create_time)命名风格不同,导致MyBatis无法自动封装。

三种解决方案
方案 代码示例 说明
手动映射 @Results({@Result(column="create_time",property="createTime")}) 灵活但繁琐
SQL起别名 select create_time createTime from dept 简单直接
驼峰映射 配置map-underscore-to-camel-case: true 推荐
驼峰命名配置

application.yml中开启自动驼峰命名映射:

1
2
3
mybatis:
configuration:
map-underscore-to-camel-case: true

映射规则create_timecreateTimeupdate_timeupdateTime

9.Nginx与前后端联调

Nginx核心功能
功能 说明
Web服务器 托管静态资源(HTML、CSS、JS、图片)
反向代理 转发客户端请求到后端服务器
负载均衡 将请求分发到多台后端服务器
请求流程
1
浏览器 → Nginx(:90) → 后端Tomcat(:8080) → Nginx → 浏览器
  1. 浏览器访问 http://localhost:90/api/depts
  2. Nginx接收到请求,根据/api/前缀匹配规则
  3. Nginx重写路径:/api/depts/depts
  4. Nginx将请求转发到 http://localhost:8080/depts
  5. 后端处理完返回数据,Nginx将结果返回给浏览器
Nginx关键配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server {
listen 90;
server_name localhost;

# 前端页面
location / {
root html;
index index.html;
try_files $uri $uri/ /index.html;
}

# 后端API代理
location ^~ /api/ {
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://localhost:8080;
}
}

配置说明

配置项 作用
location / 匹配所有路径,返回前端页面
try_files 支持前端路由刷新不404
location ^~ /api/ 精确匹配API前缀,不再检查正则
rewrite 去掉/api/前缀,重写路径
proxy_pass 转发请求到后端服务器
为什么使用Nginx
  • 安全:后端Tomcat集群不直接暴露给前端
  • 灵活:后端增减服务器对前端无感知
  • 负载均衡:便于实现多服务器负载均衡

10.Apifox接口测试

Apifox是集成了API文档、调试、Mock、测试的协作平台。

使用步骤
  1. 创建项目,导入或编写接口文档
  2. 在”接口管理”中定义接口(路径、方法、参数、响应)
  3. 在”接口调试”中发送请求测试
  4. 在”Mock服务”中生成模拟数据供前端开发
  5. 支持GET/POST/PUT/DELETE等所有请求方式

11.Logback日志

为什么使用日志框架
System.out.println Logback
硬编码,不灵活 可通过配置文件控制
只能输出到控制台 支持输出到文件
无日志级别 支持debug/info/warn/error级别
不便于维护 灵活配置格式和输出位置
Logback入门

1. 引入依赖(SpringBoot已内置)

2. 配置文件logback.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 控制台输出 -->
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>

<!-- 文件输出 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
<MaxHistory>30</MaxHistory>
<maxFileSize>10MB</maxFileSize>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50}-%msg%n</pattern>
</encoder>
</appender>

<root level="ALL">
<appender-ref ref="STDOUT" />
<appender-ref ref="FILE" />
</root>
</configuration>

3. 获取Logger对象

1
2
3
4
5
6
7
8
// 方式一:声明Logger对象
private static final Logger log = LoggerFactory.getLogger(ClassName.class);

// 方式二:使用Lombok @Slf4j注解
@Slf4j
public class ClassName {
// 自动生成log对象
}

4. 记录日志

1
2
3
4
log.debug("调试信息");
log.info("运行信息");
log.warn("警告信息");
log.error("错误信息");
日志级别
级别 说明 优先级
trace 追踪(很少使用)
debug 调试
info 运行信息
warn 警告
error 错误

规则:设置的级别越高,输出的日志越少。如设置info级别,则debug和trace级别不会输出。

12.核心知识点总结

知识点 说明
前后端分离 前端独立工程、后端独立工程,通过接口文档协作
RESTful风格 URL定位资源(复数名词),HTTP动词描述操作
@GetMapping GET请求查询数据
@PostMapping POST请求新增数据
@PutMapping PUT请求修改数据
@DeleteMapping DELETE请求删除数据
@RequestBody 接收JSON格式参数
@RequestParam 接收URL查询参数
@PathVariable 接收URL路径参数
@RequestMapping 类级别公共路径抽取
Result 统一响应封装类
map-underscore-to-camel-case 下划线自动转驼峰映射
Nginx 静态服务器+反向代理+负载均衡
Apifox 接口文档编写与测试工具
Logback 日志框架,支持控制台和文件输出
日志级别 debug < info < warn < error