学习记录:DAY28

news2025/5/10 22:03:09

DispatcherController 功能完善与接口文档编写

前言


没什么动力说废话了。
今天来完善 DispatcherController 的功能,然后写写接口文档。


日程


  • 早上:本来只有早八,但是早上摸鱼了,罪过罪过。
  • 下午:把 DispatcherController 完善得比较充足了(我认为的哈)。
  • 晚上 10 点:现在的时间,deepseek 卡爆了,先来写写 blog。
  • 晚上 10 点半:摆烂了,开摆!

学习内容


省流

  1. DispatcherController 完善

1. DispatcherController 完善(有点水了)

主要是兼容各种询问参数,注解如下:

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface KatPathVariable {
    String value() default "";
}

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface KatRequestBody {
    boolean required() default true;
}

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface KatRequestParam {
    String value() default "";  // 参数名
    boolean required() default true;  // 是否必须
    String defaultValue() default "";  // 默认值
}
1)路径参数 KatPathVariable
private Object resolvePathVariable(KatPathVariable annotation,
                                       java.lang.reflect.Parameter parameter,
                                       Class<?> paramType,
                                       HttpServletRequest req) {
    Map<String, String> pathVariables = (Map<String, String>) req.getAttribute("pathVariables");

    // 获取参数名,优先使用注解值,其次使用参数名
    String paramName = annotation.value().isEmpty()
            ? parameter.getName()
            : annotation.value();

    String value = pathVariables.get(paramName);
    if (value == null) {
        throw new IllegalArgumentException("Path variable '" + paramName + "' not found");
    }

    try {
        // 使用 TypeConverter 进行类型转换
        return TypeConverter.convertValue(value, paramType);
    } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException(
                String.format("Failed to convert path variable '%s' value '%s' to type %s",
                        paramName, value, paramType.getName()),
                e
        );
    }
}

TypeConverter 是从原来 SimpleMapper 类中拆出来的方法:

public static Object convertValue(Object value, Class<?> targetType) {
    if (value == null) {
        if (targetType == Number.class) { // Number类型检查
            return 0;
        }
        return null;
    }
    if (targetType.isInstance(value)) {
        return value;
    }

    // 数值类型转换
    if (value instanceof Number number) {
        if (targetType == Double.class || targetType == double.class) {
            return number.doubleValue();
        }
        if (targetType == Float.class || targetType == float.class) {
            return number.floatValue();
        }
        if (targetType == Integer.class || targetType == int.class) {
            return number.intValue();
        }
        // 其他数值类型省略...
    }

    // 字符串到其他类型的转换
    if (value instanceof String strValue) {
        try {
            if (targetType == Integer.class || targetType == int.class) {
                return Integer.parseInt(strValue);
            }
            if (targetType == Long.class || targetType == long.class) {
                return Long.parseLong(strValue);
            }
            // 其他类型省略...
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Failed to convert string '" + strValue +
                    "' to type " + targetType.getName(), e);
        }
    }

    // 日期类型转换
    if (value instanceof java.sql.Date sqlDate) {
        if (targetType == LocalDate.class) {
            return sqlDate.toLocalDate();
        }
        if (targetType == LocalDateTime.class) {
            return sqlDate.toLocalDate().atStartOfDay();
        }
    }

    // 布尔类型转换、时间戳转换等省略...

    log.warn("Cannot convert value '{}' of type {} to target type {}",
            value, value.getClass().getName(), targetType.getName());
    throw new IllegalArgumentException("Cannot convert value '" + value +
            "' of type " + value.getClass().getName() +
            " to target type " + targetType.getName());
}
2)询问参数 KatRequestParam

也是差不多的逻辑:

private Object resolveRequestParam(KatRequestParam annotation,
                                       java.lang.reflect.Parameter parameter,
                                       Class<?> paramType,
                                       HttpServletRequest req) {
    // 获取参数名,优先使用注解值,其次使用参数名
    String paramName = annotation.value().isEmpty()
            ? parameter.getName()
            : annotation.value();

    String paramValue = req.getParameter(paramName);

    // 处理参数缺失情况
    if (paramValue == null || paramValue.isEmpty()) {
        if (annotation.required()) {
            throw new IllegalArgumentException("Required request parameter '" + paramName + "' is not present");
        }
        if (!annotation.defaultValue().isEmpty()) {
            paramValue = annotation.defaultValue();
        } else {
            return null; // 非必需且无默认值,返回null
        }
    }

    try {
        // 使用 TypeConverter 进行类型转换
        return TypeConverter.convertValue(paramValue, paramType);
    } catch (IllegalArgumentException e) {
        throw new IllegalArgumentException(
                String.format("Failed to convert request parameter '%s' value '%s' to type %s",
                        paramName, paramValue, paramType.getName()),
                e
        );
    }
}
3)请求体参数 KatRequestBody
private Object resolveRequestBody(Class<?> paramType,
                                      HttpServletRequest req,
                                      KatRequestBody annotation) throws IOException {
    // 检查请求体是否为空
    if (req.getContentLength() == 0) {
        if (annotation.required()) {
            throw new IllegalArgumentException("Required request body is missing");
        }
        return null;
    }

    try {
        String requestBody = ServletUtils.getRequestBody(req); 

        // 如果是String类型,直接返回
        if (paramType.equals(String.class)) {
            return requestBody;
        }

        // 构建对象
        return JsonUtils.parseJson(requestBody, paramType); //这里借助了Jakson工具
    } catch (Exception e) {
        throw new IllegalArgumentException("Failed to parse request body", e);
    }
}
4)对应代理方法的装配也有比较大的改动
private Object invokeHandlerMethod(HandlerMethod handler,
                                       HttpServletRequest req,
                                       HttpServletResponse resp) throws Exception {
    Method method = handler.method();
    Object[] args = new Object[method.getParameterCount()];
    Class<?>[] paramTypes = method.getParameterTypes();
    Annotation[][] paramAnnotations = method.getParameterAnnotations(); //一个

    for (int i = 0; i < paramTypes.length; i++) {
        // 处理 @KatPathVariable 注解参数
        KatPathVariable pathVar = findAnnotation(paramAnnotations[i],KatPathVariable.class);
        if (pathVar != null) {
            args[i] = resolvePathVariable(pathVar, method.getParameters()[i],
                    paramTypes[i], req);
            continue;
        }

        // 处理 @KatRequestParam 注解参数
        KatRequestParam requestParam = findAnnotation(paramAnnotations[i], KatRequestParam.class);
        if (requestParam != null) {
            args[i] = resolveRequestParam(requestParam,method.getParameters()[i], paramTypes[i], req);
            continue;
        }

        // 处理 @KatRequestBody 注解参数
        KatRequestBody requestBody = findAnnotation(paramAnnotations[i], KatRequestBody.class);
        if (requestBody != null) {
            args[i] = resolveRequestBody(paramTypes[i], req, requestBody);
            continue;
        }

        // 处理 HttpServletRequest/HttpServletResponse 参数
        if (paramTypes[i].equals(HttpServletRequest.class)) {
            args[i] = req;
        } else if (paramTypes[i].equals(HttpServletResponse.class)) {
            args[i] = resp;
        }
    }

    return method.invoke(handler.controllerInstance(), args);
}

结语


不知不觉,不知不觉,已经 5 月 9 号了。
项目只剩下 12 天了,我真的把握好时间了吗?


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2372651.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

.NET高频技术点(持续更新中)

1. .NET 框架概述 .NET 框架的发展历程.NET Core 与 .NET Framework 的区别.NET 5 及后续版本的统一平台 2. C# 语言特性 异步编程&#xff08;async/await&#xff09;LINQ&#xff08;Language Integrated Query&#xff09;泛型与集合委托与事件属性与索引器 3. ASP.NET…

pandas中的数据聚合函数:`pivot_table` 和 `groupby`有啥不同?

pivot_table 和 groupby 是 pandas 中两种常用的数据聚合方法&#xff0c;它们都能实现数据分组和汇总&#xff0c;但在使用方式和输出结构上有显著区别。 0. 基本介绍 groupby分组聚合 groupby 是 Pandas 库中的一个功能强大的方法&#xff0c;用于根据一个或多个列对数据进…

对golang中CSP的理解

概念&#xff1a; CSP模型&#xff0c;即通信顺序进程模型&#xff0c;是由英国计算机科学家C.A.R. Hoare于1978年提出的。该模型强调进程之间通过通道&#xff08;channel&#xff09;进行通信&#xff0c;并通过消息传递来协调并发执行的进程。CSP模型的核心思想是“不要通过…

【LunarVim】CMake LSP配置

在 LunarVim 中为 CMakeLists.txt 文件启用代码提示&#xff08;如补全和语义高亮&#xff09;&#xff0c;需要安装支持 CMake 的 LSP&#xff08;语言服务器&#xff09;和适当的插件。以下是完整配置指南&#xff1a; 1、配置流程 1.1 安装cmake-language-server 通过 Ma…

Mkdocs页面如何嵌入PDF

嵌入PDF 嵌入PDF代码 &#xff0c;注意PDF的相对地址 <iframe src"../个人简历.pdf (相对地址)" width"100%" height"800px" style"border: 1px solid #ccc; overflow: auto;"></iframe>我的完整代码&#xff1a; <d…

融合静态图与动态智能:重构下一代智能系统架构

引言&#xff1a;智能系统的分裂 当前的大模型系统架构正处于两个极端之间&#xff1a; 动态智能体系统&#xff1a;依赖语言模型动态决策、自由组合任务&#xff0c;智能灵活但稳定性差&#xff1b; 静态流程图系统&#xff1a;具备强工程能力&#xff0c;可控可靠&#xf…

WORD压缩两个免费方法

日常办公和学习中&#xff0c;Word文档常常因为包含大量图片、图表或复杂格式而导致文件体积过大&#xff0c;带来诸多不便&#xff0c;比如 邮件发送受限&#xff1a;许多邮箱附件限制在10-25MB&#xff0c;大文件无法直接发送 存储空间占用&#xff1a;大量文档占用硬盘或云…

skywalking服务安装与启动

skywalking服务安装并启动 1、介绍2、下载apache-skywalking-apm3、解压缩文件4、创建数据库及用户5、修改配置文件6、下载 MySQL JDBC 驱动7、启动 OAP Serve,需要jkd11,需指定jkd版本,可以修改文件oapService.sh8、启动 Web UI,需要jkd11,需指定jkd版本,可以修改文件oapServi…

Qt 中信号与槽(signal-slot)机制支持 多种连接方式(ConnectionType)

Qt 中信号与槽&#xff08;signal-slot&#xff09;机制支持 多种连接方式&#xff08;ConnectionType&#xff09; Qt 中信号与槽&#xff08;signal-slot&#xff09;机制支持 多种连接方式&#xff08;ConnectionType&#xff09;&#xff0c;用于控制信号发出后如何调用槽…

Midjourney-V7:支持参考图片头像或背景生成新保真图

Midjourney-V7重磅升级Omni Reference&#xff1a;全能图像参考神器&#xff01;再也不用担心生成图片货不对版了&#xff01; 就在上周&#xff0c;Midjourney发版它最新的V7版本&#xff1a;Omini Reference&#xff0c;提供了全方位图像参考功能&#xff0c;它可以参考你提…

耀圣-气动带刮刀硬密封法兰球阀:攻克颗粒高粘度介质的自清洁 “利器”

气动带刮刀硬密封法兰球阀&#xff1a;攻克颗粒高粘度介质的自清洁 “利器” 在化工、矿业、食品加工等行业中&#xff0c;带颗粒高粘度介质、料浆及高腐蚀性介质的输送与控制一直是行业难题。普通阀门极易因介质附着、颗粒堆积导致卡阻失效&#xff0c;密封面磨损加剧&#x…

Google云计算原理和应用之分布式锁服务Chubby

Chubby是Google设计的提供粗粒度锁服务的一个文件系统,它基于松耦合分布式系统,解决了分布的一致性问题。通过使用Chubby的锁服务,用户可以确保数据操作过程中的一致性。不过值得注意的是,这种锁只是一种建议性的锁(Advisory Lock)而不是强制性的锁,这种选择系统具有更大…

SM2Utils NoSuchMethodError: org.bouncycastle.math.ec.ECFieldElement$Fp.<init

1&#xff0c;报错图示 2&#xff0c;报错原因&#xff1a; NoSuchMethodError 表示运行时找不到某个方法&#xff0c;通常是编译时依赖的库版本与运行时使用的库版本不一致。 错误中的 ECFieldElement$Fp. 构造函数参数为 (BigInteger, BigInteger)&#xff0c;说明代码期望使…

《100天精通Python——基础篇 2025 第16天:异常处理与调试机制详解》

目录 一、认识异常1.1 为什么要使用异常处理机制?1.2 语法错误1.3 异常错误1.4 如何解读错误信息 二、异常处理2.1 异常的捕获2.2 Python内置异常2.3 捕获多个异常2.4 raise语句与as子句2.5 使用traceback查看异常2.6 try…except…else语句2.7 try…except…finally语句--捕获…

动态创建链表(头插法、尾插法)

今天我们来学习动态创建链表&#xff01;&#xff01;&#xff01; 动态创建链表&#xff1a;分为头插法和尾插法 头插法&#xff08;动态创建&#xff09;&#xff1a; 头插法就是让新节点变成头 代码如下 吐血了&#xff1a;这边有个非常重要的知识点&#xff0c;这边第三…

利用混合磁共振成像 - 显微镜纤维束成像技术描绘结构连接组|文献速递-深度学习医疗AI最新文献

Title 题目 Imaging the structural connectome with hybrid MRI-microscopy tractography 利用混合磁共振成像 - 显微镜纤维束成像技术描绘结构连接组 01 文献速递介绍 通过多种模态绘制大脑结构能够增进我们对大脑功能、发育、衰老以及疾病的理解&#xff08;汉森等人&am…

安全监控之Linux核心资产SSH连接监测邮件

文章目录 一、引言二、邮箱设置三、脚本配置四、登录测试 一、引言 在某些特殊时期&#xff08;如HVV&#xff09;需要重点监控Linux核心资产SSH连接登录活动情况&#xff0c;实现ssh登录报警监控。其实实现方式并不难。 二、邮箱设置 在邮箱中需要启用“SMTP”协议&#xf…

文旅田园康养小镇规划设计方案PPT(85页)

1. 项目背景与定位 背景&#xff1a;位于长三角经济圈&#xff0c;依托安吉丰富的自然与文化资源&#xff0c;旨在打造集康养、度假、文化体验于一体的综合小镇。 定位&#xff1a;成为浙北地区知名的康养旅游目的地&#xff0c;融合“一溪两岸”规划理念&#xff0c;实现全面…

【Linux操作系统】第一弹——Linux基础篇

文章目录 &#x1f4a1; 一. Linux的基本常识&#x1fa94; 1.1 linux网络连接三种方式&#x1fa94;1.2 虚拟机的克隆&#x1fa94;1.3 虚拟机的快照&#x1fa94;1.4 虚拟机的迁移和删除&#x1fa94;1.5 vmtools工具 &#x1f4a1;二. Linux的目录结构&#x1fa94;2.1 Linu…

vue3: pdf.js 2.16.105 using typescript

npm create vite vuepdfpreview //创建项目npm install vue-pdf-embed npm install vue3-pdfjs npm install pdfjs-dist2.16.105 <!--* |~~~~~~~|* | |* | |…