JavaWeb零基础学习Day8——Tlias智能学习辅助系统(Web后端实战项目)

新星杯·14天创作挑战营·第17期 10w+人浏览 490人参与

一. 需求

要完成 “Tlias 智能学习辅助系统” 的实战项目,我们可以从业务场景、功能模块、技术需求三个维度进行需求分析:

1.业务场景分析

该系统定位为企业级学习辅助与管理平台,核心服务于企业内部的员工培训、部门管理、数据统计等场景,帮助企业高效管理员工信息、培训资源,并通过数据报表优化学习策略。

2.功能模块需求拆解

结合界面和右侧功能列表,系统可拆分为以下核心模块:

1)部门管理模块
  • 功能:对企业部门进行增删改查
    • 查询:支持列表展示所有部门,可按部门名称、ID 筛选
    • 新增:录入部门名称、上级部门等信息
    • 修改:更新部门基本信息
    • 删除:移除无效部门(需处理关联员工的级联逻辑)
2)员工管理模块
  • 功能:对企业员工进行全生命周期管理
    • 增删改查:支持员工信息(ID、姓名、年龄、部门、职位等)的添加、修改、删除、列表查询
    • 文件上传:支持员工证件、培训材料等附件的上传与管理
3)报表统计模块
  • 功能:通过可视化图表呈现企业学习与人员数据
    • 员工职位统计:柱状图展示各职位的员工分布
    • 员工性别统计:饼图展示性别比例
    • 班级人数统计:柱状图展示各班级学员数量
    • 学员学历统计:环形图展示学员学历分布
4)登录认证模块
  • 功能:保障系统访问安全
    • 登录:员工通过账号密码登录系统
    • 修改密码:支持登录后修改个人密码
    • 退出登录:安全登出系统
5)日志管理模块
  • 功能:记录系统操作轨迹
    • 操作日志:记录员工的系统操作(如新增部门、修改员工信息等)
    • 登录日志:记录员工的登录时间、IP 等信息
6) 班级与学员管理模块(实战核心)
  • 功能:管理企业培训班级和学员
    • 班级管理:班级的增删改查(名称、课程、班主任等)
    • 学员管理:学员信息的增删改查(关联班级、学历、培训进度等)

3.技术需求分析

结合 “Web 前端 + 后端” 的技术栈,需明确以下技术实现要求:

1)前端技术需求
  • 页面布局:采用侧边栏导航 + 顶部栏功能区 + 主体内容区的经典后台布局
  • 交互要求:
    • 表单验证:新增 / 修改数据时需做前端校验(如必填项、格式校验)
    • 分页查询:列表页支持分页、排序、筛选
    • 图表可视化:使用 ECharts 实现柱状图、饼图、环形图等数据可视化
    • 文件上传:支持多文件上传、进度条展示、文件预览
2)后端技术需求
  • 架构:采用前后端分离架构,前端通过接口与后端交互
  • 数据库:设计部门表、员工表、班级表、学员表、日志表等,需关注表间关联(如部门与员工的一对多关系)
  • 接口设计:每个功能模块需提供 RESTful 风格接口(如/api/dept/list查询部门列表)
  • 权限控制:基于登录态实现接口鉴权,不同角色(如管理员、普通员工)可访问的功能不同
  • 文件存储:实现文件上传接口,支持将文件存储到服务器本地或云存储(如 MinIO)

4.技术栈选型建议

  • 前端:HTML、CSS、JavaScript(或 Vue/React 框架)+ ECharts(图表)+ Axios(接口请求)
  • 后端:Java + Spring Boot + MyBatis(或 MyBatis-Plus)+ MySQL(数据库)
  • 部署:可部署在 Tomcat 容器,结合 Nginx 做前端静态资源代理

二.准备工作

1.开发模式

基于当前主流的前后端混合开发

2.开发规范

在案例进行开发的时候,采用的架构风格是Restful来进行前端和服务器端的交互

注:

1.REST是风格,是约定方式,约定不是规定,可以被打破。

2.描述功能模块通常使用复数形式(加s),表示此类资源,而非单个资源。如:user、books

思考:

前后端都在并行开发,后端开发完对应的接口之后,如何对接口进行请求测试?前端开发过程中,如何获取到数据,测试页面的渲染展示?

这里可以使用Apifox来解决这个问题,因为浏览器地址栏发起的请求,都是GET方式的请求,如果我们需要POST、PUT、DELETE方式的请求,就需要借助这类工具。

3.工程搭建

困惑点:三层架构、解耦、mapper

三.部门管理

1.列表查询-接口开发

困惑点:这里我遇到了一个坑,在正常写完查询数据代码后会碰到403或者500的问题,这个是因为Lombok引入后但是@Data注解没有正常生效,导致前后端返回的数据格式要求不一致,前端要求返回的是一个json格式,但是后端服务器返回的是一个html格式

解决办法:先打开pom.xml,然后找到Lombok所在位置,根据spring创建的Lombok版本,手动改一下版本即可

负载均衡:意思就是说前端给后端发送请求,代理服务器会把每次请求分批次给不同的服务器,比如第一次请求给第一台服务器,第二次请求给第二台。

这个图展示的是 Nginx 反向代理 + 路径重写的核心流程,简单说就是:Nginx 接收前端请求,先修改请求路径,再把请求转发给后端 Tomcat 服务器。

1) listen 90;
  • 作用:Nginx 启动后,会监听服务器的 90 端口,所有发往 http://localhost:90 的请求都会被这个 server 块处理。
2.)location ^~ /api/ { ... }
  • location:Nginx 用于「匹配请求路径」的指令,不同的路径可以走不同的处理规则;
  • ^~ /api/:路径匹配规则(^~ 表示 “精确前缀匹配”),意思是:只处理 “以 /api/ 开头” 的请求(比如 http://localhost:90/api/deptshttp://localhost:90/api/emps 会匹配,http://localhost:90/test 不会匹配)。
3)rewrite ^/api/(.*)$ /$1 break;(路径重写)

这是核心中的核心,作用是「修改请求路径」,用正则表达式实现:

  • 正则部分 ^/api/(.*)$
    • ^:匹配路径开头;
    • /api/:匹配固定前缀 /api/
    • (.*):匹配 /api/ 后面的所有内容(用括号包裹,作为 “分组”,后续用 $1 引用);
    • $:匹配路径结尾;
  • 替换部分 /$$1(图中是 /$$1,实际是 / + $1):把原路径替换成 /$1$1 就是前面括号里匹配到的内容);
  • break:重写完成后,停止后续的重写规则,直接执行后面的 proxy_pass

举例子(对应图中的请求):原请求路径是 /api/depts,经过 rewrite 后:

  • 原路径 ^/api/(.*)$ 中的 (.*) 匹配到的是 depts
  • 替换成 /$$1 → 最终路径变成 /depts
4) proxy_pass http://localhost:8080;(反向代理)
  • 作用:把重写后的请求转发给指定的后端服务器(这里是 Tomcat,地址是 http://localhost:8080);
  • 结合前面的路径重写,最终转发给 Tomcat 的请求是:http://localhost:8080/depts(对应图中右侧的箭头)。

完整流程(从前端请求到后端响应):

前端发送请求:http://localhost:90/api/depts(访问 Nginx 的 90 端口);
Nginx 监听 90 端口,收到请求;
Nginx 匹配 location ^~ /api/(因为请求路径以 /api/ 开头);
执行 rewrite:把请求路径从 /api/depts 改成 /depts;
执行 proxy_pass:把修改后的请求 http://localhost:8080/depts 转发给 Tomcat;
Tomcat 处理 /depts 请求(比如返回部门列表数据),并把响应结果返回给 Nginx;
Nginx 把 Tomcat 的响应结果转发给前端。

2.删除部门-接口开发

1)思路分析

2)Controller接收参数

注意事项:@RequestParam注解required属性默认为true,代表该参数必须传递,如果不传递将报错。如果参数可选,可以将属性设置为false。

    /*
    * 根据ID删除部门
    * */
    @Delete("delete  from  dept where id = #{id}")//#{id}:表示占位符,表示id参数的值,占位符的值会从方法参数中获取,占位符的值会替换掉#{id},表示预编译的sql
    void deleteById(Integer id);

3.新增部门-接口开发

1)思路分析

JSON格式的参数,通常会使用一个实体对象进行接受

规则:JSON数据的键名与方法形参对象的属性名相同,并需要使用@RequestBody注解标识

2)Controller接受参数

注:@RequestBody注解可以将一个json格式的请求参数,直接封装到一个对象当中。

困惑点:这里有一个之前学习的时候忽略,所以一直没搞懂的点,就是为啥Dept为啥能直接设置成数据类型?

这里的 Dept dept 能直接作为方法参数,核心原因是 Dept 是一个「类」(实体类),而 dept 是这个类的「对象引用变量」—— 在 Java 中,类本身就可以作为数据类型(引用类型)来使用,用于声明变量、作为方法参数或返回值。

  • Dept 是一个 Java 类(用 class 关键字定义),它是对 “部门” 这个实体的抽象,包含了部门的属性(id、name 等);
  • 在 Java 中,类是 “引用数据类型” 的一种,和 String、List 一样,都可以用来声明变量或作为方法参数类型。

为什么 Dept dept 能作为方法参数?
1. Dept 作为 “数据类型”
Java 中的数据类型分为两种:

  • 基本数据类型:int、double、boolean 等,直接存储值;
  • 引用数据类型:类(Dept、String)、接口、数组等,存储的是对象的引用(内存地址)。

Dept 作为一个类,属于引用数据类型,因此可以像 String name 一样,用 Dept dept 来声明变量 —— 这里的 Dept 是 “类型”,dept 是 “变量名”,表示这个变量可以指向一个 Dept 类型的对象。

注:json格式的请求参数适用场景主要在POST、PUT请求中,在请求体传递请求参数。

4.修改部门-查询回显

1)查询回显

查询回显是指在前后端交互过程中,前端发送查询请求到后端,后端处理请求后将结果返回给前端,前端将返回的数据展示给用户的过程。这一过程涵盖了数据查询、传输和展示三个核心环节。

常见应用场景

表单提交后显示查询结果、实时搜索建议、数据表格的分页加载等场景均依赖查询回显。例如电商网站的搜索功能,用户输入关键词后,前端实时显示后端返回的商品列表。

2)思路分析

3)Controller接收参数

注:用@PathVariable注解来声明获取的是路径参数

注:在url中可以携带多个路径参数,如:/depts/1/0

4)修改部门数据

5)@RequestMapping方法抽取(代码优化)

注:@RequestMapping("/depts") 加在Controller 类上时,作用是为当前类中所有接口方法统一指定请求路径的前缀。

困惑点:没有搞清楚在Java中方法和构造器到底有什么区别?

概念定义核心作用
构造器与类名同名、没有返回值(连void都不能写)的特殊 “函数”创建对象时初始化对象的属性(比如给name、age赋值)
方法有方法名、返回值类型(可以是void)、参数列表的普通函数封装业务逻辑(比如计算、打印、查询数据)

语法区别(代码示例对比)
以Dept类为例:

1. 构造器的语法

public class Dept {
    private Integer id;
    private String name;

    // 构造器:与类名Dept同名,无返回值
    public Dept(Integer id, String name) {
        this.id = id; // 创建对象时初始化id属性
        this.name = name; // 创建对象时初始化name属性
    }
}

2. 方法的语法

public class Dept {
    private Integer id;
    private String name;

    // 方法:有返回值(String)、方法名(getInfo)
    public String getInfo() {
        return "部门ID:" + this.id + ",部门名称:" + this.name; // 封装业务逻辑
    }
}

调用时机与方式区别
1. 构造器的调用时机
只能在创建对象时通过new关键字调用,且每个对象创建时必须调用一次构造器(即使你没写,Java 会提供默认无参构造器):

// 创建Dept对象时,自动调用构造器初始化属性
Dept dept = new Dept(1, "教研部");

2. 方法的调用时机
必须在对象创建完成后,通过 “对象。方法名 ()” 调用,可以调用任意次数:

Dept dept = new Dept(1, "教研部");
// 对象创建后,调用方法
String info = dept.getInfo(); 
System.out.println(info); // 输出:部门ID:1,部门名称:教研部

核心结论
“构造器” 和 “方法” 完全不是一回事:

  • 构造器是对象创建的 “初始化工具”,负责给对象 “初始化属性”;
  • 方法是对象的 “功能工具”,负责封装 “业务逻辑”。

简单记:new对象时用构造器初始化,对象创建后用方法做事情。

四.日志技术

1.日志技术

2.Logback快速入门程序

3.配置文件详解

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<!-- 控制台输出 -->
	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level表示级别从左显示5个字符宽度,%logger显示日志记录器的名称, %msg表示日志消息,%n表示换行符 -->
			<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">
			<!-- 日志文件输出的文件名, %i表示序号 -->
			<FileNamePattern>D:/tlias-%d{yyyy-MM-dd}-%i.log</FileNamePattern>
			<!-- 最多保留的历史日志文件数量 -->
			<MaxHistory>30</MaxHistory>
			<!-- 最大文件大小,超过这个大小会触发滚动到新文件,默认为 10MB -->
			<maxFileSize>10MB</maxFileSize>
		</rollingPolicy>

		<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
			<!--格式化输出:%d 表示日期,%thread 表示线程名,%-5level表示级别从左显示5个字符宽度,%msg表示日志消息,%n表示换行符 -->
			<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>

4.日志级别

用@Slf4j注解,将日志记录功能封装到类中,不用再写日志记录代码,简化下面一长串代码
private static final org.slf4j.Logger log  = LoggerFactory.getLogger(DeptController.class);

注:不建议用日志级别调的太低,不然日志会过多,影响日志查看!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值