【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.mzph.cn/bicheng/63029.shtml

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

相关文章

消息中间件-Kafka2-3.9.0源码构建

消息中间件-Kafka2-3.9.0源码构建 1、软件环境 JDK Version 1.8Scala Version 2.12.0Kafka-3.9.0 源码包 下载地址&#xff1a;https://downloads.apache.org/kafka/3.9.0/kafka-3.9.0-src.tgzGradle Version > 8.8Apache Zookeeper 3.7.0 2、源码编译 打开源码根目录修改…

AMEYA360 | 杭晶电子:晶振在AR/VR中的应用

晶振在AR/VR设备中扮演重要角色&#xff0c;为其核心电子系统提供稳定的时钟信号&#xff0c;确保设备的高性能运行。 以下是晶振在AR/VR应用中的具体作用&#xff1a; 01、图像处理与同步 1、晶振为图形处理单元(GPU)和显示芯片提供精准的时钟信号&#xff0c;支持高速图像渲染…

【SARL】单智能体强化学习(Single-Agent Reinforcement Learning)《纲要》

&#x1f4e2;本篇文章是博主强化学习&#xff08;RL&#xff09;领域学习时&#xff0c;用于个人学习、研究或者欣赏使用&#xff0c;并基于博主对相关等领域的一些理解而记录的学习摘录和笔记&#xff0c;若有不当和侵权之处&#xff0c;指出后将会立即改正&#xff0c;还望谅…

Java刷题常见的集合类,各种函数的使用以及常见的类型转化等等

前言 相信大家在刷算法题的过程中&#xff0c;好不容易想出来大概的思路&#xff0c;也知道去用哪个集合类&#xff0c;但各个集合类的一些命令都长得太像&#xff0c;很容易将他们弄错&#xff0c;并且在各集合之间的转化也是特别烦人&#xff0c;还有很多实用的函数都知道可…

Linux CentOS

​阿里云开源镜像下载链接 https://mirrors.aliyun.com/centos/7/isos/x86_64/ VMware 安装 CentOS7 自定义 下一步 选择稍后安装操作系统 选择 输入 查看物理机CPU内核数量 CtrlShiftEsc 总数不超过物理机内核数量 推荐内存 自选 推荐 推荐 默认 拆分成多个 默认 自定义硬件…

大数据新视界 -- Hive 数据湖集成与数据治理(下)(26 / 30)

&#x1f496;&#x1f496;&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎你们来到 青云交的博客&#xff01;能与你们在此邂逅&#xff0c;我满心欢喜&#xff0c;深感无比荣幸。在这个瞬息万变的时代&#xff0c;我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

数据结构 (26)图的遍历

前言 数据结构中的图遍历是指从图中的任一顶点出发&#xff0c;按照某种方法访问图中的所有顶点&#xff0c;且每个顶点只访问一次。 一、遍历方法 遍历主要有两种方法&#xff1a;深度优先搜索&#xff08;DFS&#xff09;和广度优先搜索&#xff08;BFS&#xff09;。 1.深度…

B站狂神说Mybatis+Spring+SpringMVC整合理解(ssm框架整合)

文章目录 0.写在前面(对mybatis,spring的理解)&#xff08;不看可跳过&#xff09;0.1 为什么需要mybatis0.2 为什么需要spring0.3为什么需要springmvc 1.新建ssmbuild数据库2.新建Maven项目3.初始化步骤3.1 配置下载maven依赖&#xff0c;构建资源导出3.2 连接数据库3.3建包&a…

el-cascader 使用笔记

1.效果 2.官网 https://element.eleme.cn/#/zh-CN/component/cascader 3.动态加载&#xff08;官网&#xff09; <el-cascader :props"props"></el-cascader><script>let id 0;export default {data() {return {props: {lazy: true,lazyLoad (…

MySQL事件

1、在数据库d_eams中创建一个名为E_enent的事件&#xff0c;用于每隔10s向数据表T_event 中插入一条数据 use d_eams; create event E_event on schedule every 10 second on completion preserve do insert into T_event(用户, 创建时间) values(Root, now()); 2、查看当前…

C语言(分支结构)

问题引出 我们在程序设计往往会遇到如下的问题&#xff0c;比如下的函数的计算。 也就是我们是必须要通过一个条件的结果来选择下一步的操作&#xff0c;算法上属于一个分支结构&#xff0c;C语言中实现分支结构主要使用if语句。 条件判断 根据某个条件成立与否&#xff0c…

SpringAop(1)

Spring中有两大重心&#xff1a;springIoc和springAop springioc将bean的控制权交给了spring管理&#xff0c;直接从spring中获取&#xff0c;通过五大注解来告诉spring帮我管理这个对象。通过Autowired和构造方法和set方法注入。 不仅仅是学习重点也是面试常考的难点。 spr…

GoReplay开源工具使用教程

目录 一、GoReplay环境搭建 1、Mac、Linux安装GoReplay环境 二、GoReplay录制与重播 1、搭建练习接口 2、录制命令 3、重播命令 三、GoReplay单个命令 1、常用命令 2、其他命令 3、命令示例 4、性能测试 5、正则表达式 四、gorepaly组合命令 1、组合命令实例 2、…

Nginx:ssl

目录 部署ssl前提 nginx部署ssl证书 部署ssl部署建议 部署ssl前提 网站有域名根据域名申请到ssl证书&#xff0c;并下载证书部署到nginx中 部署了ssl证书后&#xff0c;访问的流量是加密的。 nginx部署ssl证书 #80端口跳转到443 server {listen 80;return 302 https://1…

USB 声卡全解析:提升音频体验的得力助手

在当今数字化的时代&#xff0c;音频领域的追求愈发多元。无论是热衷聆听高品质音乐的爱好者&#xff0c;还是在专业音频工作中精雕细琢的人士&#xff0c;亦或是在游戏世界里渴望极致音效沉浸的玩家&#xff0c;都始终在寻觅能让音频体验更上一层楼的妙法。而 USB 声卡&#x…

[TPAMI 2024]Vision-Language Models for Vision Tasks: A Survey

论文网址&#xff1a;Vision-Language Models for Vision Tasks: A Survey | IEEE Journals & Magazine | IEEE Xplore 论文Github页面&#xff1a;GitHub - jingyi0000/VLM_survey: Collection of AWESOME vision-language models for vision tasks 英文是纯手打的&…

深度学习模型:门控循环单元(GRU)详解

本文深入探讨了门控循环单元&#xff08;GRU&#xff09;&#xff0c;它是一种简化版的长短期记忆网络&#xff08;LSTM&#xff09;&#xff0c;在处理序列数据方面表现出色。文章详细介绍了 GRU 的基本原理、与 LSTM 的对比、在不同领域的应用以及相关的代码实现&#xff0c;…

HCIA笔记6--路由基础与静态路由:浮动路由、缺省路由、迭代查找

文章目录 0. 概念1.路由器工作原理2. 跨网访问流程3. 静态路由配置4. 静态路由的应用场景4.1 路由备份4.2 浮动路由4.3 缺省路由 5. 迭代路由6 问题6.1 为什么路由表中有的下一跳的地址有接口&#xff1f;6.2 个人电脑的网关本质是什么&#xff1f; 0. 概念 自治系统&#xff…

Spark常问面试题---项目总结

一、数据清洗&#xff0c;你都清洗什么&#xff1f;或者说 ETL 你是怎么做的&#xff1f; 我在这个项目主要清洗的式日志数据&#xff0c;日志数据传过来的json格式 去除掉无用的字段&#xff0c;过滤掉json格式不正确的脏数据 过滤清洗掉日志中缺少关键字段的数据&#xff…

【北京迅为】iTOP-4412全能版使用手册-第三十二章 网络通信-TCP套字节

iTOP-4412全能版采用四核Cortex-A9&#xff0c;主频为1.4GHz-1.6GHz&#xff0c;配备S5M8767 电源管理&#xff0c;集成USB HUB,选用高品质板对板连接器稳定可靠&#xff0c;大厂生产&#xff0c;做工精良。接口一应俱全&#xff0c;开发更简单,搭载全网通4G、支持WIFI、蓝牙、…