当前位置: 首页 > news >正文

【JavaWeb】Tlias后台管理系统

文章目录

1.班级管理

1.1 班级列表查询 (分页查询)

controller层
ClazzController.java

 /*** 分页查询班级*/@GetMapping//这里是请求参数,用问号衔接public Result getClazz(ClazzQueryParam clazzQueryParam) { //专门写一个封装类,把请求参数封装到里面log.info("分页查询:{}", clazzQueryParam);PageResult<Clazz> pageResult =  clazzService.page(clazzQueryParam);return Result.success(pageResult);}

总结:
1.请求参数:这里根据接口文档可以看出,是一个请求参数(用?衔接),由于很长,所以可以专门写一个封装类,把请求参数封装到里面。如果不长,如果请求参数名与形参变量名相同,直接定义方法形参即可接收。(省略@RequestParam),不然可以用Spring提供的 @RequestParam 注解,将请求参数绑定给方法形参,如下:

@DeleteMapping("/depts")
public Result delete(@RequestParam("id") Integer deptId){ System.out.println("根据ID删除部门: " + deptId);return Result.success();
}

2.使用PageResult做返回结构,里面有总数据个数和对应页面的值

service层
ClazzServiceImpl.java

@Overridepublic PageResult<Clazz> page(ClazzQueryParam clazzQueryParam) {PageHelper.startPage(clazzQueryParam.getPage(), clazzQueryParam.getPageSize());List<Clazz> clazzList = clazzMapper.list(clazzQueryParam); //传进去的作用是后面要读取if(!CollectionUtils.isEmpty(clazzList)){LocalDate now = LocalDate.now();for (Clazz clazz : clazzList) {LocalDate BeginDate = clazz.getBeginDate();LocalDate EndDate = clazz.getEndDate();if(BeginDate.isAfter(now)){clazz.setStatus("未开班");}else if(now.isAfter(EndDate)){clazz.setStatus("已结课");}else{clazz.setStatus("在读中");}}}Page<Clazz> p = (Page<Clazz>) clazzList;return new PageResult<Clazz>(p.getTotal(), p.getResult());}

总结:
1.处理一下satus,其实在sql中用case when处理也行。
2.这里要做的是封装为PageResult返回给controller层。pagehelper所做的事情就是:
(1)拦截你的查询,自动加上 LIMIT 和 OFFSET,实现分页。
(2)执行了另一个 COUNT 查询来获取总数。SELECT COUNT(*) FROM emp WHERE …这样它就知道数据库总共有多少条满足条件的记录。
3.clazzList其实已经是一个Page对象了,里面已经有total这个值,只是声明为了list,如果直接声明为page会很奇怪,因为Mapper 方法本身并不真的返回 Page,是 PageHelper 在中间动的手脚,所以强转为page也是一种约定,这样最后用p.getTotal(), p.getResult()即可获得PageResult需要的两个值
4.需要返回多个内容的时候,可以创建list返回,mybatis会自动封装到list里面

mapper层

  <!--id:方法名 resultType:查询返回的单条记录所封装的类型,注意是单条!!--><select id="list" resultType = "org.example.pojo.Clazz">select c.*, e.name as masterName from Clazz c left join emp e on c.master_id = e.id<where><if test="name != null and name != ''">c.name like concat('%', #{name}, '%')</if><if test="begin != null and end != null">and c.end_date between #{begin} and #{end}</if></where></select>

总结:
1.实体类属性名和数据库表查询返回的字段名一致,mybatis会自动封装,开启驼峰命名映射的话也可以!!所以这里如果想把数据库返回的对应值封装到Clazz这个类中,只要开启驼峰命名,类似end_date会转为类中的endDate,可以封装成功。

1.2 查询所有员工(显示班主任)

1.3 新增班级

1.4 根据ID查询班级(注意查询了才能修改)

1.5 修改班级信息

1.6 删除班级信息

注意:在页面原型中,要求如果该班级下关联的有学生,是不允许删除的,并提示错误信息:“对不起, 该班级下有学生, 不能直接删除”。 (提示:可以通过自定义异常 + 全局异常处理器实现)

controller层

    /*** 删除班级*/@DeleteMapping("/{id}")//表示这里有个动态参数id//路径参数 使用@PathVariable绑定给方法形参!!public Result deleteClazz(@PathVariable Integer id) {log.info("删除班级路径参数:{}", id);clazzService.deleteClazzById(id);return Result.success();}

注意点:
1.这里是路径参数,也就是直接在/之后传入,需要用@PathVariable绑定给方法形参。并且DeleteMapping后面的路径(“/{id}”)要用大括号包裹起来,表示这是动态参数id。

Service层
ClazzService.java

void deleteClazzById(Integer id);

ClazzServiceImpl.java

    /***根据id删除班级*/@Overridepublic void deleteClazzById(Integer id) {int studentCount = studentMapper.countByClazzId(id);if(studentCount > 0){//先创建一个对象,再抛出,然后被全局异常处理器捕获throw new DeletionNotAllowedException("对不起, 该班级下有学生, 不能直接删除");}clazzMapper.deleteClazzById(id);}

Mapper层

ClazzMapper.java

void deleteClazzById(Integer id);

ClazzMapper.xml

<!--    删除班级--><delete id="deleteClazzById">delete from clazz where id = #{id}</delete>

StudentMapper.java

int countByClazzId(Integer id);

StudentMapper.xml

 <select id="countByClazzId" resultType ="Integer">select count(*) from student where clazz_id = #{id}</select>

注意事项:
一开始想的是select count(*) from student group by clazz_id having clazz_id = #{id} ,但是有点复杂了,其实不需要分组,因为已经知道id是多少了,直接用where计算就行。
另外having是对分组后的内容进行过滤,where是分组前。
一些关于分组查询的知识点复习:
注意事项:

  • 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无任何意义【原因可以看上面,因为不知道要选谁】
  • 执行顺序:where > 聚合函数 > having
    where与having区别(面试题)
  • 执行时机不同:where是分组之前进行过滤,不满足where条件,不参与分组;而having是分组之后对结果进行过滤。
  • 判断条件不同:where不能对聚合函数进行判断,而having可以。

自定义异常 +全局异常处理器

创建异常类

public class DeletionNotAllowedException  extends RuntimeException {public DeletionNotAllowedException(String message) {//使得在抛出自定义异常时,可以带上自定义错误信息,并通过父类机制打印出来或传递给全局异常处理器。super(message);}
}

全局异常处理器

    @ExceptionHandler(DeletionNotAllowedException.class)public Result handleDeletionNotAllowedException(DeletionNotAllowedException e){//把异常传进来处理return Result.error(e.getMessage());}

整个流程大概是:
程序捕获异常->创建异常对象->被全局处理器捕获->输出保存进去的msg

所以要做的就是,新建一个自定义异常,写到全局处理器里,在对应位置抛出该异常


🧩 一、什么是“异常”(Exception)?

异常(Exception)就是程序运行时发生的错误事件
打断了正常的程序流程

简单说:

当代码遇到无法继续执行的情况时,JVM 就会抛出一个“异常对象”,告诉你哪里出了问题。


🔧 举个例子:

int a = 10 / 0;   // ❌ 除以零

运行结果:

Exception in thread "main" java.lang.ArithmeticException: / by zero

这就叫“异常”。
它告诉我们:在运行时,出现了不能继续执行的情况。


🧠 二、Java 为什么要有异常机制?

因为错误是无法避免的
文件可能不存在、网络可能断开、数据可能为 null、输入可能错误……

如果没有异常机制,你就得在每一行代码都写 if...else 检查,非常麻烦。

Java 的异常机制帮你做了两件事:

  1. 检测错误:当程序出错时,JVM 自动创建异常对象;
  2. 处理错误:你可以用 try...catch 来捕获、处理错误,让程序不崩溃。

💡 例子:

try {int result = 10 / 0;   // 这里会出错System.out.println("结果:" + result);
} catch (ArithmeticException e) {System.out.println("出错了:" + e.getMessage());
}

输出:

出错了:/ by zero

✅ 程序不会崩溃,还能优雅地提示错误。


🧩 三、Java 中的异常类型(按继承关系)
Throwable├── Error              ← 程序无法恢复(JVM错误,比如内存溢出)└── Exception├── Checked Exception(受检异常)→ 编译器必须处理(比如IOException)└── RuntimeException(运行时异常)→ 可选处理(比如NullPointerException)

📘 举几个常见的:

异常类型示例含义
NullPointerException对 null 调用了方法空指针
ArithmeticException除以0数学错误
ArrayIndexOutOfBoundsException访问数组越界下标越界
IOException文件或网络出错I/O错误
SQLExceptionSQL语句执行出错数据库错误

🧩 四、为什么要自定义异常?

内置异常只能描述“技术错误”,
比如“空指针”、“除0”、“SQL错误”。
但在真实业务中,你需要表达的是“业务逻辑错误”。


⚙️ 举个实际例子:

你的系统有一个“删除班级”的功能:

要求:如果班级下还有学生,就不允许删除。

用 Java 内置异常你只能抛 RuntimeException("不能删除")
但这太笼统了,别人根本不知道是哪种删除逻辑出错。

于是我们写一个更语义化的异常:

public class DeletionNotAllowedException extends RuntimeException {public DeletionNotAllowedException(String message) {super(message);}
}

然后使用它:

if (studentCount > 0) {throw new DeletionNotAllowedException("对不起,该班级下有学生,不能直接删除");
}

这时别人一看日志:

org.example.exception.DeletionNotAllowedException: 对不起,该班级下有学生,不能直接删除

就一目了然:
👉 这是业务逻辑错误(禁止删除),不是程序崩溃。


🧩 五、自定义异常的好处
优点说明
✅ 可读性高一看类名就知道错误类型(如 DeletionNotAllowedException
✅ 可区分业务异常和系统异常系统异常是代码错误,业务异常是逻辑错误
✅ 易于统一管理可以在全局异常处理器中统一捕获并格式化返回给前端
✅ 更易调试日志中清晰可见是哪种错误、在哪个模块触发的

🧩 六、异常处理的整体流程(项目中就是这样):
1️⃣ 程序运行中发现错误↓
2️⃣ 抛出异常(throw)↓
3️⃣ Spring 全局异常处理器捕获 (@ExceptionHandler)↓
4️⃣ 封装成 Result 对象返回前端↓
5️⃣ 前端显示错误提示

比如:

{"code": 0,"message": "对不起,该班级下有学生,不能直接删除"
}

✅ 七、一句话总结

异常 是程序在运行时报告错误的机制,
自定义异常 是为了让错误信息更符合业务语义,
从而让系统更可读、更易维护、更优雅。

一些知识点:
路径参数(pathvariable),请求参数(@RequestParam),json格式的参数(requestbody)

http://www.dtcms.com/a/580994.html

相关文章:

  • 硬件工程师-基础知识电阻(四)
  • 网站设计建设那家好门户网站开发项目
  • 视频号下载视频思路
  • Visual Basic 手工制作工具栏
  • 电话交换机软件和录音转文字服务器部署笔记
  • 常州建站程序衡水高端网站建设
  • Java五大排序算法详解与实现
  • [特殊字符] Vue3 + WebView 双端通信桥:用 TypeScript 构建高可维护的 JSBridge 与 JSSDK
  • 自然科学笔记-微积分
  • iOS 上架要求全解析,App Store 审核标准、开发者准备事项与开心上架(Appuploader)跨平台免 Mac 实战指南
  • iOS app语言切换
  • Search-o1:增强大型推理模型的主动搜索能力
  • 个人笔记|IP分片不用TTL
  • 百汇游戏网站开发商南通网站推广公司
  • 【Linux】权限(2):文件权限的深入理解粘滞位
  • 做网站公司如何选百度广告联盟推广链接
  • BIM+GIS协同:RVT文件转3DTiles的技术路径与场景落地
  • 中颖AFE芯片:SH367303、SH367306 和 SH367309
  • 数据结构—排序算法篇三
  • 从“医疗大模型”向“医疗智能体”架构与路径分析(白皮书草案-上)
  • LeetCode算法日记 - Day 95: 回文子串
  • DockerCompose与多容器编排
  • AngularJS与SQL的集成使用指南
  • 【ZeroRange WebRTC】TWCC 在 WebRTC 中的角色与工作原理(深入指南)
  • 数据结构常见的八大排序算法
  • 个人怎么做网站app推广引流方法
  • 初识光伏逆变器
  • 一文了解LLM应用架构:从Prompt到Multi-Agent
  • MongoDB 内存管理避坑指南:解决高占用、页错误等核心问题,让数据库性能翻倍
  • 关于DNS中毒攻击的解决方案分享