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

域名和网站空间相互做解析/宁波seo排名外包

域名和网站空间相互做解析,宁波seo排名外包,网站建设和优化,分析网站建设的论文这里写目录标题 说明一、新建项目二、创建适配器三、创建服务器和客户端3.1 服务器3.2 客户端3.3 客户端发送3.4 客户端接收3.5 服务器接收与发送 四、关于同步Send 说明 今天有小伙伴咨询我,他和同事(c端)协商了一个协议,如果使…

这里写目录标题

  • 说明
  • 一、新建项目
  • 二、创建适配器
  • 三、创建服务器和客户端
    • 3.1 服务器
    • 3.2 客户端
    • 3.3 客户端发送
    • 3.4 客户端接收
    • 3.5 服务器接收与发送
  • 四、关于同步Send

说明

今天有小伙伴咨询我,他和同事(c++端)协商了一个协议,如果使用TouchSocket应该如何解析呢。协议大致如下。

我一看,这个协议还是比较复杂的,因为里面有package len、command len、data len三个部分是不固定的。

而且是不对称协议。即:请求包格式和响应包格式是不一样的(响应包多了一个Code)。

在这里插入图片描述
首先先解释一下数据格式。

  • head:两个字节,固定为“mr”。
  • package len:4字节,int32大端有符号类型。值等于head+package len+command len+command+(code)+data len+data。即所有数据长度。
  • command len:2字节,uint16大端无符号类型,标识command长度
  • command:不固定长度
  • code:仅响应时包含,一个字节
  • data len:4字节,int32大端有符号类型。标识data长度
  • data:不固定长度

看得人头皮发麻,不过虽然难。但是也属于固定包头的范畴。

因为如果我们把head和package len看成一个固定包头的话,固定头就是6。那command len、command、(code)、data len、data就相当于Body,body长度就是package len-6。然后可以再解析command len,command,data len data等。那么就可以使用模板解析“固定包头”数据适配器。

一、新建项目

首先,新建一个控制台项目。使用net6.0。然后nuget安装TouchSocket。此操作不会的小伙伴可以看看入门 TouchSocket入门和VS、Unity安装和使用Nuget包

二、创建适配器

TouchSocket中,适配器就是负责对数据编解码的。具体可以看数据处理适配器。

首先新建一个类,名为MyBase。用于存放请求和响应的共同成员。结构大致如下:

class MyBase
{/// <summary>/// header固定为mr/// </summary>public string Header => "mr";public ushort CommandLen { get; protected set; }public byte[] Command { get; protected set; }public int DataLen { get; protected set; }public byte[] Data { get; protected set; }public void SetCommand(byte[] command){this.Command = command;this.CommandLen = (ushort)(command == null ? 0 : command.Length);}public void SetData(byte[] data){this.Data = data;this.DataLen = data == null ? 0 : data.Length;}
}

因为此协议是不对称协议,对于客户端,它需要发送Request,然后能解析Response。

对于服务器,它需要接受(解析)Request,响应(发送)Response

那么我们先来写客户端适配器。

首先再新建一个类,名为MyResponsePackage。然后继承MyBase,同时实现IFixedHeaderRequestInfo

操作原理可以看模板解析“固定包头”数据适配器

class MyResponsePackage : MyBase, IFixedHeaderRequestInfo
{public byte Code { get; private set; }private int m_length;public void SetCode(byte code){this.Code = code;}int IFixedHeaderRequestInfo.BodyLength => this.m_length;bool IFixedHeaderRequestInfo.OnParsingBody(byte[] body){try{//下标索引int index = 0;this.CommandLen = TouchSocketBitConverter.BigEndian.ToUInt16(body, index);index += 2;this.Command = body.Skip(index).Take(this.CommandLen).ToArray();index += this.CommandLen;this.Code = body[index];index += 1;this.DataLen = TouchSocketBitConverter.BigEndian.ToInt32(body, index);index += 4;this.Data = body.Skip(index).Take(this.DataLen).ToArray();index += this.DataLen;return true;}catch (Exception ex){return false;}}bool IFixedHeaderRequestInfo.OnParsingHeader(byte[] header){var headerStr = Encoding.ASCII.GetString(header, 0, 2);if (this.Header.Equals(headerStr)){this.m_length = TouchSocketBitConverter.BigEndian.ToInt32(header, 2) - 6;return true;}return false;}
}

然后再新建一个类,名为MyClientAdapter,继承CustomFixedHeaderDataHandlingAdapter,同时指定MyResponsePackage为泛型成员。

/// <summary>
/// 此适配器仅用于客户端。解析收到的<see cref="MyResponsePackage"/>
/// </summary>
internal class MyClientAdapter : CustomFixedHeaderDataHandlingAdapter<MyResponsePackage>
{public override int HeaderLength => 6;protected override MyResponsePackage GetInstance(){return new MyResponsePackage();}
}

至此,客户端的适配器解析就完成了。

现在我们来写服务器端适配器。

首先新建一个类,名为MyRequestPackage,同样继承MyBase,然后实现IFixedHeaderRequestInfo

class MyRequestPackage : MyBase, IFixedHeaderRequestInfo
{private int m_length;int IFixedHeaderRequestInfo.BodyLength => this.m_length;bool IFixedHeaderRequestInfo.OnParsingBody(byte[] body){try{//下标索引int index = 0;this.CommandLen = TouchSocketBitConverter.BigEndian.ToUInt16(body, index);index += 2;this.Command = body.Skip(index).Take(this.CommandLen).ToArray();index += this.CommandLen;this.DataLen = TouchSocketBitConverter.BigEndian.ToInt32(body, index);index += 4;this.Data = body.Skip(index).Take(this.DataLen).ToArray();index += this.DataLen;return true;}catch (Exception ex){return false;}}bool IFixedHeaderRequestInfo.OnParsingHeader(byte[] header){var headerStr = Encoding.ASCII.GetString(header, 0, 2);if (this.Header.Equals(headerStr)){this.m_length = TouchSocketBitConverter.BigEndian.ToInt32(header, 2) - 6;return true;}return false;}
}

然后新建一个类,名为MyServerAdapter。同样继承CustomFixedHeaderDataHandlingAdapter,指定MyRequestPackage为泛型成员。

/// <summary>
/// 此适配器仅用于服务器。主要功能是解析收到的<see cref="MyRequestPackage"/>
/// </summary>
internal class MyServerAdapter : CustomFixedHeaderDataHandlingAdapter<MyRequestPackage>
{public override int HeaderLength => 6;protected override MyRequestPackage GetInstance(){return new MyRequestPackage();}
}

至此。服务器适配器就写好了。

如果你的工作只是其中的一部分。那么你可以直接交差了。但是对我们来说还差点东西。

比如,对于客户端。我们应该怎么发送数据呢?按字节发送吗?那就太low了。

我们当然是要封装成对象来发送才比较好操作。

那么,让我们来改造一下MyRequestPackage

首先,我们需要让MyRequestPackage再实现一个IRequestInfoBuilder的接口。该接口大概如下,其中Build方法,会指示成员应当如何构建数据。

/// <summary>
/// 指示<see cref="IRequestInfo"/>应当如何构建
/// </summary>
public interface IRequestInfoBuilder
{/// <summary>/// 构建数据时,指示内存池的申请长度。/// </summary>int MaxLength { get;}/// <summary>/// 构建对象到<see cref="ByteBlock"/>/// </summary>/// <param name="byteBlock"></param>void Build(ByteBlock byteBlock);
}

实现完大概这样。

class MyRequestPackage : MyBase, IRequestInfoBuilder, IFixedHeaderRequestInfo
{...public int MaxLength => 1024 * 1024;//构建数据时,指示内存池的申请长度。也就是单个包可能达到的最大长度。避免内存池扩容带来消耗public int PackageLen{get{int len = 0;len += 2;//headlen += 4;//PackageLenlen += 2;//commandlenlen += Command == null ? 0 : Command.Length; //Commandlen += 2;//data lenlen += this.Data == null ? 0 : this.Data.Length;//Datareturn len;}}public void Build(ByteBlock byteBlock){byteBlock.Write(Encoding.ASCII.GetBytes(this.Header));byteBlock.Write(this.PackageLen, bigEndian: true);byteBlock.Write(this.CommandLen, bigEndian: true);byteBlock.Write(this.Command);byteBlock.Write(this.DataLen, bigEndian: true);byteBlock.Write(this.Data);}
}

然后此时,我们只需要在MyClientAdapter里面设置支持对象发送即可。

/// <summary>
/// 此适配器仅用于客户端。主要功能是包装发送的<see cref="MyRequestPackage"/>。解析收到的<see cref="MyResponsePackage"/>
/// </summary>
internal class MyClientAdapter : CustomFixedHeaderDataHandlingAdapter<MyResponsePackage>
{...//因为MyRequestPackage已经实现IRequestInfoBuilder接口,所以可以使用True。public override bool CanSendRequestInfo => true;
}

此后,我们只需要发送MyRequestPackage对象,然后适配器内部会自动调用Build函数,然后执行发送。

同理,对于服务也需要这样做。

class MyResponsePackage : MyBase, IFixedHeaderRequestInfo, IRequestInfoBuilder
{...public int PackageLen{get{int len = 0;len += 2;//headlen += 4;//PackageLenlen += 2;//commandlenlen += Command == null ? 0 : Command.Length; //Commandlen += 1;//codelen += 2;//data lenlen += this.Data == null ? 0 : this.Data.Length;//Datareturn len;}}public int MaxLength => 1024 * 1024;//构建数据时,指示内存池的申请长度。也就是单个包可能达到的最大长度。避免内存池扩容带来消耗public void Build(ByteBlock byteBlock){byteBlock.Write(Encoding.ASCII.GetBytes(this.Header));byteBlock.Write(this.PackageLen, bigEndian: true);byteBlock.Write(this.CommandLen, bigEndian: true);byteBlock.Write(this.Command);byteBlock.Write(this.Code);byteBlock.Write(this.DataLen, bigEndian: true);byteBlock.Write(this.Data);}
}
/// <summary>
/// 此适配器仅用于服务器。主要功能是包装发送的<see cref="MyResponsePackage"/>。解析收到的<see cref="MyRequestPackage"/>
/// </summary>
internal class MyServerAdapter : CustomFixedHeaderDataHandlingAdapter<MyRequestPackage>
{...//因为MyRequestPackage已经实现IRequestInfoBuilder接口,所以可以使用True。public override bool CanSendRequestInfo => true;
}

至此,基本的工作就完全完成了。

三、创建服务器和客户端

3.1 服务器

服务器应该使用MyServerAdapter适配器。其他配置可以看TcpService

var service = new TcpService();
service.Received = async (client, e) =>
{if (e.RequestInfo is MyRequestPackage requestPackage){await Console.Out.WriteLineAsync("已收到MyRequestPackage");//构建响应var response=new MyResponsePackage();response.SetCode(200);response.SetCommand(new byte[] {0,1,2 });response.SetData(new byte[] {3,4,5 });await client.SendAsync(response);}
};service.Setup(new TouchSocketConfig()//载入配置.SetListenIPHosts("tcp://127.0.0.1:7789", 7790)//同时监听两个地址.SetTcpDataHandlingAdapter(() => new MyServerAdapter()).ConfigureContainer(a =>//容器的配置顺序应该在最前面{a.AddConsoleLogger();//添加一个控制台日志注入(注意:在maui中控制台日志不可用)}).ConfigurePlugins(a =>{//a.Add();//此处可以添加插件}));service.Start();//启动

3.2 客户端

客户端应该使用MyClientAdapter适配器。其他配置可以看TcpClient

var tcpClient = new TcpClient();
tcpClient.Received =async (client, e) =>
{//从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。if (e.RequestInfo is MyResponsePackage responsePackage){await Console.Out.WriteLineAsync("已收到MyResponsePackage");}
};//载入配置
tcpClient.Setup(new TouchSocketConfig().SetRemoteIPHost("127.0.0.1:7789").SetTcpDataHandlingAdapter(()=>new MyClientAdapter()).ConfigureContainer(a =>{a.AddConsoleLogger();//添加一个日志注入})) ;tcpClient.Connect();//调用连接,当连接不成功时,会抛出异常。tcpClient.Logger.Info("客户端成功连接");

3.3 客户端发送

在发送时,我们可以直接发送一个MyRequestPackage的对象,因为适配器里面已经定义了如何Build

var client = GetTcpClient();var request = new MyRequestPackage();
request.SetCommand(new byte[] {0,1,2 });
request.SetData(new byte[] {3,4,5 });
client.Send(request);

3.4 客户端接收

客户端在接收时,适配器会做好解析,然后直接投递MyResponsePackage对象。

var tcpClient = new TcpClient();
tcpClient.Received =async (client, e) =>
{//从服务器收到信息。但是一般byteBlock和requestInfo会根据适配器呈现不同的值。if (e.RequestInfo is MyResponsePackage responsePackage){await Console.Out.WriteLineAsync("已收到MyResponsePackage");}
};

3.5 服务器接收与发送

同理,服务器接收时,适配器会解析投递MyRequestPackage,发送时直接发送MyResponsePackage即可。

var service = new TcpService();
service.Received = async (client, e) =>
{if (e.RequestInfo is MyRequestPackage requestPackage){await Console.Out.WriteLineAsync("已收到MyRequestPackage");//构建响应var response=new MyResponsePackage();response.SetCode(200);response.SetCommand(new byte[] {0,1,2 });response.SetData(new byte[] {3,4,5 });await client.SendAsync(response);}
};

四、关于同步Send

同步Send,就是发送一个数据,然后等待响应,详情可以看Tcp同步请求

但是此处有个小问题,就是waitClient.SendThenReturn函数并没有发送对象的实现。那么我们就需要手动Build数据。

同时只能用SendThenResponse,而不是SendThenReturn

var client = GetTcpClient();var request = new MyRequestPackage();
request.SetCommand(new byte[] { 0, 1, 2 });
request.SetData(new byte[] { 3, 4, 5 });
client.Send(request);var waitingClient = client.CreateWaitingClient(new WaitingOptions());
var responsedData = waitingClient.SendThenResponse(request.BuildAsBytes());
if (responsedData.RequestInfo is MyResponsePackage responsePackage)
{//to do
}

结束,看起来很麻烦的协议,实际上也可以很优雅的解决。

最后,完整代码我上传到 csdn资源。没别的意思,就是我的积分也没有了。得赚点积分。

如果大家下载困难,不妨把文中代码复制一下也可以,因为全部代码也在这里。

相关文章:

使用TouchSocket适配一个c++的自定义协议

这里写目录标题 说明一、新建项目二、创建适配器三、创建服务器和客户端3.1 服务器3.2 客户端3.3 客户端发送3.4 客户端接收3.5 服务器接收与发送 四、关于同步Send 说明 今天有小伙伴咨询我&#xff0c;他和同事&#xff08;c端&#xff09;协商了一个协议&#xff0c;如果使…...

VSC改造MD编辑器及图床方案分享

VSC改造MD编辑器及图床方案分享 用了那么多md编辑器&#xff0c;到头来还是觉得VSC最好用。这次就来分享一下我的blog文件编辑流吧。 这篇文章包括&#xff1a;VSC下md功能扩展插件推荐、图床方案、blog文章管理方案 VSC插件 Markdown All in One Markdown Image - 粘粘图片…...

SpringBoot的依赖管理和自动配置

与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 1 依赖管理机制2 自动配置机制2.1 初步理解2.2 完整流程 &#x1f48e;总结 1 依赖管理机制 为什么导入starter-web后所有相关依赖都会导入进来&#xff1f; 开发什么场景&#xff0c;导入什么场景启动器-spring-bo…...

linux 定时任务

使用 crontab Usage: crontab [-u user] [-e|-l|-r] Crontab 的格式说明如下: * 逗号(‘,’) 指定列表值。如: “1,3,4,7,8″ * 中横线(‘-’) 指定范围值 如 “1-6″, 代表 “1,2,3,4,5,6″ * 星号 (‘*’) 代表所有可能的值 */15 表示每 15 分钟执行一次 # Use the ha…...

增强现实中的真实人/机/环与虚拟人/机/环

在增强现实中&#xff0c;真实人与虚拟人、真实机器与虚拟机器、真实环境与虚拟环境之间有着密切的关系。增强现实技术通过将真实与虚拟相结合&#xff0c;打破了传统的现实世界与虚拟世界的界限&#xff0c;创造出了一种新的体验方式。真实人、真实机器和真实环境与其对应的虚…...

Python网络爬虫环境的安装指南

网络爬虫是一种自动化的网页数据抓取技术&#xff0c;广泛用于数据挖掘、信息搜集和互联网研究等领域。Python作为一种强大的编程语言&#xff0c;拥有丰富的库支持网络爬虫的开发。本文将为你详细介绍如何在你的计算机上安装Python网络爬虫环境。 一、安装python开发环境 进…...

【MyBatis系列】MyBatis字符串问题

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

【Java】构建表达式二叉树和表达式二叉树求值

问题背景 1. 实现一个简单的计算器。通过键盘输入一个包含圆括号、加减乘除等符号组成的算术表达式字符串&#xff0c;输出该算术表达式的值。要求&#xff1a; &#xff08;1&#xff09;系统至少能实现加、减、乘、除等运算&#xff1b; &#xff08;2&#xff09;利用二叉…...

采用Python 将PDF文件按照页码进行切分并保存

工作中经常会遇到 需要将一个大的PDF文件 进行切分&#xff0c;比如仅需要大PDF文件的某几页 或者连续几页&#xff0c;一开始都是用会员版本的WPS&#xff0c;但是对于程序员&#xff0c;就是要采用技术白嫖 这里就介绍一个 python的PDF 包 PyPDF2 其安装方式也很简单 p…...

H264视频编码原理

说到视频&#xff0c;我们首先想到的可能就是占内存。我们知道一个视频是由一连串图像序列组成的&#xff0c;视频中图像一般是 YUV 格式。假设有一个电影视频&#xff0c;分辨率是 1080P&#xff0c;帧率是 25fps&#xff0c;并且时长是 2 小时&#xff0c;如果不做视频压缩的…...

UDP实现群聊

代码&#xff1a; import java.awt.*; import java.awt.event.*; import javax.swing.*; import java.net.*; import java.io.IOException; import java.lang.String;public class liaotian extends JFrame{private static final int DEFAULT_PORT8899;private JLabel stateLB…...

服务器部署网易开源TTS | EmotiVoice部署教程

一、环境 ubuntu 20.04 python 3.8 cuda 11.8二、部署 1、docker方式部署 1.1、安装docker 如何安装docker&#xff0c;可以参考这篇文章 1.2、拉取镜像 docker run -dp 127.0.0.1:8501:8501 syq163/emoti-voice:latest2、完整安装 安装python依赖 conda create -n Emo…...

贪心算法和动态规划

目录 一、简介 二、贪心算法案例&#xff1a;活动选择问题 1.原理介绍 三、动态规划案例&#xff1a;背包问题 1.原理介绍 四、贪心算法与动态规划的区别 五、总结 作者其他文章链接 正则表达式-CSDN博客 深入理解HashMap&#xff1a;Java中的键值对存储利器-CSDN博客…...

jsp 设备预约管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 设备预约管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…...

Python:核心知识点整理大全10-笔记

目录 5.4 使用 if 语句处理列表 5.4.1 检查特殊元素 toppings.py 5.4.2 确定列表不是空的 5.4.3 使用多个列表 5.5 设置 if 语句的格式 5.6 小结 第6章 字 典 6.1 一个简单的字典 alien.py 6.2 使用字典 6.2.1 访问字典中的值 6.2.2 添加键—值对 6.2.3 先创建一…...

Hive数据库系列--Hive数据类型/Hive字段类型/Hive类型转换

文章目录 一、Hive数据类型1.1、数值类型1.2、字符类型1.3、日期时间类型1.4、其他类型1.5、集合数据类型1.5.1、Struct举例1.5.2、Array举例1.5.3、Map举例 二、数据类型转换2.1、隐式转换2.2、显示转换 三、字段类型的使用3.1、DECIMAL(precision&#xff0c;scale) 本章主要…...

在Spring Cloud中使用组件Ribbon和Feign,并分别创建子模块注册到Eureka中去

ok&#xff0c;在上篇文章中我们讲了在Spring cloud中使用Zuul网关&#xff0c;这篇文章我们将Spring Cloud的五大核心组件的Ribbon和Feign分别创建一个微服务模块。 题外话&#xff0c;本篇博客就是配置子模块&#xff0c;或者说是微服务&#xff0c;然后将微服务正式启动之前…...

(JAVA)-缓冲流

缓冲流能高效的读取数据 缓冲流底层自带了8192的缓冲区提高性能&#xff0c;他在原有的流上进行了包装&#xff0c;加上了缓冲效果 原理&#xff1a; 读入时首先会将内存中缓冲区大小的数据读入缓冲区中&#xff0c;接着下次读取直接从缓冲区中读取数据&#xff0c;当缓冲区…...

Autosar UDS-CAN诊断开发02-1(CAN诊断帧格式类型详解、CANFD诊断帧格式类型详解、15765-2(CANTP层)的意义)

目录 前言 CANTP层&#xff08;15765-2协议&#xff09;存在的意义 CANTP层&#xff08;15765-2协议&#xff09;帧类型详细解读&#xff08;普通CAN格式&#xff09; 四种诊断报文类型 单帧SingleFrame(SF) 首帧&#xff1a;FirstFrame(FF) 流控帧&#xff1a;FlowCont…...

swing快速入门(三)

解答一下上一篇关于留下的关于布局管理器的疑问 上一篇 几种常见的布局管理器 看不懂&#xff1f;看不懂没关系&#xff0c;这篇是概念篇&#xff0c;大概了解一下就行~ 1.FlowLayout&#xff08;流式布局&#xff09;&#xff1a;按照从左到右、从上到下的顺序依次排列组件。…...

Swagger PHP Thinkphp 接口文档

安装 1. 安装依赖 composer require zircote/swagger-php 2. 下载Swagger UI git clone https://github.com/swagger-api/swagger-ui.git 3. 复制下载好的Swagger UI 中的dist目录到public目录中&#xff0c;修改目录名称 cp -rf swagger-ui/dist /home/htdocs/public/ m…...

12.9每日一题(备战蓝桥杯循环结构)

12.9每日一题&#xff08;备战蓝桥杯循环结构&#xff09; 题目 2165: 求平均年龄题目描述输入输出样例输入样例输出来源/分类 题解 2165: 求平均年龄题目 2166: 均值题目描述输入输出样例输入样例输出来源/分类 题解 2166: 均值题目 2167: 求整数的和与均值题目描述输入输出样…...

与时代共进退

还记得当初自己为什么选择计算机&#xff1f; 当初你问我为什么选择计算机&#xff0c;我笑着回答&#xff1a;“因为我梦想成为神奇的码农&#xff01;我想像编织魔法一样编写程序&#xff0c;创造出炫酷的虚拟世界&#xff01;”谁知道&#xff0c;我刚入门的那天&#xff0…...

Python 云服务器应用,Https,定时重启

Python 云服务器应用,Https,定时重启 环境搭建Python模块模块导入生成Flask实例GET处理启动服务器打开网页验证 GET接入证书 支持https申请证书下载证书保留 xxx.crt 和 xxx.key文件就可以了 copy到python项目目录ssl_context 配置 宝塔面板操作在www目录下新建python工作目录在…...

pytorch 笔记:dist 和 cdist

1 dist 1.1 基本使用方法 torch.dist(input, other, p2) 计算两个Tensor之间的p-范数 1.2 主要参数 input输入张量other另一个输入张量p范数 input 和 other的形状需要是可广播的 1.3 举例 import torchxtorch.randn(4) x #tensor([ 1.2698, -0.1209, 0.0462, -1.3271…...

Java的List中的各种浅拷贝和深拷贝问题

先来看一组代码 public class Temp{public static void main(String[] args) {List<Integer> list new ArrayList<>();list.add(1);list.add(2);list.add(3);List<Integer> temp list;list.add(4);System.out.println(list.toString());System.out.print…...

20231207_最新已测_Centos7.4安装nginx1.24.0_安装详细步骤---Linux工作笔记066

以前安装的太模糊了,干脆重新写一个: 1.首先下载对应的nginx-1.24.0.tar.gz安装文件 2.然后: 去执行命令 安装依赖 yum install -y gcc yum install -y pcre pcre-devel yum install -y zlib zlib-devel yum install -y openssl openssl-devel 3.然后:去解压 tar -zxvf ngi…...

前端知识笔记(二十六)———React如何像Vue一样将css和js写在同一文件

如果想在React中想要像Vue一样把css和js写到一个文件中&#xff0c;可以使用CSS-in-JS。 使用CSS-in-JS 下载 npm i styled-components使用 就像写scss一样&#xff0c;不过需要声明元素的类型 基本语法及展示如下 import styled from "styled-components"expor…...

Photoshop Circular Text

Ctrl N 新增 现学现卖...

深入解析Spring Boot中的注解@PathVariable、@RequestParam、@RequestBody的正确使用

文章目录 1. 引言2. PathVariable&#xff1a;处理路径变量2.1 简介2.2 使用示例 3. RequestParam&#xff1a;处理请求参数3.1 简介3.2 使用示例 4. RequestBody&#xff1a;处理请求体4.1 简介4.2 使用示例 5. 多个注解的组合使用6. 参数绑定的原理6.1 HandlerMethodArgument…...