day11
计划
- 前后端分离开发规范与REST风格
- 工程搭建与基础代码结构
- 部门管理CRUD功能实现
- 参数接收方式详解
- MyBatis结果映射与驼峰命名
- Nginx部署与前后端联调
- Logback日志技术
笔记
1.前后端分离开发
前后端分离
将工程拆分为前端工程和后端工程,各自独立开发、独立部署。前端通过异步请求获取数据,后端根据接口文档提供数据。
开发流程
- 需求分析 → 理解产品原型和需求文档
- 接口定义 → 查阅接口文档,明确地址、参数、响应
- 前后端并行开发 → 各自按接口文档实现
- 接口测试 → 使用Apifox/Postman等工具测试后端接口
- 前后端联调 → 前端请求后端接口,验证整体功能
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; 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
| 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 public Result list() { ... } @DeleteMapping public Result delete(Integer id) { ... } @PostMapping public Result insert(@RequestBody Dept dept) { ... } @GetMapping("/{id}") public Result getById(@PathVariable Integer id) { ... } @PutMapping 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_time → createTime,update_time → updateTime
9.Nginx与前后端联调
Nginx核心功能
| 功能 |
说明 |
| Web服务器 |
托管静态资源(HTML、CSS、JS、图片) |
| 反向代理 |
转发客户端请求到后端服务器 |
| 负载均衡 |
将请求分发到多台后端服务器 |
请求流程
1
| 浏览器 → Nginx(:90) → 后端Tomcat(:8080) → Nginx → 浏览器
|
- 浏览器访问
http://localhost:90/api/depts
- Nginx接收到请求,根据
/api/前缀匹配规则
- Nginx重写路径:
/api/depts → /depts
- Nginx将请求转发到
http://localhost:8080/depts
- 后端处理完返回数据,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; }
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、测试的协作平台。
使用步骤
- 创建项目,导入或编写接口文档
- 在”接口管理”中定义接口(路径、方法、参数、响应)
- 在”接口调试”中发送请求测试
- 在”Mock服务”中生成模拟数据供前端开发
- 支持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
| private static final Logger log = LoggerFactory.getLogger(ClassName.class);
@Slf4j public class ClassName { }
|
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 |