实现简单的Http服务器+SpringMvc,集成到Spring

news2025/1/10 11:18:09
实现简单的Http服务器+SpringMvc,集成到Spring
1、Http协议
1.1、HTTP 协议请求格式
方法 + 空格 + URL + 空格 + 版本 + 回车符 + 换行符

头部域名称:头部域值                 + 回车符 + 换行符

...

头部域名称:头部域值                 + 回车符 + 换行符

回车符 + 换行符

请求数据

利用Tcp接收一条Http请求数据如下:

GET /task/findAll?a=b HTTP/1.1
Host: localhost:8081
Connection: keep-alive
sec-ch-ua: "Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9


完全符合上面的http协议的格式,反过来,可以根据上面的协议格式,解析Http的参数和需要的字段。

解析完后的实体如下:

{
    "headers": {
        "Accept": " text/html,application/xhtml xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
        "Connection": " keep-alive",
        "User-Agent": " Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
        "Sec-Fetch-Site": " none",
        "Sec-Fetch-Dest": " document",
        "Host": " localhost",
        "Accept-Encoding": " gzip, deflate, br",
        "content-Type": "application/x-www-form-urlencoded",
        "Sec-Fetch-Mode": " navigate",
        "sec-ch-ua": " \"Google Chrome\";v=\"119\", \"Chromium\";v=\"119\", \"Not?A_Brand\";v=\"24\"",
        "sec-ch-ua-mobile": " ?0",
        "Cache-Control": " max-age=0",
        "Upgrade-Insecure-Requests": " 1",
        "sec-ch-ua-platform": " \"Windows\"",
        "Sec-Fetch-User": " ?1",
        "Accept-Language": " zh-CN,zh;q=0.9"
    },
    "methodName": "GET",
    "protocol": "HTTP",
    "queryString": {
        "a": "b"
    },
    "uri": "/task/findAll",
    "version": "1.1"
}
1.2、http协议相应格式
版本 + 空格 + 状态码 + 空格 + 原因短句 + 回车符 + 换行符

头部域名称:头部域值                             + 回车符 + 换行符

...

头部域名称:头部域值                             + 回车符 + 换行符

回车符 + 换行符

相应正文
1.3、请求及相应
public class Test {

    public static void main(String[] args) {
        HttpInvoke httpInvoke = new HttpInvoke() {
            @Override
            public Object invoke(RequestEntity entity) {
                return "hello";
            }
        };

        BootstrapServer bootstrapServer = new BootstrapServer(8081, httpInvoke);
    }
}
// HttpInvoke作为请求的回调,这里只做简单的回应"hello",启动8081

在这里插入图片描述

传送门(在httptest包下)

2、SpringMvc
2.1、扫描组件包

扫描组件包,将每个接口请求封装成MethodHandler

Properties prop = PropertyUtils.getClassPathProperties(MVC_CLASSPATH_NAME);
packageScanner = new GenericPackagesScanner(ctx.getPackages());
// 1、找到被controller注解标记的类
Set<Class<?>> classes = packageScanner.getFullyQualifiedClassNameList();
Set<Class<?>> webSet = new HashSet<>();
Iterator<Class<?>> iterator = classes.iterator();
while (iterator.hasNext()) {
    Class<?> next = iterator.next();
    if(AnnotationUtils.containsAnyAnnotation(next, ControllerVax.class)) {
        webSet.add(next);
    }
}
// 2、解析处理方法
Iterator<Class<?>> controller = webSet.iterator();
List<MethodHandler> handlers = new ArrayList<>();
while (controller.hasNext()) {
    Class<?> next = controller.next();
    String commonUrl = AnnotationUtils.get(next, UrlMapping.class);
    List<Method> methods = ClassUtils.getMarkedMethod(next, UrlMapping.class);
    Iterator<Method> methodIt = methods.iterator();
    while (methodIt.hasNext()) {
        Method method = methodIt.next();
        String subUri = AnnotationUtils.get(method, UrlMapping.class);
        MethodHandler methodHandler = new MethodHandler();
        methodHandler.setMethod(method);
        methodHandler.setMethodURL(subUri);
        methodHandler.setClazz(next);
        methodHandler.setClazzUrl(commonUrl);
        methodHandler.setObj(ctx.getBean(next));
        methodHandler.setUrl(PathUtils.merge(commonUrl, subUri));
        methodHandler.setParameters(ClassUtils.getMethodParameters(method));
        if(handlers.contains(methodHandler)) {
        throw new MappingExistsException("method mapping exists");
        }
        handlers.add(methodHandler);
    }
}
2.2、匹配请求

遍历所有的MethodHandler,如果接口上的uri和请求中的uri一直,则将参数带进去执行,并将结果返回。

Iterator<MethodHandler> iterator = handlers.iterator();
        while (iterator.hasNext()) {
            // 接口方法
            MethodHandler handler = iterator.next();
            if(StringUtils.equals(handler.getUrl(), entity.getUri())) {
                // controller实例
                Object bean = ctx.getBean(handler.getClazz());
                Method method = handler.getMethod();
                List<String> parameters = handler.getParameters();
                List<Parameter> parameterType = Arrays.asList(method.getParameters());
                Object[] parameterVal = new Object[parameters.size()];
                for (int i = 0; i < parameters.size(); i++) {
                    // 1、queryString
                    Map<String, String> queryString = entity.getQueryString();
                    if(queryString != null && queryString.size() > 0) {
                        parameterVal[i] = ObjectUtils.firstNotNull(queryString.get(parameters.get(i)));
                    }
                    // 2、body-json/form-data
                    Map<String, String> body = (Map<String, String>) entity.getBody();
                    if(body != null && body.size() > 0) {
                        parameterVal[i] = ObjectUtils.firstNotNull(body.get(parameters.get(i)));
                    }
                    if(!ObjectUtils.isSimpleType(parameterType.get(i).getType()) && StringUtils.equalsIgnore(entity.getContentType(), Constants.JSON_CONTENT_TYPE_VAL)) {
                        parameterVal[i] = JSON.parseObject(entity.getBody().toString(), parameterType.get(i).getType());
                    }
                }
                return ObjectUtils.invoke(bean, method, parameterVal);
            }
        }
3、Spring集成Mybatis

mybatis的代理对象,作为Spring组件,注入到容器中

JdbcManager jdbcManager = new JdbcManager(getJdbcProperties());
packageScanner.setPackages(ctx.getPackages());
this.classes = packageScanner.getFullyQualifiedClassNameList();
Iterator<Class<?>> iterator = this.classes.iterator();
// 2、移除没有被注解标记的类
while (iterator.hasNext()) {
    Class<?> clazz = iterator.next();
    if(!AnnotationUtils.containsAnyAnnotation(clazz, GlobalConstants.MAPPER_ANNOTATIONS)) {
        iterator.remove();
        continue;
    }
    ctx.registry(clazz.getSimpleName(), ProxyUtils.getProxy(clazz, new MapperProxyFactory(jdbcManager)));
}
ctx.refresh(false);
4、运行结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
传送门

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

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

相关文章

次世代建模纹理贴图怎么做?

在线工具推荐&#xff1a; 三维数字孪生场景工具 - GLTF/GLB在线编辑器 - Three.js AI自动纹理化开发 - YOLO 虚幻合成数据生成器 - 3D模型在线转换 - 3D模型预览图生成服务 1、什么是次时代建模&#xff1f; "次世代建模"是一个术语&#xff0c;通常用来描述…

daima8资源网整站数据打包完整代码(集成了ripro9.1主题,开箱即用)

基于ripro9.1完全明文无加密后门版本定制开发&#xff0c;无需独立服务器&#xff0c;虚拟主机也可以完美运营&#xff0c;只要主机支持php和mysql即可。整合了微信登录和几款第三方的主题文件&#xff0c;看起来更美观一些。站长本人就是程序员&#xff0c;所以本站的代码资源…

iceoryx(冰羚)-共享内存分配

iceoryx其实主要分两大部分IceOryxRouDiMemoryManager&#xff0c; PortManager。IceOryxRouDiMemoryManager 负责内存创建、分配、管理。 PortManager 负责消息通讯的接口管理&#xff0c;处理usrapp发来的消息。roudi.cpp接口消息并调用PortManager来处理。 IceOryxRouDiMemo…

Tkinter 面向对象框架《一》

一、说明 在本教程中&#xff0c;您将学习如何在 Tkinter 中应用面向对象编程以使代码更有条理。首先介绍Tk下小部件&#xff0c;然后介绍Ttk小部件&#xff0c;即如何从ttk.Frame类继承并在根窗口中使用它。 二、定义 Tkinter 面向对象的窗口 2.1 最基本的对象 以下简单程序创…

leetcode-206-反转链表(C语言实现)

题目&#xff1a; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]示例 2&#xff1a; 输入&#xff1a;head [1,2] 输出&#xff1a;[2,1]示例 3&…

TA-Lib学习研究笔记(八)——Momentum Indicators 上

TA-Lib学习研究笔记&#xff08;八&#xff09;——Momentum Indicators 上 Momentum Indicators 动量指标&#xff0c;是最重要的股票分析指标&#xff0c;能够通过数据量化分析价格、成交量&#xff0c;预测股票走势和强度&#xff0c;大部分指标都在股票软件中提供。 1. A…

Python函数专题(下)侯小啾python领航班系列(十三)】

Python函数专题(下)侯小啾python领航班系列(十三)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹…

不会代码(零基础)学语音开发(语音开发板)

语音开发板板载资源介绍 通过上图可以看到VDB-150S语音开发板应该是集目前上市的所有语音开发板中板载资源最为丰富的一款开发板。板载的主要资源有&#xff1a; 双色LED状态指示灯&#xff1b;两个测试时使用的按键开关&#xff1b;红外寻迹/接近传感器&#xff1b;固件烧录器…

初识Linux:权限

目录 提示&#xff1a;以下指令均在Xshell 7 中进行 Linux 的权限 内核&#xff1a; 查看操作系统版本 查看cpu信息 查看内存信息 外部程序&#xff1a; 用户&#xff1a; 普通用户变为超级用户&#xff1a; su 和 su-的区别&#xff1a; root用户变成普通用户&#…

管理员配置Jupterhub

在Ubuntu上演示如何部署R语言环境&#xff0c;包括 posit的已经编译了一些R的安装 系统已经装了R&#xff0c;我额外编译的R如何让大家都能用到 如何配置RStudio jupyterhub的配置和使用 管理员如何配置jupyterhub 用户如何配置自己的jupyter环境 Ubuntu上的R部署 这一次…

OSI七层模型与TCP/IP四层模型

一、OSI七层模型简述 OSI 模型的七层是什么&#xff1f;在 OSI 模型中如何进行通信&#xff1f;OSI 模型有哪些替代方案&#xff1f; TCP/IP 模型关于专有协议和模型的说明 二、七层模型详解&#xff08;DNS、CDN、OSI&#xff09; 状态码DNS nslookup命令 CDN whois命令 …

java商城系统选型技巧

近期有很多网友在知乎、百度上咨询如何选择java商城系统&#xff0c;本文我们介绍目前有哪些java商城系统&#xff0c;如何选择商城系统&#xff0c;希望有所帮助。 我们之前做过调研&#xff0c;目前java语言开发的商城系统主要有shop、javashop、ejavashop、远丰、mall4j、li…

【【FPGA 之 MicroBlaze定时器中断实验】】

FPGA 之 MicroBlaze定时器中断实验 AXI Timer 具有 AXI 总线接口&#xff0c;能够产生不同时间周期和占空比的时钟、脉冲产生电路、产生与时间有关的中断和用于电机控制的脉宽调制信号。 AXI Timer IP 核提供了一个 AXI4 Lite 接口用于与处理器通信&#xff1b;它内部有两个可…

美国站卖家请在今年12/28前更新W-8税务信息

美国税务信息采集指南 根据美国国家税务局的规定&#xff0c;非美国纳税人需要向亚马逊提供W-8BEN表格&#xff0c;以豁免美国报税要求。美国国家税务局W-8BEN表格将在卖家向亚马逊提供此表格三年后过期。收到提示时&#xff0c;海外卖家需要重新接受税务信息采集以提交新表格。…

探索APP自动化测试工具的重要作用是什么?

随着移动应用市场的蓬勃发展&#xff0c;保障应用程序的质量和性能成为开发团队至关重要的任务。在这个背景下&#xff0c;APP自动化测试工具崭露头角&#xff0c;成为提高开发效率、减少错误率的关键工具。本文将探讨APP自动化测试工具的用途&#xff0c;以及它们在移动应用开…

Qt开发 之 安装程序错误--安装进程(qt.tool.perl)的解决办法

文章目录 1、问题描述2、问题原因3、解决方案3.1、不关闭错误弹出窗口3.2、手动安装Perl3.3、安装Perl完成后&#xff0c;点击“ignore”继续安装 1、问题描述 Win11下&#xff0c;安装qt5.12.12时遇到“安装进程(qt.tools.perl)运行期间出现错误” 问题描述&#xff1a; Err…

C++-详解智能指针

目录 ​编辑 一.什么是智能指针 1.RAII 2.智能智能指针 二.为什么需要智能指针 1.内存泄漏 a. 什么是内存泄漏&#xff0c;内存泄漏的危害 b.内存泄漏分类 c.如何检测内存泄漏 d.如何避免内存泄漏 总结一下: 2.为什么需要智能指针以及智能指针的原理 三.智能指针的使用 1.C…

程序员养生之道:延寿不忘初心——延寿必备

文章目录 每日一句正能量前言如何养生饮食篇运动篇休息篇后记 每日一句正能量 现代社会已不是大鱼吃小鱼的年代&#xff0c;而是快鱼吃慢鱼的年代。 前言 在IT行业中&#xff0c;程序员是一个重要的职业群体。由于长时间的繁重编程工作&#xff0c;程序员们常常忽略了身体健康…

(Python) 字典dict的使用

a dict(namekl_pen, kl_target0.01, lam0.5) print(类型&#xff1a;, type(a)) print(数值&#xff1a;, a) print(name键的值&#xff1a;, a[name]) print(键&#xff1a;, a.keys()) print(值&#xff1a;, a.values())

知虾平台丨优化Shopee店铺运营,提升销售利润——了解知虾平台

在如今竞争激烈的电商市场中&#xff0c;Shopee作为一家快速发展的平台&#xff0c;吸引了众多卖家加入。然而&#xff0c;要在Shopee上取得成功并实现可观的销售利润&#xff0c;并不是一件容易的事情。为了帮助卖家更好地了解市场趋势、优化商品关键词、监控竞争对手等&#…