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

每日学习:DAY24

日常开发与学习记录

前言

怎么感觉自己越来越懒了。

日程

忘记写了,大概是早上做了 SQL 表单,晚上写了 DispatcherController

学习记录

操作系统

  1. 页面分配置换策略

学习内容

省流

  1. SQL 表单构建
  2. 关于嵌套注解的生效机制
  3. DispatcherController 统一路由接收/转发器

1. SQL 表单构建

表结构设计

每张表的通用表单项:创建时间,更新时间。

  • 用户表

    CREATE TABLE 用户 (id INT PRIMARY KEY,姓名 VARCHAR(50),用户名 VARCHAR(50) UNIQUE,密码 VARCHAR(100),身份标识符 INT CHECK (身份标识符 IN (0, 1, 2)) -- 0: 学生,1:老师,2:管理员
    );
    
  • 学生班级关联表

    CREATE TABLE 学生班级关联 (id INT PRIMARY KEY,学生id INT,班级id INT,FOREIGN KEY (学生id) REFERENCES 用户(id),FOREIGN KEY (班级id) REFERENCES 班级(id)
    );
    
  • 教师课程关联表

    CREATE TABLE 教师课程关联 (id INT PRIMARY KEY,教师id INT,课程id INT,FOREIGN KEY (教师id) REFERENCES 用户(id),FOREIGN KEY (课程id) REFERENCES 课程(id)
    );
    
  • 班级表

    CREATE TABLE 班级 (id INT PRIMARY KEY,名称 VARCHAR(100)
    );
    
  • 题目表

    CREATE TABLE 题目 (id INT PRIMARY KEY,题目类型标识符 INT CHECK (题目类型标识符 IN (0, 1)), -- 0:选择题,1:简答题描述 TEXT,题干 TEXT,答案 TEXT,难度 INT,分值 INT,创建者id INT,FOREIGN KEY (创建者id) REFERENCES 用户(id)
    );
    
  • 练习列表表

    CREATE TABLE 练习列表 (id INT PRIMARY KEY,名称 VARCHAR(100),课程id INT,开始时间 DATETIME,截止时间 DATETIME,状态 INT CHECK (状态 IN (0, 1, 2)), -- 0: 未开始, 1: 进行中, 2: 已结束创建者id INT,FOREIGN KEY (课程id) REFERENCES 课程(id),FOREIGN KEY (创建者id) REFERENCES 用户(id)
    );
    
  • 练习题目表

    CREATE TABLE 练习题目 (id INT PRIMARY KEY,练习id INT,题目id INT,排序号 INT,FOREIGN KEY (练习id) REFERENCES 练习列表(id),FOREIGN KEY (题目id) REFERENCES 题目(id)
    );
    
  • 学生答题记录表

    CREATE TABLE 学生答题记录表 (id INT PRIMARY KEY,学生id INT,练习id INT,题目id INT,提交答案 TEXT,得分 INT,批改状态 INT CHECK (批改状态 IN (0, 1)), -- 0: 未批改, 1: 已批改批改备注 TEXT,批改时间 DATETIME,提交时间 DATETIME,FOREIGN KEY (学生id) REFERENCES 用户(id),FOREIGN KEY (练习id) REFERENCES 练习列表(id),FOREIGN KEY (题目id) REFERENCES 题目(id)
    );
    
  • 练习班级表

    CREATE TABLE 练习班级 (id INT PRIMARY KEY,练习id INT,班级id INT,FOREIGN KEY (练习id) REFERENCES 练习列表(id),FOREIGN KEY (班级id) REFERENCES 班级(id)
    );
    
  • 学期表

    CREATE TABLE 学期 (id INT PRIMARY KEY,名称 VARCHAR(100),开始时间 DATETIME,截至时间 DATETIME
    );
    
  • 课程表

    CREATE TABLE 课程 (id INT PRIMARY KEY,名称 VARCHAR(100),学期id INT,FOREIGN KEY (学期id) REFERENCES 学期(id)
    );
    
  • 提醒表

    CREATE TABLE 提醒表 (id INT PRIMARY KEY,目标用户id INT,发起者id INT,生效时间 DATETIME,内容 TEXT,FOREIGN KEY (目标用户id) REFERENCES 用户(id),FOREIGN KEY (发起者id) REFERENCES 用户(id)
    );
    
核心层级关系

课程 → 练习 → 题目
(1对多) (1对多)

具体关联方式
层级关联表关键字段说明
课程层课程学期id课程属于特定学期
教师课程关联教师id+课程id定义教师授课权限
练习层练习列表课程id练习必须归属于一个课程
练习班级练习id+班级id练习可分配给多个班级
题目层练习题目练习id+题目id题目可被多个练习复用
数据流动示例
学期2023秋季
课程: 数据库原理
练习: 第一章作业
练习: 第二章测验
题目1: SQL选择题
题目2: 简答题
题目3: 设计题

2. 关于嵌套注解的生效机制

想简化注解,我理解的注解机制和实际的有不少偏差。

元注解

元注解(Meta-annotation)是注解在其他注解上的注解。例如:

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@KatComponent
public @interface KatController {String value() default "";
}

默认情况下注解不具备继承性。@Inherited 只对类注解有效,对方法/字段注解无效。

@Inherited // 只有加上这个注解才能被继承
public @interface MyAnnotation {}
直接获取
// 只能获取直接注解,不会获取元注解
if (clazz.isAnnotationPresent(KatComponent.class)) {...}
递归获取元注解
// 获取所有注解(包括元注解)
Annotation[] annotations = clazz.getAnnotations();// 递归检查元注解
public static boolean isAnnotationPresent(Class<?> targetClass, Class<? extends Annotation> annotationClass) {// 检查直接注解if (targetClass.isAnnotationPresent(annotationClass)) {return true;}// 检查元注解for (Annotation annotation : targetClass.getAnnotations()) {if (annotation.annotationType().isAnnotationPresent(annotationClass)) {return true;}}return false;
}

在 Spring Boot 中,实现了 AnnotatedElementUtils 来进行多级注解查找,而且还支持注解属性合并:子注解可以覆盖元注解的属性值。

3. DispatcherController 统一路由接收/转发器

包装类设置
// 路由表: 路径 -> 控制器方法映射
private final Map<RouteKey, HandlerMethod> routeMappings = new ConcurrentHashMap<>();// 路由键定义
private record RouteKey(String path, String httpMethod) {private RouteKey(String path, String httpMethod) {this.path = PathUtils.normalize(path);this.httpMethod = httpMethod.toUpperCase();}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;RouteKey routeKey = (RouteKey) o;return path.equals(routeKey.path) &&httpMethod.equals(routeKey.httpMethod);}@Overridepublic String toString() {return httpMethod + " " + path;}
}// 处理器方法封装
private record HandlerMethod(Object controllerInstance, Method method) {}
初始化路由表
@Override
public void init(){// 获取ContainerFactory进而获取BeanRegistrythis.containerFactory = (ContainerFactory) getServletContext().getAttribute("ContainerFactory");// 构建路由表buildRouteMappings();
}private void buildRouteMappings() {// 获取所有控制器类(标记了@KatComponent和@Controller)containerFactory.getRegistry().getClassRegistry().forEach((beanName, clazz) -> {if (clazz.isAnnotationPresent(KatController.class)) {registerControllerRoutes(clazz, containerFactory.getBean(clazz));}});
}
路由表的构建
private void registerControllerRoutes(Class<?> controllerClass, Object controllerInstance) {// 类级别的路径String basePath = "";if (controllerClass.isAnnotationPresent(KatRequestMapping.class)) {basePath = controllerClass.getAnnotation(KatRequestMapping.class).path();}// 方法级别的映射for (Method method : controllerClass.getDeclaredMethods()) {if (method.isAnnotationPresent(KatRequestMapping.class)) {KatRequestMapping mapping = method.getAnnotation(KatRequestMapping.class);String fullPath = PathUtils.normalize(basePath + mapping.path());String httpMethod = mapping.method().toUpperCase();RouteKey key = new RouteKey(fullPath, httpMethod);routeMappings.put(key, new HandlerMethod(controllerInstance, method));}}
}
请求处理
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp)throws IOException {// 标准化请求路径String path = PathUtils.normalize(req.getRequestURI().replace(req.getContextPath(), ""));String method = req.getMethod().toUpperCase();RouteKey key = new RouteKey(path, method);// 查找处理器HandlerMethod handler = routeMappings.get(key);if (handler == null) {resp.sendError(HttpServletResponse.SC_NOT_FOUND);return;}// 调用处理器方法try {Object result = handler.method.invoke(handler.controllerInstance, req, resp);// 处理返回结果ServletUtils.sendResponse(resp, Result.success(result));} catch (Exception e) {handleError(resp, e);}
}

结语

被蚊子轮着咬。
天生万物以养人,人滋血性以养蚊。

相关文章:

  • Spring AI 入门(持续更新)
  • 深入解析建造者模式(Builder Pattern)——以Java实现复杂对象构建的艺术
  • 支持鸿蒙next的uts插件
  • 计算机学习路线与编程语言选择(信息差)
  • LLaMA模型本地部署全攻略:从零搭建私有化AI助手
  • 突破网络限制:Windows平台离线搭建Linux环境+Docker化部署AI知识库RAGFlow实战
  • 平板收银系统、国产系统,鸿蒙系统,小键盘的封装与应用—仙盟创梦IDE
  • Matlab 数控车床进给系统的建模与仿真
  • Java执行linux服务器本地命令
  • HTTP Error 500.31 - Failed to load ASP.NET Core runtime
  • 第三节第一部分:Static修饰类变量、成员变量
  • xiaopiu原型设计工具笔记
  • 多环串级PID
  • Spring Boot 启动原理的核心机制
  • Git实战经验分享:深入掌握git commit --amend的进阶技巧
  • 一种机载扫描雷达实时超分辨成像方法——论文阅读
  • uniapp|实现多终端视频弹幕组件、内容轮询、信息表情发送(自定义全屏半屏切换、弹幕启用)
  • k8s(11) — 探针和钩子
  • 【Redis】持久化与事务
  • 电容的基本介绍
  • 深圳两家会所涉卖淫嫖娼各被罚7万元逾期未缴,警方发催告书
  • 国家主席习近平在莫斯科出席红场阅兵式
  • 欧派家居:一季度营收降4.8%,目前海外业务整体体量仍较小
  • 保利发展前4个月销售额约876亿元,单月斥资128亿元获4个项目
  • 昆廷·斯金纳:作为“独立自主”的自由
  • “子宫内膜异位症”相关论文男性患者样本超六成?福建省人民医院发布情况说明