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

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、加密解密原理 客户端和服务端都可以加密和解密&#xff0c;使用base64进行网络传输 加密方 字符串 -> AES加密 -> base64解密方 base64 -> AES解密 -&g…...

【PHP】Swoole:一款强大的PHP网络编程工具

在科学计算领域&#xff0c;Swoole是一款功能强大的PHP扩展&#xff0c;它提供了高性能的网络通信和异步编程功能。Swoole不仅支持TCP、UDP、Unix Socket和HTTP等通信协议&#xff0c;还具有异步并发处理能力&#xff0c;使得PHP开发者能够轻松地构建高性能的网络应用程序。 1…...

【C语言】每日一题(除自身以外数组的乘积)

添加链接描述&#xff0c;链接奉上 方法&#xff1a; 暴力循环:前缀积后缀积&#xff08;分组&#xff09;: 暴力循环: 暴力循换真的是差生法宝&#xff0c;简单好懂&#xff0c;就是不实用&#xff0c;大多数的题目都会超过时间限制&#xff08;无奈&#xff09; 思路&…...

C语言每日一练-----Day(4)

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

如何使用工具将批量查询的物流信息导出到表格

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

Haproxy+Keepalive 整合rabbitmq实现高可用负载均衡

Haproxy 实现负载均衡 HAProxy 提供高可用性、负载均衡及基于 TCPHTTP 应用的代理&#xff0c;支持虚拟主机&#xff0c;它是免费、快速并且可靠的一种解决方案&#xff0c;包括 Twitter,Reddit,StackOverflow,GitHub 在内的多家知名互联网公司在使用。HAProxy 实现了一种…...

电子病历系统的核心技术——电子病历编辑器

一体化电子病历系统基于云端SaaS服务的方式&#xff0c;采用B/S&#xff08;Browser/Server&#xff09;架构提供&#xff0c;覆盖了医疗机构电子病历模板制作到管理使用的整个流程。除实现在线制作内容丰富、图文并茂、功能完善的电子病历模板外&#xff0c;还可按照医疗机构的…...

C++------map和set的使用

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

URI和URL和URN区别

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

【Unity学习笔记】DOTween(1)基础介绍

本文中大部分内容学习来自DOTween官方文档 文章目录 什么是DOTween&#xff1f;DOSetOnTweenerSequenceTweenNested tween 初始化使用方式 什么是DOTween&#xff1f; DOTween是一个动画插件&#xff0c;Tween是补间的意思。这个插件以下简称DOT&#xff0c;DOT很方便使用&…...

springboot项目,使用JNA框架调用C++库无法捕获异常的解决思路

写在前面&#xff1a;这个东西真的坑&#xff0c;工作上遇到的和JNA项目的入门案例差别就像是二重积分与小学数学之间的差距&#xff0c;折磨&#xff01; 使用 JNA&#xff08;Java Native Access&#xff09;框架调用 C 库时&#xff0c;如果出现问题导致进程直接结束而无法捕…...

【项目 计网7】4.20 多进程实现并发服务器 4.22 多线程实现并发服务器

文章目录 4.20 多进程实现并发服务器server_process.cclient.c4.22 多线程实现并发服务器客户端代码&#xff1a;服务端代码&#xff1a; 4.20 多进程实现并发服务器 要实现TCP通信服务器处理并发的任务&#xff0c;使用多线程或者多进程来解决。 思路&#xff1a; 1、一个父进…...

论文阅读_扩散模型_LDM

英文名称: High-Resolution Image Synthesis with Latent Diffusion Models 中文名称: 使用潜空间扩散模型合成高分辨率图像 地址: https://ieeexplore.ieee.org/document/9878449/ 代码: https://github.com/CompVis/latent-diffusion 作者&#xff1a;Robin Rombach 日期: 20…...

LeetCode——回溯篇(二)

刷题顺序及思路来源于代码随想录&#xff0c;网站地址&#xff1a;https://programmercarl.com 目录 131. 分割回文串 93. 复原 IP 地址 78. 子集 90. 子集 II 491. 递增子序列 131. 分割回文串 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个…...

RabbitMQ工作模式-发布订阅模式

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

JDK源码解析-Object

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

pinia——添加插件——基础积累

问题&#xff1a;是否给pinia添加过插件&#xff1f;具体添加的方式是什么&#xff1f; 在pinia中&#xff0c;我们可以为仓库添加插件&#xff0c;通过添加插件能够扩展以下的内容&#xff1a; 为 store 添加新的属性 定义 store 时增加新的选项 为 store 增加新的方法 包装现…...

软件国产化之殇

今天又看到这么一个帖子讨论一款国产化软件&#xff0c;属实给我震撼到了。 对于国产化产品&#xff0c;一直主打的都是”自研“&#xff0c;难道是我对”自研“这个词的理解有误&#xff1f; 做一个产品&#xff0c;别人开源了&#xff0c;你拿过来使用&#xff0c;你可以说…...

SQLyog问题处理集合

sqlyog 问题处理 1. 错误号码:1049错误&#xff1a; 数据库命令参数参考&#xff1a;数据库命令地址 检查数据库是否存在检查创建的数据库名称 与 要进行连接的数据库名称是否一致&#xff1b; 2. 错误号码:1819错误&#xff1a; MySQL授予远程连接权限时出现&#xff1a; …...

JavaSE【继承和多态】(1)(重点:初始化、pretected封装、组合)

一、继承 继承 (inheritance) 机制 &#xff1a;是面向对象程序设计使代码可以复用的最重要的手段&#xff0c;它允许程序员在保持原有类特 性 的基础上进行扩展&#xff0c;增加新功能 &#xff0c;这样产生新的类&#xff0c;称 派生类 。 继承呈现了面向对象程序设计的层次结…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

抖音增长新引擎:品融电商,一站式全案代运营领跑者

抖音增长新引擎&#xff1a;品融电商&#xff0c;一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中&#xff0c;品牌如何破浪前行&#xff1f;自建团队成本高、效果难控&#xff1b;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...

MODBUS TCP转CANopen 技术赋能高效协同作业

在现代工业自动化领域&#xff0c;MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步&#xff0c;这两种通讯协议也正在被逐步融合&#xff0c;形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

Angular微前端架构:Module Federation + ngx-build-plus (Webpack)

以下是一个完整的 Angular 微前端示例&#xff0c;其中使用的是 Module Federation 和 npx-build-plus 实现了主应用&#xff08;Shell&#xff09;与子应用&#xff08;Remote&#xff09;的集成。 &#x1f6e0;️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...

Docker拉取MySQL后数据库连接失败的解决方案

在使用Docker部署MySQL时&#xff0c;拉取并启动容器后&#xff0c;有时可能会遇到数据库连接失败的问题。这种问题可能由多种原因导致&#xff0c;包括配置错误、网络设置问题、权限问题等。本文将分析可能的原因&#xff0c;并提供解决方案。 一、确认MySQL容器的运行状态 …...

jdbc查询mysql数据库时,出现id顺序错误的情况

我在repository中的查询语句如下所示&#xff0c;即传入一个List<intager>的数据&#xff0c;返回这些id的问题列表。但是由于数据库查询时ID列表的顺序与预期不一致&#xff0c;会导致返回的id是从小到大排列的&#xff0c;但我不希望这样。 Query("SELECT NEW com…...

海云安高敏捷信创白盒SCAP入选《中国网络安全细分领域产品名录》

近日&#xff0c;嘶吼安全产业研究院发布《中国网络安全细分领域产品名录》&#xff0c;海云安高敏捷信创白盒&#xff08;SCAP&#xff09;成功入选软件供应链安全领域产品名录。 在数字化转型加速的今天&#xff0c;网络安全已成为企业生存与发展的核心基石&#xff0c;为了解…...

HTTPS证书一年多少钱?

HTTPS证书作为保障网站数据传输安全的重要工具&#xff0c;成为众多网站运营者的必备选择。然而&#xff0c;面对市场上种类繁多的HTTPS证书&#xff0c;其一年费用究竟是多少&#xff0c;又受哪些因素影响呢&#xff1f; 首先&#xff0c;HTTPS证书通常在PinTrust这样的专业平…...

【QT控件】显示类控件

目录 一、Label 二、LCD Number 三、ProgressBar 四、Calendar Widget QT专栏&#xff1a;QT_uyeonashi的博客-CSDN博客 一、Label QLabel 可以用来显示文本和图片. 核心属性如下 代码示例: 显示不同格式的文本 1) 在界面上创建三个 QLabel 尺寸放大一些. objectName 分别…...