学成在线-内容管理1

一、查询课程

1.需求分析

  • 确认用户需求
  • 确认关键问题
  • 梳理业务流程
  • 数据建模
  • 需求说明书

2.内容管理架构模型

image-20260227171202758

然后在pom文件中可以定义

3.pom文件父工程

3.1、<relativePath> 的俩种常见写法

写法 A:不写或者默认值(适用于“嵌套结构”)

如果你完全不写 <relativePath> 标签,Maven 的默认值是 ../pom.xml(即直接去上一级目录找)。 这是最传统的父子工程目录结构:

1
2
3
4
xuecheng-plus-parent/      (父工程目录)
├── pom.xml (父 POM)
└── xuecheng-plus-content/ (子工程目录,在父工程内部)
└── pom.xml (子 POM,不写 relativePath 默认去上一层找)

写法 B:自定义路径(适用于“平铺结构”)

有时候为了方便 Git 管理,团队会把父工程和各个子工程放在同一个级别的目录(平铺/扁平结构),而不是把子工程塞进父工程里面。

1
2
3
4
5
工作区文件夹 (workspace)/
├── xuecheng-plus-parent/ (父工程与子工程平级)
│ └── pom.xml
└── xuecheng-plus-content/ (子工程)
└── pom.xml (这里的 relativePath 必须写 ../xuecheng-plus-parent)

因为它们是平级的,所以子工程需要先退回上一层目录(..),再进入父工程的文件夹(xuecheng-plus-parent),这正是你这段代码的作用。如果不这么写,Maven 默认去上一级目录找 pom.xml 是找不到的

3.2、具体写法

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
27
28
29
<?xml version="1.0" encoding="UTF-8"?>
<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>



<parent>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-content</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>



<artifactId>xuecheng-plus-content-api</artifactId>


<dependencies>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xuecheng-plus-content-model</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>


</project>

4.课程内容接口设计

image-20260227182301770

5.接口流程

从底层出发

数据库 service 接口

  • 代码生成器

    1
    https://github.com/baomidou/generator

定义模型类

定义接口类(springMVC)

1
2
3
4
5
6
7
8
9
10
11
12

@RestController//相当于@Controller和@ResponseBody的结合,返回json数据
public class CourseBaseInfoController {

@RequestMapping("/course/list")
public PageResult<CourseBase> list(PageParams pageParams, @RequestBody QueryCourseParamsDto queryCourseParams){

return null;

}

}

image-20260227220650942

6.查询接口流程

先写 mapper 持久层代码

**接着 service **

接着完成controller

service 层

进行test测试类

依赖 -> 配置类 -> 编写测试代码

1
2
3
test resource文件
启动类复制
配置类 扫描子包以及插件注册

对于系统信息,一部分是 code 一部分是中文名,使用数据系统表存储

方法搞定之后单元测试

1
注入mapper

httpclient接口测试

postman工具太过笨重,swagger接口文档无法保存数据

httpclient应运而生

7.前后端联调

导入system工程

7.1、解决跨域问题CORS问题

同源:

跨域问题是由浏览器的同源策略(Same-Origin Policy)引起的。当你的前端应用和后端接口在协议(Protocol)、域名(Domain)或端口(Port)上存在任何不同时,浏览器出于安全考虑,会拦截前端向后端发起的请求或拦截后端返回的数据

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
1.CORS(跨域资源共享)
这是目前最官方、最推荐的解决方式。CORS 完全由后端进行配置,前端基本不需要做任何修改。

原理: 后端服务器在 HTTP 响应头中添加特定的字段,告诉浏览器允许哪些源(Origin)访问该资源。

核心响应头:
Access-Control-Allow-Origin:指定允许的域名,或者使用 * 允许所有
Access-Control-Allow-Methods:允许的 HTTP 方法(如 GET, POST, PUT)
Access-Control-Allow-Headers:允许携带的自定义请求头
Access-Control-Allow-Credentials:是否允许携带 Cookie(如果设为 true,Origin 不能为 *)

适用场景: 现代 Web 开发的绝大多数场景

2. 代理服务器(Proxy / 反向代理)
同源策略是浏览器的限制,服务器与服务器之间进行通信是没有同源策略限制的。利用这一特点,可以设置一个与前端同源的代理服务器来转发请求。
开发环境(Webpack / Vite Proxy): 在 Vue 或 React 等脚手架的配置文件中设置代理。前端将请求发给本地的开发服务器,开发服务器再将请求转发给真实的后端 API
生产环境(Nginx 反向代理): 部署时,使用 Nginx 作为统一的入口。前端静态文件和后端 API 都通过同一个域名和端口暴露,Nginx 根据路径规则(如 /api/)将请求转发给内部真实的后端服务
适用场景: 前后端分离项目,特别是前后端部署在不同服务器或端口时

3. JSONP (JSON with Padding)
这是一种比较古老的“黑客”做法。

原理: 浏览器对 <script>、<img> 等标签的 src 属性加载资源是没有同源限制的。JSONP 就是利用 <script> 标签发起请求,后端不返回 JSON,而是返回一段执行特定前端回调函数的 JavaScript 代码,并将数据作为参数传入
缺点: 只支持 GET 请求,安全性较差(容易遭受 XSS 攻击),现在已经很少在核心业务中使用了

适用场景: 兼容老旧浏览器,或者一些简单的跨站数据拉取(如获取天气、新闻等第三方数据)

二、添加课程

1.课程分类

一个树形结构

1.1、树形结构获取方式

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
1.固定层级类型(自连接)

原理:将同一张表在 SQL 语句中当成多张表来使用,通过 LEFT JOIN 或 INNER JOIN 将父节点表和子节点表关联起来。
SQL 示例(假设我们要查询固定的 3 级部门树):
SELECT
t1.name AS '一级部门',
t2.name AS '二级部门',
t3.name AS '三级部门'
FROM
department t1
LEFT JOIN
department t2 ON t2.parent_id = t1.id
LEFT JOIN
department t3 ON t3.parent_id = t2.id
WHERE
t1.parent_id IS NULL; -- 假设顶级部门的 parent_id 为 NULL


2.非固定层级类型(递归查询)
原理:利用 SQL 的公用表表达式(Common Table Expressions, CTE),特别是 WITH RECURSIVE 语法。它分为两部分:先查出“初始节点”(锚点),然后让 SQL 引擎循环不断地用上一轮查出的节点去 JOIN 原始表找下一级,直到找不到为止。

SQL 示例(查询某个顶级部门及其下面的所有无限级子孙部门):

SQL
WITH RECURSIVE DepartmentTree AS (
-- 1. 锚点/初始查询:找出我们要作为起点的顶级部门
SELECT id, name, parent_id, 1 AS level
FROM department
WHERE parent_id IS NULL -- 或者写 id = 某个具体的顶级部门ID

UNION ALL

-- 2. 递归查询:用上一轮的结果 (t) 去 JOIN 原始表 (d) 找下一级
SELECT d.id, d.name, d.parent_id, t.level + 1
FROM department d
INNER JOIN DepartmentTree t ON d.parent_id = t.id
)
优点:极度灵活。完美解决“层级深度未知”的问题,无论树有 3 层还是 30 层,这一段代码通吃。并且可以很方便地在递归过程中计算节点的深度(层级 level)或者拼接完整的路径。

缺点:语法相对复杂,有一定的学习门槛;MySQL 直到 8.0 版本才开始支持 WITH RECURSIVE(PostgreSQL、SQL Server、Oracle 则早就支持了)。如果数据量极大且树极深,由于是数据库引擎在做循环,会占用一定的数据库 CPU 资源。