【spring mvc】全局处理请求体和响应体

目录

  • 说明
  • 实现效果
    • 逻辑图
  • 实现步骤
    • 创建公共处理的请求和响应的类
    • api接口
    • 测试
      • 前端请求
      • 响应结果
  • 扩展
    • Response响应格式实体
    • ResponseCode 响应状态码
    • RSA工具类
  • RequestBodyAdvice 介绍
    • 使用场景
  • ResponseBodyAdvice 介绍
    • 使用场景

说明

由于项目中需要进行加密传输数据提高项目安全性,前端调用接口时,请求体中的数据全部加密成密文传输到后端接口,后端接口接收之后解密回明文。本例中使用的RSA非对称加解密方式处理。

如果后端接口参数使用字符串String 接收密文参数,则需要在每个接口方法中进行解密操做,代码会产生冗余。

如下伪代码:

@Slf4j
@RestController
@RequestMapping(value = "user")
public class TUserController {/*** 说明: 添加* @author   zhangxiaosan* @create   2024/12/3* @param* @return*/@PostMapping(value = "add")public String add(@RequestBody String user){// user 参数为前端传递过来的 密文// 使用RSA 解密方法,传入密文和密钥解密得到明文String data = RSA.decryption(user,key); // 此部分为冗余代码。// todo 业务操做逻辑return user.toString();}
}

现在,有个需求是,接口方法中正常使用实体类来作为参数类型接收。前端依旧是传递加密后的密文。后端接收到密文之后,解密得到明文后,将明文数据转成接口参数所需要的数据类型。

业务处理完成之后,将返回的数据再进行加密传给前端。前端解密后才能得到明文展示 。

实现效果

逻辑图

在这里插入图片描述

实现步骤

创建公共处理的请求和响应的类

此类主要是公共处理api接收前端请求的密文参数,解密。处理方法返回数据的加密。

import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import www.three.common.response.Response;
import www.three.common.security.rsa.RSAUtil;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
import java.util.Objects;/*** 说明:* 对请求体和响应体进行加密解密* 此类用于全局处理请求和响应的功能类* RequestBodyAdvice 接口* RequestBodyAdvice 接口用于在请求的请求体被反序列化(即转化为 Java 对象)之前对其进行处理。你可以使用它来解密请求体中的数据。* <p>* ResponseBodyAdvice<Response> 接口* ResponseBodyAdvice 接口用于在响应体被序列化(即将 Java 对象转化为响应内容)之前对其进行处理。你可以使用它来加密响应体中的数据。Response 为自定义的响应格式实体类。** @author 张小三* @create 2024-12-04 10:00* @verson 1.0.0*/
@Slf4j
@ControllerAdvice
public class EncryptRequestResponseBodyAdvice implements ResponseBodyAdvice<Response>, RequestBodyAdvice {// 前端 RSA算法的私钥,用于解密前端传递过来的密文。前端需要于此私钥对应的公钥进行加密数据。private static final String privateKey = "";// 此处填写为前端的RSA私钥// 后端Api RSA 算法的公钥,用于加密响应体的数据。前端需要使用此公钥对应的私钥才能进行数据解密。private static final String publicKey = ""; // 此处填写为后端api的RSA公钥/*** 此方法判断当前处理器是否支持给定的方法参数、目标类型和HTTP消息转换器类型* @param methodParameter 方法参数* @param targetType      目标类型* @param converterType   HTTP消息转换器类型* @return 总是返回false,表示不支持*/@Overridepublic boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {return true;//返回 true 表示我们想要处理所有请求的请求体}/*** 在读取请求体之前调用此方法进行预处理* @param inputMessage  输入消息* @param parameter     方法参数* @param targetType    目标类型* @param converterType HTTP消息转换器类型* @return 返回null,表示不需要进行特殊处理* @throws IOException 如果处理过程中发生I/O错误*/@Overridepublic HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException {return new HttpInputMessage() {@Overridepublic InputStream getBody() throws IOException {// 读取响应体的流InputStream inputStream = inputMessage.getBody();byte[] bytes = new byte[inputStream.available()];inputStream.read(bytes);// 转成字符串String data = JSON.parseObject(bytes).getString("data");log.info("RequestBody 密文:" + data);// 使用RSA工具方法解密data = RSAUtil.decryption(data,privateKey);log.info("RequestBody 明文:" + data);return new ByteArrayInputStream(data.getBytes());}@Overridepublic HttpHeaders getHeaders() {return inputMessage.getHeaders();}};}/*** 在读取请求体之后调用此方法进行后处理** @param body          请求体内容* @param inputMessage  输入消息* @param parameter     方法参数* @param targetType    目标类型* @param converterType HTTP消息转换器类型* @return 返回null,表示不需要进行特殊处理*/@Overridepublic Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {return body;}/*** 当请求体为空时调用此方法进行处理** @param body          请求体内容(此时为空)* @param inputMessage  输入消息* @param parameter     方法参数* @param targetType    目标类型* @param converterType HTTP消息转换器类型* @return 返回null,表示不需要进行特殊处理*/@Overridepublic Object handleEmptyBody(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {return body;}/*** 此方法判断当前处理器是否支持给定的返回类型和HTTP消息转换器类型* @param returnType    返回类型* @param converterType HTTP消息转换器类型* @return 总是返回false,表示不支持*/@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return true;}/*** 在写入响应体之前调用此方法进行预处理* 本实现中不需要任何预处理,因此返回null** @param body                  响应体内容* @param returnType            返回类型* @param selectedContentType   选定的内容类型* @param selectedConverterType 选定的HTTP消息转换器类型* @param request               HTTP请求* @param response              HTTP响应* @return 返回null,表示不需要进行特殊处理*/@Overridepublic Response beforeBodyWrite(Response body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {if (Objects.nonNull(body) && body.getData() != null) {String data = JSON.toJSONString(body.getData());log.info("ResponseBody 明文:" + data);// 用RSA工具将返回的数据进行加密data = RSAUtil.encryption(data,publicKey);log.info("ResponseBody 密文:" + data);body.setData(data);}return body;}
}

api接口

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import www.three.common.response.Response;
import www.three.components.log.annotations.Log;
import www.three.system.user.model.po.TUser;/*** 说明:** @author 张小三* @create 2024-12-03 17:37* @verson 1.0.0*/
@Slf4j
@RestController
@RequestMapping(value = "user")
public class TUserController {/*** 说明: 添加* @author   zhangxiaosan* @create   2024/12/3* @param* @return*/@Log@PostMapping(value = "add")public Response<?> add(@RequestBody TUser user){log.info("添加用户:{}",user.toString());return Response.success(user);}
}

测试

前端请求

使用idea的 HTTP Client 工具 请求案例:

POST http://127.0.0.1:8081/three-user/user/add
Content-Type: application/json{"data":"6944323931323669415876424a653867445233636247553464552b3256466c2b3631586639314675584a6b5068394a6f6b54457235464c4743666e496b5342574a6256564e484b4c49667a6d0d0a6c55696d74444b4778363858465945516f34756d4b6938714f494b732f5157742b6a3235543256737733356c7677465976474463613043454e636376726257502f2f6f3337686c6d6b6e46680d0a38367237467663634c6950586648657135534b31736d6e372b6637667658454d386a79454e794c346b44546c444f367050476e594c793041366d65324a4a6136387251536a616963325a51680d0a6756446369386a743346755a47565377574147332f76306739472f57614e4b3330372b4455467377677536536e79534e71703530635637576a5a38533732654477744d4365587945653638550d0a4976704d4c6e6a303465446c754f506474626f33493578693479724265446a6f356f46557a513d3d"}

响应结果

{"code": 0,"message": "成功","data": "4b637168342f4a7537637956784c7368637a527068314772783139515555506e336e7049474469524a654754464a7242327873545766574a666c346d66427268414b754264306a45454766640d0a5a764a76426e644d77526664613632635a48596a72562b546447597366653667796f6c68616648536f786f6737464575765342686b706473624b4d78574b645145637257655a62615a6e4c670d0a6d79566f467a697a7a5468445153744264627a6d304b42524d54654b6f41347746376d6137427878774c66537159526856484261486f305578734b686f4d78763638434342763959653249320d0a4f557073423545784b354e5a724465416663535a502f4b34516455464d4f33655a335552505067674f714f6d42755a4351654858586c3366334441704448444f5a6b644561354b436e702f330d0a636d6e2f38347771586c62373038344d316479546b4e466778696358592b62555864567a51773d3d","count": null
}

扩展

Response响应格式实体

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import lombok.Data;/*** 说明:** @author 张小三* @create 2024-07-12 16:12* @verson 1.0.0*/
@Data
public class Response<T> {/*** 状态码* 其他值表示失败*/private Integer code;/*** 提示信息*/private String message;/*** 响应数据*/private T data;/*** 数据总量(layui 列表使用)*/private Integer count;public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public Object getData() {return data;}public void setData(T data) {this.data = data;}public Integer getCount() {return count;}public void setCount(Integer count) {this.count = count;}public Response(Integer code, String message, T data, Integer count) {this.code = code;this.message = message;this.data = data;this.count = count;}public static <T> Response<T> success(){return response(ResponseCode.successCode,ResponseCode.successMessage,null,null);}public static <T> Response<T> success(T data){return response(ResponseCode.successCode,ResponseCode.successMessage,data,null);}public static <T> Response<T> success(T data, String message){return response(ResponseCode.successCode,message,data,null);}public static <T> Response<T> fail(){return response(ResponseCode.failCode,ResponseCode.failMessage,null,null);}public static <T> Response<T> fail(String message){return response(ResponseCode.failCode,message,null,null);}private static <T> Response<T> response(Integer code,String message,T data,Integer count){return new Response(code,message,data,count);}@Overridepublic String toString() {JSONObject jsonObject = new JSONObject();jsonObject.put("code",code);jsonObject.put("message",message);jsonObject.put("count",count);jsonObject.put("data",data);return JSON.toJSONString(jsonObject, JSONWriter.Feature.WriteNulls);}}

ResponseCode 响应状态码

import java.io.Serializable;/*** 说明:*  响应状态码* @author 张小三* @create 2024-07-12 14:19* @verson 1.0.0*/
public class ResponseCode implements Serializable {/*** 说明: 成功状态码* @author   zhangxiaosan* @create   2024/7/12* @param* @return*/public static final Integer successCode = 0;/*** 说明: 成功默认信息* @author   zhangxiaosan* @create   2024/7/12* @param* @return*/public static final String successMessage = "成功";/*** 说明: 失败状态码* @author   zhangxiaosan* @create   2024/7/12* @param* @return*/public static final Integer failCode = -1;/*** 说明: 失败默认信息* @author   zhangxiaosan* @create   2024/7/12* @param* @return*/public static final String failMessage = "失败";}

RSA工具类

import com.alibaba.fastjson2.JSONObject;
import www.three.common.security.hex.HexUtil;import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;/*** 说明:*  rsa 工具类* @author 张小三* @create 2024-12-03 11:52* @verson 1.0.0*/
public class RSAUtil {private static String keySize =  "2048";/*** 创建公钥和私钥** @return* @throws RSAException*/public static Map<String, String> createKeys() throws RSAException {KeyPairGenerator keygen;try {keygen = KeyPairGenerator.getInstance("RSA");} catch (NoSuchAlgorithmException e) {throw new RSAException("RSA初始化密钥出现错误,算法异常");}SecureRandom secrand = new SecureRandom();//初始化随机产生器secrand.setSeed("jst".getBytes());//初始化密钥生成器if (Objects.isNull(keySize)){keySize = "2048";}keygen.initialize(Integer.valueOf(keySize), secrand);KeyPair keyPair = keygen.genKeyPair();//获取公钥并转成base64编码byte[] pub_key = keyPair.getPublic().getEncoded();String publicKeyStr = Base64.getEncoder().encodeToString(pub_key);//获取私钥并转成base64编码byte[] pri_key = keyPair.getPrivate().getEncoded();String privateKeyStr = Base64.getEncoder().encodeToString(pri_key);// 公钥和私钥转成16进制publicKeyStr = HexUtil.encode(publicKeyStr);privateKeyStr = HexUtil.encode(privateKeyStr);//创建一个Map返回结果Map<String, String> keyPairMap = new HashMap<>();keyPairMap.put("publicKey", publicKeyStr);keyPairMap.put("privateKey", privateKeyStr);return keyPairMap;}/*** RSA 加密** @param data 加密内容* @param key  密钥* @return*/public static  String encryption(String data,String key) throws RSAException {// 16进制密钥还原key = HexUtil.decode(key);byte[] publicKeyByte = Base64.getMimeDecoder().decode(key);X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyByte);String res = null;try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.ENCRYPT_MODE,publicKey);byte[] bytes = cipher.doFinal(data.getBytes());res = Base64.getMimeEncoder().encodeToString(bytes);res = HexUtil.encode(res); // 密文转成16进制} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException |IllegalBlockSizeException | BadPaddingException e) {throw new RSAException("RSA出现错误,算法异常:"+e.getMessage());}return res ;}/*** RSA 解密** @param data 密文* @param key 密钥* @return*/public  static String decryption(String data ,String key) throws RSAException {// 16进制密钥还原key = HexUtil.decode(key);byte[] privateKeyByte = Base64.getMimeDecoder().decode(key);PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyByte);String res = null;try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());cipher.init(Cipher.DECRYPT_MODE,privateKey);// 密文还原data = HexUtil.decode(data);byte[] decode = Base64.getMimeDecoder().decode(data);byte[] bytes = cipher.doFinal(decode);res = new String(bytes);} catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {throw new RSAException("RSA出现错误,算法异常:"+e.getMessage());}return res ;}/*** RSA 签名** @param data 待签名的数据* @param privateKey 私钥* @return 签名后的字符串* @throws RSAException 如果签名过程中出现异常*/public static String sign(String data, String privateKey) throws RSAException {// 16进制密钥还原privateKey = HexUtil.decode(privateKey);byte[] privateKeyByte = Base64.getMimeDecoder().decode(privateKey);PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKeyByte);String signature = null;try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");PrivateKey privateKeyObj = keyFactory.generatePrivate(pkcs8EncodedKeySpec);Signature signer = Signature.getInstance("SHA256withRSA");signer.initSign(privateKeyObj);signer.update(data.getBytes());byte[] signedData = signer.sign();signature = Base64.getMimeEncoder().encodeToString(signedData);signature = HexUtil.encode(signature); // 签名转成16进制} catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | SignatureException e) {throw new RSAException("RSA签名出现错误,算法异常:" + e.getMessage());}return signature;}/*** RSA 验签** @param data 原始数据* @param publicKey 公钥* @param signature 签名* @return 验签结果* @throws RSAException 如果验签过程中出现异常*/public static boolean verify(String data, String publicKey, String signature) throws RSAException {// 16进制密钥还原publicKey = HexUtil.decode(publicKey);byte[] publicKeyByte = Base64.getMimeDecoder().decode(publicKey);X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(publicKeyByte);boolean isVerify = false;try {KeyFactory keyFactory = KeyFactory.getInstance("RSA");PublicKey publicKeyObj = keyFactory.generatePublic(x509EncodedKeySpec);Signature signer = Signature.getInstance("SHA256withRSA");signer.initVerify(publicKeyObj);signer.update(data.getBytes());// 签名还原signature = HexUtil.decode(signature);byte[] decodedSignature = Base64.getMimeDecoder().decode(signature);isVerify = signer.verify(decodedSignature);} catch (NoSuchAlgorithmException | InvalidKeySpecException | InvalidKeyException | SignatureException e) {throw new RSAException("RSA验签出现错误,算法异常:" + e.getMessage());}return isVerify;}
}

RequestBodyAdvice 介绍

用于在请求体被反序列化之前对其进行处理,典型场景是解密请求体。用于拦截请求体(Request Body)的处理,在请求体被反序列化为 Java 对象之前对其进行处理。这个接口允许开发者在请求进入控制器之前做一些预处理,比如解密或格式转换等。

RequestBodyAdvice 接口提供了 5 个方法,具体如下:

  1. boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType)
    用于判断当前请求是否需要处理,返回 true 表示该请求体需要进行处理。你可以根据 methodParameter、targetType 或 converterType 来做特定的控制。

  2. Object handleBodyBeforeRead(MethodParameter methodParameter, Type targetType, HttpInputMessage inputMessage, Class<? extends HttpMessageConverter<?>> converterType) throws IOException
    在请求体反序列化之前调用,可以对请求体进行解密、转换或者其他处理。返回值将是处理后的请求体内容,或者可以直接读取 inputMessage 数据并进行修改。

  3. Object handleBodyAfterRead(Object body, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType, HttpInputMessage inputMessage)
    请求体被成功反序列化后调用。在此方法中你可以进一步处理数据,比如验证或转换成其他格式。

  4. boolean handleBodyAfterWrite(Object body, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType, HttpOutputMessage outputMessage) throws IOException
    在响应体被序列化后调用,允许你对响应体进行最后的修改,比如加密、转换等。返回值决定了是否继续执行后续处理。

  5. boolean handleBodyBeforeWrite(Object body, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType, HttpOutputMessage outputMessage) throws IOException
    在响应体被写入前调用。你可以在这里对响应体数据进行修改、加密等处理。

使用场景

解密请求体: 在请求到达控制器之前,你可能需要对请求体进行解密操作(例如,使用某种加密算法加密请求体数据)。

日志记录: 记录请求的请求体内容,或者修改请求体中的数据。

格式转换: 例如,将请求体从 JSON 转换成 XML,或者做其他格式的处理。

ResponseBodyAdvice 介绍

用于在响应体被序列化并发送之前对其进行处理,典型场景是加密响应体。当控制器方法执行完毕并返回数据后,Spring 会通过 ResponseBodyAdvice 对响应体进行处理。它可以用于对响应数据进行加密、修改、过滤等操作。

ResponseBodyAdvice 接口提供了 2 个方法,具体如下:

  1. boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType)
    用于判断是否对当前的响应体执行处理。你可以根据返回类型、converterType 等条件判断是否处理。
  2. Object handleBodyBeforeWrite(Object body, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType, HttpOutputMessage outputMessage) throws IOException
    在响应体被序列化并写入 HTTP 响应之前调用。你可以在这里对响应体进行加密或修改等操作。

使用场景

加密响应体: 例如,在返回给客户端的数据需要加密时,你可以在 ResponseBodyAdvice 中对响应体进行加密。

日志记录: 记录响应体内容,或者根据需要修改返回的数据。

修改响应体格式: 可以根据需要改变响应的格式,比如将返回的 JSON 数据转换成其他格式。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FlyHttp 的设计思想:前端 API 自动化构建工具

FlyHttp的相关文章&#xff1a; FlyHttp 的诞生&#xff1a;从认识各种网络请求开始 FlyHttp 的设计思想&#xff1a;前端 API 自动化构建工具 FlyHttp 的使用&#xff1a;如何高效使用 FlyHttp&#xff0c;支持 JS、TS 项目 FlyHttp 的最佳实践&#xff1a;加速项目级 API…

在CentOS上无Parallel时并发上传.wav文件的Shell脚本解决方案

在CentOS上无Parallel时并发上传.wav文件的Shell脚本解决方案 背景概述解决方案脚本实现脚本说明使用指南注意事项在CentOS操作系统环境中,若需并发上传特定目录下的.wav文件至HTTP服务器,而系统未安装GNU parallel工具,我们可通过其他方法实现此需求。本文将介绍一种利用Sh…

springboot整合flowable工作流

1、工作流介绍 1.Flowable起源于Activiti工作流引擎&#xff0c;由Activiti的主要开发者在2016年创建。它继承了Activiti的众多优点&#xff0c;并在此基础上进行了优化和改进&#xff0c;以提供更加稳定、高效的工作流管理解决方案。Flowable与Activiti有着共同的祖先&#x…

Linux Shell 脚本题目集(2)

1、使用 case 语句根据用户输入的分数&#xff08;0-100&#xff09;输出相应的成绩等级&#xff08;A, B, C, D&#xff09;。 #! /bin/bashread -p "请输入您的分数&#xff08;0-100&#xff09;&#xff1a;" score# 验证输入是否为数字且在0到100之间 if ! [[ …

交换机四大镜像(端口镜像、流镜像、VLAN镜像、MAC镜像)应用场景、配置实例及区别对比

在网络管理中&#xff0c;端口镜像、流镜像、VLAN镜像和MAC镜像都是用于监控和分析网络流量的重要技术。 端口镜像&#xff08;Port Mirroring&#xff09; 定义&#xff1a;端口镜像是将一个或多个源端口的流量复制到一个目标端口&#xff0c;以便于网络管理员能够监控和分析…

Redis(1)

Redis是一个在内存中存储数据的中间件。 1.在内存中存储数据。 通过数据结构来存储&#xff0c;mysql通过表的方式存储数据&#xff0c;是关系型数据库&#xff0c;redis通过键值对存储&#xff0c;key的类型是string&#xff0c;value的类型是非关系型数据库。 2.可编程的 …

基于Pyside6开发一个通用的在线升级工具

UI main.ui <?xml version"1.0" encoding"UTF-8"?> <ui version"4.0"><class>MainWindow</class><widget class"QMainWindow" name"MainWindow"><property name"geometry"&…

Linux 系统/etc目录下配置文件分类

目录 一、网络相关配置文件 主机名与 IP 映射类 /etc/hosts /etc/hostname 网络接口配置类 /etc/sysconfig/network-scripts/ifcfg-ens33 DNS 相关类 /etc/resolv.conf /etc/host.conf 网络服务相关类 /etc/hosts.allow文件 /etc/hosts.deny文件 /etc/netconfig …

自由学习记录(28)

C# 中的流&#xff08;Stream&#xff09; 流&#xff08;Stream&#xff09;是用于读取和写入数据的抽象基类。 流表示从数据源读取或向数据源写入数据的矢量过程。 C# 中的流类是从 System.IO.Stream 基类派生的&#xff0c;提供了多种具体实现&#xff0c;每种实现都针对…

Redis3——线程模型与数据结构

Redis3——线程模型与数据结构 本文讲述了redis的单线程模型和IO多线程工作原理&#xff0c;以及几个主要数据结构的实现。 1. Redis的单线程模型 redis6.0之前&#xff0c;一个redis进程只有一个io线程&#xff0c;通过reactor模式可以连接大量客户端&#xff1b;redis6.0为了…

Elasticsearch Serverless 现已正式发布

作者&#xff1a;来自 Elastic Yaru Lin 基于全新无状态&#xff08;stateless&#xff09;架构的 Elasticsearch Serverless 现已正式发布。它采用完全托管方式&#xff0c;因此你可以快速启动项目而无需操作或升级&#xff0c;并且可以使用最新的向量搜索和生成式 AI 功能。 …

Android CoordinatorLayout:打造高效交互界面的利器

目录 一、CoordinatorLayout 介绍及特点 二、使用方法 2.1 创建 CoordinatorLayout 布局 2.2 添加需要协调的子视图 2.3 自定义 Behavior 三、结语 相关推荐 在Android开发中&#xff0c;面对复杂多变的用户界面需求&#xff0c;CoordinatorLayout以其强大的交互管理能力…

基于Java Springboot旅游攻略APP且微信小程序

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 微信…

多模态大语言模型的对比

简介 文章主要对比了包括 VideoLLaMA 2 、CogVLM2-video 、MiniCPM-V等模型 目前主流的多模态视觉问答大模型&#xff0c;大部分采用视觉编码器、大语言模型、图像到文本特征的投影模块 目录 简介1. VideoLLaMA 21.1 网络结构1.2 STC connector具体的架构 2. MiniCPM-V 2.62.…

Android渗透环境配置教程

工具 模拟器 ADB brew install android-platform-tools set import cert # cer 证书转为 pem 证书 openssl x509 -inform DER -in cacert.der -out cacert.pem# 获取证书的 hash 值 hash$(openssl x509 -inform PEM -subject_hash_old -in cacert.pem | head -n 1)# 将 pem…

Microi吾码|.NET、VUE快速搭建项目,低代码便捷开发教程

Microi吾码&#xff5c;VUE快速搭建项目&#xff0c;低代码便捷开发教程 一、摘要二、Microi吾码介绍2.1 功能介绍2.2 团队介绍2.3 上线项目案例 三、VUE中使用Microi吾码3.1 前期了解3.2 创建第一个低代码应用3.3 接口API使用说明3.4 引擎界面可视化配置&#xff0c;生成API3.…

常见Linux命令(详解)

文章目录 常见Linux命令文件目录类命令pwd 打印当前目录的绝对路径ls 列出目录内容cd 切换路径mkdir 建立目录rmdir 删除目录touch 创建空文件cp 复制文件或目录rm 移除文件或者目录mv 移动文件与目录或重命名cat 查看文件内容more 文件分屏查看器less 分屏显示文件内容head 显…

AI - 如何构建一个大模型中的Tool

AI - 如何构建一个大模型中的Tool 大家好&#xff01;今天我们聊聊一个有趣的技术问题&#xff1a;什么是工具&#xff08;Tool&#xff09;&#xff0c;如何使用聊天模型调用工具&#xff0c;以及如何将工具的输出传递给聊天模型。我们还是基于LangChain来进行讨论&#xff0…

【测试工具JMeter篇】JMeter性能测试入门级教程(四):JMeter中BeanShell内置方法使用

一、什么是BeanShell BeanShell是一种完全符合Java语法规范的脚本语言,并且又拥有自己的一些语法和方法;BeanShell是一种松散类型的脚本语言(这点和JS类似);BeanShell是用Java写成的,一个小型的、免费的、可以下载的、嵌入式的Java源代码解释器,具有对象脚本语言特性,非常精简…

MyBatis异常体系中ErrorContext和ExceptionFactory原理分析

&#x1f3ae; 作者主页&#xff1a;点击 &#x1f381; 完整专栏和代码&#xff1a;点击 &#x1f3e1; 博客主页&#xff1a;点击 文章目录 exceptions包分包设计ExceptionFactory类介绍为什么使用工厂不是直接new呢&#xff1f;【统一的异常处理机制】【异常的封装与转化】【…