Java:SpringBoot使用AES对JSON数据加密和解密
目录
- 1、加密解密原理
- 2、项目示例
- 2.1、项目结构
- 2.2、常规业务代码
- 2.3、加密的实现
- 2.4、接口测试
- 2.5、总结
1、加密解密原理
客户端和服务端都可以加密和解密,使用base64进行网络传输
加密方
字符串 -> AES加密 -> base64
解密方
base64 -> AES解密 -> 字符串
2、项目示例
2.1、项目结构
$ tree -I target -I test
.
├── pom.xml
└── src└── main├── java│ └── com│ └── example│ └── demo│ ├── Application.java│ ├── annotation│ │ └── SecretData.java│ ├── config│ │ ├── CrossConfig.java│ │ ├── DecryptRequestBodyAdvice.java│ │ ├── EncryptResponseBodyAdvice.java│ │ ├── SecretConfig.java│ │ └── WebMvcConfig.java│ ├── controller│ │ ├── IndexController.java│ │ └── UserController.java│ ├── request│ │ └── JsonRequest.java│ ├── response│ │ ├── JsonResult.java│ │ └── JsonResultVO.java│ ├── service│ │ ├── SecretDataService.java│ │ └── impl│ │ └── SecretDataServiceImpl.java│ └── utils│ └── CipherUtil.java└── resources├── application.yml├── static│ ├── axios.min.js│ └── crypto-js.min.js└── templates└── index.html
2.2、常规业务代码
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.7</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>demo</artifactId><version>0.0.1-SNAPSHOT</version><name>demo</name><description>Demo project for Spring Boot</description><properties><java.version>1.8</java.version><mybatis-plus.version>3.5.2</mybatis-plus.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.15</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-devtools</artifactId><scope>runtime</scope><optional>true</optional></dependency><!-- test --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>
Application.java
package com.example.demo;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
WebMvcConfig.java
package com.example.demo.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {// 设置静态资源映射@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");}
}
CrossConfig.java
package com.example.demo.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;/*** 处理跨域问题*/
@Configuration
public class CrossConfig {@Beanpublic CorsFilter corsFilter() {CorsConfiguration config = new CorsConfiguration();config.addAllowedOrigin("*");config.setAllowCredentials(false);config.addAllowedMethod("*");config.addAllowedHeader("*");config.setMaxAge(3600L);UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**", config);return new CorsFilter(configSource);}
}
JsonRequest.java
package com.example.demo.request;import lombok.Data;/*** 统一的请求体数据*/
@Data
public class JsonRequest {/*** 未加密数据*/private Object data;/*** 加密数据*/private String encryptData;
}
JsonResult.java
package com.example.demo.response;import lombok.Data;/*** 统一的返回体数据 不加密*/
@Data
public class JsonResult<T> {private String message;private T data;private Integer code;public static <T> JsonResult success(T data){JsonResult<T> jsonResult = new JsonResult<>();jsonResult.setCode(0);jsonResult.setData(data);jsonResult.setMessage("success");return jsonResult;}
}
JsonResultVO.java
package com.example.demo.response;import lombok.Data;/*** 统一的返回体数据 加密*/
@Data
public class JsonResultVO {private String message;private String encryptData;private Integer code;
}
IndexController.java
package com.example.demo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;@Controller
public class IndexController {@GetMapping("/")public String index(){return "index";}
}
UserController.java
package com.example.demo.controller;import com.example.demo.annotation.SecretData;
import com.example.demo.response.JsonResult;
import org.springframework.web.bind.annotation.*;import java.util.HashMap;
import java.util.Map;/*** 对该Controller中的所有方法进行加解密处理*/
@RestController
@SecretData
public class UserController {@GetMapping("/user/getUser")public JsonResult getUser() {Map<String, String> user = new HashMap<>();user.put("name", "Tom");user.put("age", "18");return JsonResult.success(user);}@PostMapping("/user/addUser")public Object addUser(@RequestBody Map<String, String> data) {System.out.println(data);return data;}
}
2.3、加密的实现
application.yml
secret:key: 1234567890123456 # 密钥位数为16位enabled: true # 开启加解密功能
SecretData.java
package com.example.demo.annotation;import org.springframework.web.bind.annotation.Mapping;import java.lang.annotation.*;/*** 只有添加有该注解的Controller类或是具体接口方法才进行数据的加密解密*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Mapping
@Documented
public @interface SecretData {}
DecryptRequestBodyAdvice.java
package com.example.demo.config;import com.example.demo.annotation.SecretData;
import com.example.demo.request.JsonRequest;
import com.example.demo.service.SecretDataService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdviceAdapter;import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;/*** 对请求内容进行解密* 只有开启了加解密功能才会生效* 仅对使用了@RqestBody注解的生效* https://blog.csdn.net/xingbaozhen1210/article/details/98189562*/
@ControllerAdvice
// @ConditionalOnProperty(name = "secret.enabled", havingValue = "true")
public class DecryptRequestBodyAdvice extends RequestBodyAdviceAdapter {@Resourceprivate SecretDataService secretDataService;@Overridepublic boolean supports(MethodParameter methodParameter, Type targetType,Class<? extends HttpMessageConverter<?>> converterType) {return methodParameter.getMethod().isAnnotationPresent(SecretData.class)|| methodParameter.getMethod().getDeclaringClass().isAnnotationPresent(SecretData.class);}@Overridepublic HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter, Type targetType,Class<? extends HttpMessageConverter<?>> converterType) throws IOException {System.out.println("beforeBodyRead");String body = inToString(inputMessage.getBody());System.out.println(body);ObjectMapper objectMapper = new ObjectMapper();JsonRequest jsonRequest = objectMapper.readValue(body, JsonRequest.class);// 默认取data数据,如果提交加密数据则解密String decryptData = null;if (jsonRequest.getEncryptData() != null) {decryptData = secretDataService.decrypt(jsonRequest.getEncryptData());} else{decryptData = objectMapper.writeValueAsString(jsonRequest.getData());}String data = decryptData;// 解密后的数据System.out.println(data);return new HttpInputMessage() {@Overridepublic HttpHeaders getHeaders() {return inputMessage.getHeaders();}@Overridepublic InputStream getBody() throws IOException {return new ByteArrayInputStream(data.getBytes());}};}/*** 读取输入流为字符串** @param is* @return*/private String inToString(InputStream is) {byte[] buf = new byte[10 * 1024];int length = -1;StringBuilder sb = new StringBuilder();try {while ((length = is.read(buf)) != -1) {sb.append(new String(buf, 0, length));}return sb.toString();} catch (IOException e) {throw new RuntimeException(e);}}}
EncryptResponseBodyAdvice.java
package com.example.demo.config;import com.example.demo.annotation.SecretData;
import com.example.demo.response.JsonResult;
import com.example.demo.response.JsonResultVO;
import com.example.demo.service.SecretDataService;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.MethodParameter;
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.ResponseBodyAdvice;import javax.annotation.Resource;/*** 对响应内容加密*/
@ControllerAdvice
@ConditionalOnProperty(name = "secret.enabled", havingValue = "true")
public class EncryptResponseBodyAdvice implements ResponseBodyAdvice<Object> {@Resourceprivate SecretDataService secretDataService;@Overridepublic boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {return returnType.getMethod().isAnnotationPresent(SecretData.class)|| returnType.getMethod().getDeclaringClass().isAnnotationPresent(SecretData.class);}@SneakyThrows@Overridepublic Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,Class<? extends HttpMessageConverter<?>> selectedConverterType,ServerHttpRequest request, ServerHttpResponse response) {System.out.println("beforeBodyWrite");// 仅对JsonResult对象数据加密if (body instanceof JsonResult) {JsonResult jsonResult = (JsonResult) body;JsonResultVO jsonResultVO = new JsonResultVO();BeanUtils.copyProperties(jsonResult, jsonResultVO);String jsonStr = new ObjectMapper().writeValueAsString(jsonResult.getData());jsonResultVO.setEncryptData(secretDataService.encrypt(jsonStr));return jsonResultVO;} else {return body;}}
}
SecretConfig.java
package com.example.demo.config;import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;@Configuration
@ConfigurationProperties(prefix = "secret")
public class SecretConfig {private Boolean enabled;private String key;public Boolean getEnabled() {return enabled;}public void setEnabled(Boolean enabled) {this.enabled = enabled;}public String getKey() {return key;}public void setKey(String key) {this.key = key;}}
SecretDataService.java
package com.example.demo.service;/*** 加密解密的接口*/
public interface SecretDataService {/*** 数据加密** @param data 待加密数据* @return String 加密结果*/String encrypt(String data);/*** 数据解密** @param data 待解密数据* @return String 解密后的数据*/String decrypt(String data);
}
SecretDataServiceImpl.java
package com.example.demo.service.impl;import com.example.demo.config.SecretConfig;
import com.example.demo.service.SecretDataService;
import com.example.demo.utils.CipherUtil;
import org.springframework.stereotype.Service;import javax.annotation.Resource;/*** 具体的加解密实现*/
@Service
public class SecretDataServiceImpl implements SecretDataService {@Resourceprivate SecretConfig secretConfig;@Overridepublic String decrypt(String data) {return CipherUtil.decrypt(secretConfig.getKey(), data);}@Overridepublic String encrypt(String data) {return CipherUtil.encrypt(secretConfig.getKey(), data);}
}
CipherUtil.java
package com.example.demo.utils;import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.util.Base64;/*** 数据加密解密工具类* 加密后返回base64*/
public class CipherUtil {/*** 定义加密算法*/private static final String ALGORITHM = "AES/ECB/PKCS5Padding";/*** 解密** @param secretKey* @param cipherText base64* @return*/public static String decrypt(String secretKey, String cipherText) {// 将Base64编码的密文解码byte[] encrypted = Base64.getDecoder().decode(cipherText);try {Cipher cipher = Cipher.getInstance(ALGORITHM);SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "AES");cipher.init(Cipher.DECRYPT_MODE, key);return new String(cipher.doFinal(encrypted));} catch (Exception e) {throw new RuntimeException(e);}}/*** 加密** @param secretKey* @param plainText base64* @return*/public static String encrypt(String secretKey, String plainText) {try {Cipher cipher = Cipher.getInstance(ALGORITHM);SecretKeySpec key = new SecretKeySpec(secretKey.getBytes(), "AES");cipher.init(Cipher.ENCRYPT_MODE, key);return Base64.getEncoder().encodeToString(cipher.doFinal(plainText.getBytes(Charset.forName("UTF-8"))));} catch (Exception e) {throw new RuntimeException(e);}}
}
浏览器中实现加密解密
templates/index.html
<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8" /><title>接口数据加密解密</title></head><body><!-- 引入依赖 --><!-- <script src="https://cdn.bootcdn.net/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script> --><script src="/static/crypto-js.min.js"></script><!-- <script src="https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js"></script> --><script src="/static/axios.min.js"></script><h1>查看控制台</h1><!-- 加密解密模块 --><script type="text/javascript">const SECRET_KEY = "1234567890123456";/*** 加密方法* @param data 待加密数据* @returns {string|*}*/function encrypt(data) {let key = CryptoJS.enc.Utf8.parse(SECRET_KEY);if (typeof data === "object") {data = JSON.stringify(data);}let plainText = CryptoJS.enc.Utf8.parse(data);let secretText = CryptoJS.AES.encrypt(plainText, key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7}).toString();return secretText;}/*** 解密数据* @param data 待解密数据*/function decrypt(data) {let key = CryptoJS.enc.Utf8.parse(SECRET_KEY);let result = CryptoJS.AES.decrypt(data, key, {mode: CryptoJS.mode.ECB,padding: CryptoJS.pad.Pkcs7}).toString(CryptoJS.enc.Utf8);return JSON.parse(result);}</script><!-- http请求模块 --><script type="text/javascript">// 获取加密数据并解密axios.get("http://127.0.0.1:8080/user/getUser").then((res) => {console.log("接收到api返回加密数据:");console.log(decrypt(res.data.encryptData));});// 提交加密参数const data = {name: "Tom",age: "18",};axios.post("http://127.0.0.1:8080/user/addUser", {encryptData: encrypt(data),}).then((res) => {console.log("接收到api返回未加密数据:");console.log(res.data);});</script></body>
</html>
2.4、接口测试
- 开发环境不加密更易于开发调试
- 生产环境需要数据加密
前后端都可以通过参数 encryptData
判断对方提交/返回的数据是否为加密数据,如果是加密数据则进行解密操作
接口返回加密数据
GET http://127.0.0.1:8080/user/getUser
未加密的数据
{"message": "success","data": {"name": "Tom","age": "18"},"code": 0
}
返回数据
{"message": "success","encryptData": "kun2Wvk2LNKICaXIeIExA7jKRyqOV0qCv5KQXFOzfpQ=","code": 0
}
客户端提交参数
POST http://127.0.0.1:8080/user/addUser
提交数据
{"data": {"name": "Tom","age": "18"}
}
提交加密数据
{"encryptData": "kun2Wvk2LNKICaXIeIExA7jKRyqOV0qCv5KQXFOzfpQ="
}
2.5、总结
服务端
- 全局开关:通过控制
secret.enabled=true
全局开启返回数据加密 - 全局局部:可以通过
SecretData
或者自定义PassSecretData
来控制单个控制器或者单个接口的需要或不需要加密
客户端
- 可以根据开发环境、测试环境、生产环境来控制是否开启加密
- 需要注意,FormData传输文件的数据格式可以考虑不加密
相同点
- 服务端和客户端都通过对方传输的
encryptData
来判断是否为加密数据 - 服务端和客户端都可以根据自己的环境来决定是否开启数据加密
完整代码:https://github.com/mouday/spring-boot-demo/tree/master/SpringBoot-Secret
参考文章
- 详解API接口如何安全的传输数据
相关文章:
Java:SpringBoot使用AES对JSON数据加密和解密
目录 1、加密解密原理2、项目示例2.1、项目结构2.2、常规业务代码2.3、加密的实现 2.4、接口测试2.5、总结 1、加密解密原理 客户端和服务端都可以加密和解密,使用base64进行网络传输 加密方 字符串 -> AES加密 -> base64解密方 base64 -> AES解密 -&g…...
【PHP】Swoole:一款强大的PHP网络编程工具
在科学计算领域,Swoole是一款功能强大的PHP扩展,它提供了高性能的网络通信和异步编程功能。Swoole不仅支持TCP、UDP、Unix Socket和HTTP等通信协议,还具有异步并发处理能力,使得PHP开发者能够轻松地构建高性能的网络应用程序。 1…...

【C语言】每日一题(除自身以外数组的乘积)
添加链接描述,链接奉上 方法: 暴力循环:前缀积后缀积(分组): 暴力循环: 暴力循换真的是差生法宝,简单好懂,就是不实用,大多数的题目都会超过时间限制(无奈) 思路&…...

C语言每日一练-----Day(4)
本专栏为c语言练习专栏,适合刚刚学完c语言的初学者。本专栏每天会不定时更新,通过每天练习,进一步对c语言的重难点知识进行更深入的学习。 今日练习题关键字:记负均正 旋转数组的最小数字 二分查找 💓博主…...

如何使用工具将批量查询的物流信息导出到表格
现如今,物流行业发展迅速,人们对于物流信息的查询需求也越来越高。为了满足用户的需求,我们推荐一款便捷高效的物流信息查询工具——"固乔快递查询助手"软件。 首先,用户需要下载并安装"固乔快递查询助手"软件…...

Haproxy+Keepalive 整合rabbitmq实现高可用负载均衡
Haproxy 实现负载均衡 HAProxy 提供高可用性、负载均衡及基于 TCPHTTP 应用的代理,支持虚拟主机,它是免费、快速并且可靠的一种解决方案,包括 Twitter,Reddit,StackOverflow,GitHub 在内的多家知名互联网公司在使用。HAProxy 实现了一种…...
电子病历系统的核心技术——电子病历编辑器
一体化电子病历系统基于云端SaaS服务的方式,采用B/S(Browser/Server)架构提供,覆盖了医疗机构电子病历模板制作到管理使用的整个流程。除实现在线制作内容丰富、图文并茂、功能完善的电子病历模板外,还可按照医疗机构的…...

C++------map和set的使用
文章目录 关联式容器键值对树型结构的关联式容器set的介绍map的介绍 关联式容器 什么是关联式容器?它与序列式容器有什么区别? 关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key,value>结…...

URI和URL和URN区别
URI、URL 和 URN 是一系列从不同角度来看待资源标识和定位的概念。虽然它们有一些重叠,但每个概念都强调了不同的方面。 URI(Uniform Resource Identifier):URI 是一个通用的术语,用于标识和定位资源。它是一个抽象的概…...

【Unity学习笔记】DOTween(1)基础介绍
本文中大部分内容学习来自DOTween官方文档 文章目录 什么是DOTween?DOSetOnTweenerSequenceTweenNested tween 初始化使用方式 什么是DOTween? DOTween是一个动画插件,Tween是补间的意思。这个插件以下简称DOT,DOT很方便使用&…...
springboot项目,使用JNA框架调用C++库无法捕获异常的解决思路
写在前面:这个东西真的坑,工作上遇到的和JNA项目的入门案例差别就像是二重积分与小学数学之间的差距,折磨! 使用 JNA(Java Native Access)框架调用 C 库时,如果出现问题导致进程直接结束而无法捕…...

【项目 计网7】4.20 多进程实现并发服务器 4.22 多线程实现并发服务器
文章目录 4.20 多进程实现并发服务器server_process.cclient.c4.22 多线程实现并发服务器客户端代码:服务端代码: 4.20 多进程实现并发服务器 要实现TCP通信服务器处理并发的任务,使用多线程或者多进程来解决。 思路: 1、一个父进…...

论文阅读_扩散模型_LDM
英文名称: High-Resolution Image Synthesis with Latent Diffusion Models 中文名称: 使用潜空间扩散模型合成高分辨率图像 地址: https://ieeexplore.ieee.org/document/9878449/ 代码: https://github.com/CompVis/latent-diffusion 作者:Robin Rombach 日期: 20…...
LeetCode——回溯篇(二)
刷题顺序及思路来源于代码随想录,网站地址:https://programmercarl.com 目录 131. 分割回文串 93. 复原 IP 地址 78. 子集 90. 子集 II 491. 递增子序列 131. 分割回文串 给你一个字符串 s,请你将 s 分割成一些子串,使每个…...

RabbitMQ工作模式-发布订阅模式
Publish/Subscribe(发布订阅模式) 官方文档: https://www.rabbitmq.com/tutorials/tutorial-three-python.html 使用fanout类型类型的交换器,routingKey忽略。每个消费者定义生成一个队列关绑定到同一个Exchange,每个…...

JDK源码解析-Object
1. Object类 所有类的基类——java.lang.Object Object 类是所有类的基类,当一个类没有直接继承某个类时,默认继承Object类Object 类属于 java.lang 包,此包下的所有类在使用时无需手动导入,系统会在程序编译期间自动导入。 思…...

pinia——添加插件——基础积累
问题:是否给pinia添加过插件?具体添加的方式是什么? 在pinia中,我们可以为仓库添加插件,通过添加插件能够扩展以下的内容: 为 store 添加新的属性 定义 store 时增加新的选项 为 store 增加新的方法 包装现…...
软件国产化之殇
今天又看到这么一个帖子讨论一款国产化软件,属实给我震撼到了。 对于国产化产品,一直主打的都是”自研“,难道是我对”自研“这个词的理解有误? 做一个产品,别人开源了,你拿过来使用,你可以说…...
SQLyog问题处理集合
sqlyog 问题处理 1. 错误号码:1049错误: 数据库命令参数参考:数据库命令地址 检查数据库是否存在检查创建的数据库名称 与 要进行连接的数据库名称是否一致; 2. 错误号码:1819错误: MySQL授予远程连接权限时出现: …...

JavaSE【继承和多态】(1)(重点:初始化、pretected封装、组合)
一、继承 继承 (inheritance) 机制 :是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性 的基础上进行扩展,增加新功能 ,这样产生新的类,称 派生类 。 继承呈现了面向对象程序设计的层次结…...

使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...