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

Java实现SM2前后端加解密

Sm2加解密原理,非对称加密,公钥加密,私钥解密。公私钥对成对生成,加密端解密端各自保存。用公钥加密必须要用对应的私钥才能解密,保证安全性。

这里我们实现的功能是前端加密,后端解密,这样前端暴露了公钥,后端持有配对的私钥,保证安全性。

1.jsp引入sm2

<script type="text/javascript" src="${pageContext.request.contextPath}/jslib/jquery-easyui-1.5.2/jquery.easyui.min.js" charset="utf-8"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/jslib/sm2/crypto-js.js" charset="utf-8"></script>
<script type="text/javascript" src="${pageContext.request.contextPath}/jslib/sm2/sm2.js" charset="utf-8"></script>

2.js加密

改写sm2.js,输入公钥

function sm2EncryptPwd(data) {var publicKey = '04XXXXXXXXXXXXXXXXXXXXXXXXXXXCB42F6044B1BA8640B42AE038252F3490F02029E37B91D6E0796DE0B3D67166CDD971E556EF1D6B54ED350031817DED6B0C40';return sm2Encrypt(data, publicKey, 1);}

公钥用后端的生成公私钥对方法生成,请勿使用文章提到的公私钥对。

例如login.js使用了加密,即

login.js,调用加密函数

var encryptedPwd = sm2EncryptPwd(pwd);

3.后端Java解密

引用依赖库 bcprov-jdk15on-1.68.jar

<dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk15on</artifactId><version>1.68</version></dependency>

login.java

私钥附上对应的值

pwd = new String(SM2Utils.decrypt(pwd, sm2PrivKey));

Sm2Utils.java

package com.sgsg.basic.encrypt.util;import org.bouncycastle.asn1.gm.GMNamedCurves;
import org.bouncycastle.asn1.x9.X9ECParameters;
import org.bouncycastle.crypto.CipherParameters;
import org.bouncycastle.crypto.engines.SM2Engine;
import org.bouncycastle.crypto.params.ECDomainParameters;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.crypto.params.ParametersWithRandom;
import org.bouncycastle.crypto.signers.SM2Signer;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPrivateKeySpec;
import org.bouncycastle.math.ec.ECPoint;
import org.bouncycastle.util.encoders.Hex;import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.ECGenParameterSpec;
import java.util.Base64;/*** SM2工具类* @author van*/public class SM2Utils {/*** 生成 SM2 公私钥对** @return* @throws NoSuchAlgorithmException* @throws InvalidAlgorithmParameterException*/public static KeyPair geneSM2KeyPair() throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {final ECGenParameterSpec sm2Spec = new ECGenParameterSpec("sm2p256v1");// 获取一个椭圆曲线类型的密钥对生成器final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());// 产生随机数SecureRandom secureRandom = new SecureRandom();// 使用SM2参数初始化生成器kpg.initialize(sm2Spec, secureRandom);// 获取密钥对KeyPair keyPair = kpg.generateKeyPair();return keyPair;}/*** 生产hex秘钥对*/public static void geneSM2HexKeyPair(){try {KeyPair keyPair = geneSM2KeyPair();PrivateKey privateKey = keyPair.getPrivate();PublicKey publicKey = keyPair.getPublic();System.out.println("========  EC X Y keyPair    ========");System.out.println(privateKey);System.out.println(publicKey);System.out.println("========  hex keyPair       ========");System.out.println("hex priKey: " + getPriKeyHexString(privateKey));System.out.println("hex pubKey: " + getPubKeyHexString(publicKey));System.out.println("========  base64 keyPair    ========");System.out.println("base64 priKey: " + new String(Base64.getEncoder().encode(privateKey.getEncoded())));System.out.println("base64 pubKey: " + new String(Base64.getEncoder().encode(publicKey.getEncoded())));System.out.println("========  generate finished ========");} catch (Exception e) {e.printStackTrace();}}/*** 获取私钥(16进制字符串,头部不带00长度共64)** @param privateKey 私钥PrivateKey型* @return*/public static String getPriKeyHexString(PrivateKey privateKey) {// OK
//	        BCECPrivateKey s=(BCECPrivateKey)privateKey;
//	        String priKeyHexString = Hex.toHexString(s.getD().toByteArray());
//	        if(null!= priKeyHexString && priKeyHexString.length()==66 && "00".equals(priKeyHexString.substring(0,2))){
//	            return priKeyHexString.substring(2);
//	        }// OKBCECPrivateKey key = (BCECPrivateKey) privateKey;BigInteger intPrivateKey = key.getD();String priKeyHexString = intPrivateKey.toString(16);return priKeyHexString;}/*** 获取私钥 base64字符串** @param privateKey 私钥PrivateKey型* @return*/public static String getPriKeyBase64String(PrivateKey privateKey) {return new String(Base64.getEncoder().encode(privateKey.getEncoded()));}/*** 获取公钥(16进制字符串,头部带04长度共130)** @param publicKey 公钥PublicKey型* @return*/public static String getPubKeyHexString(PublicKey publicKey) {BCECPublicKey key = (BCECPublicKey) publicKey;return Hex.toHexString(key.getQ().getEncoded(false));}/*** 获取公钥 base64字符串** @param publicKey 公钥PublicKey型* @return*/public static String getPubKeyBase64String(PublicKey publicKey) {return new String(Base64.getEncoder().encode(publicKey.getEncoded()));}/*** SM2加密算法** @param publicKey 公钥* @param data      明文数据* @return*/public static String encrypt(String data, PublicKey publicKey) {return encrypt(data.getBytes(StandardCharsets.UTF_8), publicKey);}/*** @param data* @param publicKey* @return* @author * @version 1.0* 2023年4月12日下午4:41:24*/public static String encrypt(byte[] data, PublicKey publicKey) {BCECPublicKey key = (BCECPublicKey) publicKey;return encrypt(data, Hex.toHexString(key.getQ().getEncoded(false)));}/*** @param data* @param pubKeyHexString* @return* @author * @version 1.0* 2023年4月12日下午4:46:37*/public static String encrypt(String data, String pubKeyHexString) {return encrypt(data.getBytes(StandardCharsets.UTF_8), pubKeyHexString);}/*** SM2加密算法** @param pubKeyHexString 公钥(16进制字符串)* @param data            明文数据* @return hex字符串*/public static String encrypt(byte[] data, String pubKeyHexString) {// 获取一条SM2曲线参数X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");// 构造ECC算法参数,曲线方程、椭圆曲线G点、大整数NECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());//提取公钥点ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pubKeyHexString));// 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 设置sm2为加密模式sm2Engine.init(true, new ParametersWithRandom(publicKeyParameters, new SecureRandom()));byte[] arrayOfBytes = null;try {arrayOfBytes = sm2Engine.processBlock(data, 0, data.length);} catch (Exception e) {System.out.println("SM2加密时出现异常:" + e.getMessage());}return Hex.toHexString(arrayOfBytes);}/*** SM2解密算法* @param cipherData    hex格式密文* @param privateKey    密钥PrivateKey型* @return              明文*/public static String decrypt(String cipherData, PrivateKey privateKey) {return decrypt(Hex.decode(cipherData), privateKey);}/*** @param cipherData* @param privateKey* @return* @author * @version 1.0* 2023年4月12日下午4:46:50*/public static String decrypt(byte[] cipherData, PrivateKey privateKey) {BCECPrivateKey key = (BCECPrivateKey) privateKey;return decrypt(cipherData, Hex.toHexString(key.getD().toByteArray()));}/*** @param cipherData* @param priKeyHexString* @return* @author * @version 1.0* 2023年4月12日下午4:46:53*/public static String decrypt(String cipherData, String priKeyHexString) {// 使用BC库加解密时密文以04开头,传入的密文前面没有04则补上if (!cipherData.startsWith("04")) {cipherData = "04" + cipherData;}return decrypt(Hex.decode(cipherData), priKeyHexString);}/*** SM2解密算法** @param cipherData      密文数据* @param priKeyHexString 私钥(16进制字符串)* @return*/public static String decrypt(byte[] cipherData, String priKeyHexString) {//获取一条SM2曲线参数X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");//构造domain参数ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());BigInteger privateKeyD = new BigInteger(priKeyHexString, 16);ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(privateKeyD, domainParameters);SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);// 设置sm2为解密模式sm2Engine.init(false, privateKeyParameters);String result = "";try {byte[] arrayOfBytes = sm2Engine.processBlock(cipherData, 0, cipherData.length);return new String(arrayOfBytes);} catch (Exception e) {System.out.println("SM2解密时出现异常:" + e.getMessage());}return result;}/*** @param data* @param priKeyHexString hex私钥,长度64* @return hex格式签名值* @throws Exception*/public static String sign(String data, String priKeyHexString) throws Exception {return sign(data.getBytes(StandardCharsets.UTF_8), priKeyHexString);}/*** 签名* @param data              原始数据,字节数组* @param priKeyHexString   hex私钥,64长度* @return                  Hex字符串* @throws Exception*/public static String sign(byte[] data, String priKeyHexString) throws Exception {String signValue = null;SM2Signer signer = new SM2Signer();X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");//构造domain参数ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());CipherParameters param = new ParametersWithRandom(new ECPrivateKeyParameters(new BigInteger(priKeyHexString, 16), domainParameters));signer.init(true, param);signer.update(data, 0, data.length);signValue = Hex.toHexString(signer.generateSignature());return signValue;}/*** 验签* @param data                  数据* @param signValue             签名值(hex型)* @param pKHexString    hex130长度公钥* @return */public static boolean verify(String data, String signValue, String publicKeyHexString) throws Exception {return verify(data.getBytes(StandardCharsets.UTF_8), Hex.decode(signValue), publicKeyHexString);}/*** 验签* @param data                  原始数据字节数组* @param sign                  字节数组()* @param pKHexString    hex130长度公钥* @return                      true or false* @throws Exception*/public static boolean verify(byte[] data, byte[] sign, String pKHexString) throws Exception {SM2Signer signer = new SM2Signer();X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");//构造domain参数ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());if (pKHexString.length() == 128) {pKHexString = "04" + pKHexString;}ECPoint ecPoint = sm2ECParameters.getCurve().decodePoint(Hex.decode(pKHexString));CipherParameters param = new ECPublicKeyParameters(ecPoint, domainParameters);signer.init(false, param);signer.update(data, 0, data.length);return signer.verifySignature(sign);}/*** 私钥生成公钥* @param priKeyHexString 私钥Hex格式,必须64位* @return 公钥Hex格式,04开头,130位* @throws Exception 例如:*/public static String getPubKeyByPriKey(String priKeyHexString) throws Exception {if (priKeyHexString == null || priKeyHexString.length() != 64) {System.err.println("priKey 必须是Hex 64位格式,例如:11d0a44d47449d48d614f753ded6b06af76033b9c3a2af2b8b2239374ccbce3a");return "";}String pubKeyHexString = null;X9ECParameters sm2ECParameters = GMNamedCurves.getByName("sm2p256v1");//构造domain参数BigInteger privateKeyD = new BigInteger(priKeyHexString, 16);ECParameterSpec ecParameterSpec = new ECParameterSpec(sm2ECParameters.getCurve(), sm2ECParameters.getG(), sm2ECParameters.getN());ECPrivateKeySpec ecPrivateKeySpec = new ECPrivateKeySpec(privateKeyD, ecParameterSpec);PrivateKey privateKey = null;privateKey = KeyFactory.getInstance("EC", new BouncyCastleProvider()).generatePrivate(ecPrivateKeySpec);// 临时解决办法String pointString = privateKey.toString();
//	        System.out.println(pointString);String pointString_X = pointString.substring(pointString.indexOf("X: ") + "X: ".length(), pointString.indexOf("Y: ")).trim();String pointString_Y = pointString.substring(pointString.indexOf("Y: ") + "Y: ".length()).trim();
//	        System.out.println(pointString_X);
//	        System.out.println(pointString_Y);pubKeyHexString = "04" + pointString_X + pointString_Y;return pubKeyHexString;}}

相关文章:

Java实现SM2前后端加解密

Sm2加解密原理&#xff0c;非对称加密&#xff0c;公钥加密&#xff0c;私钥解密。公私钥对成对生成&#xff0c;加密端解密端各自保存。用公钥加密必须要用对应的私钥才能解密&#xff0c;保证安全性。 这里我们实现的功能是前端加密&#xff0c;后端解密&#xff0c;这样前端…...

自动化PLC工程师能否转到c#上位机开发?

成功从自动化PLC工程师转向C#上位机开发的经历可能因人而异&#xff0c;以下是一些分享的思路和建议&#xff1a;扩展编程技能&#xff1a;学习C#语言和相关的开发工具和框架&#xff0c;掌握语言的基础知识和常用的编程技巧。可以通过在线教程、培训课程、书籍等途径进行学习&…...

LiveData相关基本使用及去除黏性数据的方法

目录 一、LiveData的基本使用1. 使用方式一2. 使用方式二3. 使用方式三 二、LiveData 去除黏性数据的方法1. 去除黏性的Java版本2. 去除黏性的Kotlin版本 一、LiveData的基本使用 1. 使用方式一 MyLiveData.kt package com.example.mylivedata.simple1import androidx.lifec…...

【MegaCli】安装MegaCli后执行报参数错误

问题: 刚安装好Mega后执行报错 /opt/MegaRAID/MegaCli/MegaCli64 Fatal error - Command Tool invoked with wrong parameters Exit Code: 0x01 /opt/MegaRAID/MegaCli/MegaCli64 Fatal error - Command Tool invoked with wrong parameters Exit Code: 0x01原因&#xff1a;…...

时间范围选择时选中日期所使用的当日内具体时刻 如00:00:00= 23:59:59

<el-form-item label"审核时间&#xff1a;"><el-date-pickerv-model"auditTime"type"datetimerange"range-separator"至"value-format"yyyy-MM-dd HH:mm:ss"start-placeholder"开始日期"end-placeholde…...

算法面试-深度学习面试题整理(2024.8.29开始,每天下午持续更新....)

一、无监督相关&#xff08;聚类、异常检测&#xff09; 1、常见的距离度量方法有哪些&#xff1f;写一下距离计算公式。 1&#xff09;连续数据的距离计算&#xff1a; 闵可夫斯基距离家族&#xff1a; 当p 1时&#xff0c;为曼哈顿距离&#xff1b;p 2时&#xff0c;为欧…...

Maven之高版本的 lombok 和 tomcat 7 插件冲突问题

高版本的 lombok 和 tomcat 7 插件冲突问题 在开发期间&#xff0c;当我们使用 tomcat7-maven-plugin 来作为运行环境运行我们项目使&#xff0c;如果我们项目中使用了 1.16.20 及以上版本的 lombok 包&#xff0c;项目启动时会报错&#xff1a; for annotations org.apache.…...

微信小程序申请

方案说明&#xff1a; 微信小程序申请步骤有两个过程&#xff0c;目前采用的是第二种方案 第一种方案&#xff1a;直接向微信申请微信小程序 第二种方案&#xff1a;先申请公众号后再通过公众号快速注册并申请小程序 无论申请公众号还是小程序都需要微信认证&#xff0c;微…...

ffmpeg 配合Fiddler抓包操作

首先需要安装和配置ffmpeg 1.扩大音频2倍 ffmpeg -i 2.mp3 -filter:a "volume2.0" 3.mp32.扩大音频4倍 ffmpeg -i 2.mp3 -filter:a "volume4.0" 3.mp33.音视频合成&#xff08;m4s视频和mp3音频合成&#xff09; ffmpeg -i 1.m4s -i 3.mp3 -vcodec cop…...

美团面试拷打:ConcurrentHashMap 为何不能插入 null?HashMap 为何可以?

周末的时候,有一位小伙伴提了一些关于 ConcurrentHashMap 的问题,都是他最近面试遇到的。原提问如下(星球原贴地址:https://t.zsxq.com/11jcuezQs ): 整个提问看着非常复杂,其实归纳来说就是两个问题: ConcurrentHashMap 为什么 key 和 value 不能为 null?ConcurrentH…...

【力扣每日一题】2023.8.29 带因子的二叉树

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 题目给我们一些元素&#xff0c;让我们用这些元素连接形成特定的二叉树&#xff0c;每种元素可以使用任意次数&#xff0c;形成的二叉树要…...

origin导出pdf曲线超出边框

软件版本 软件版本Word2021Origin2021Adobe Acrobat Pro2023 问题描述 Origin导出的emf格式矢量图片&#xff0c;插入到Word中&#xff0c;显示正常&#xff0c;但是在使用Word导出→创建Adobe PDF→创建Adobe PDF导出PDF文件后&#xff0c;图片曲线就会超出边框&#xff0c…...

由Android10适配到Android12时遇到相关编译失败问题

最近Android系统各大应用商店联合发出公告&#xff0c;处于个人隐私安全考虑&#xff0c;强制APP适配到Android 11及以上版本。下面是其中应用市场的公告&#xff08;顺带提醒没适配的同学&#xff09;&#xff1a; 适配前的开发环境 名称版本Android studioGiraffe | 2022.3…...

高职教育应对ChatGPT应用的策略

一、完善顶层设计&#xff0c;提升技术水平 在推广ChatGPT平台的过程中&#xff0c;高职院校需要关注技术本身的问题。这就需要在国家和地方政府的引导下&#xff0c;引入更完善的技术顶层设计&#xff0c;提高人工智能在高职教育中的运用水平。具体来说&#xff0c;一方面需要…...

Linux 内核编译参数

文章目录 前言1 -Wall2 -Wundef3 -Wstrict-prototypes4 -Wno-trigraphs5 -fno-strict-aliasing6 -fno-common7 -Werror-implicit-function-declaration8 -Wno-format-security9 -fno-delete-null-pointer-checks10 -stdgnu89 前言 # cat /etc/os-release NAME"CentOS Lin…...

vscode使用anaconda自带的python环境在终端运行时报错

目录 具体报错内容官方翻译报错讲人话解决方法 具体报错内容 CommandNotFoundError: Your shell has not been properly configured to use conda activate. If your shell is Bash or a Bourne variant, enable conda for the current user with$ echo ". E:\Anaconda/e…...

葡萄叶病害识别(图像连续识别和视频识别,Python代码,pyTorch框架)

葡萄叶病害识别&#xff08;图像连续识别和视频识别&#xff0c;Python代码&#xff0c;pyTorch框架&#xff09;_哔哩哔哩_bilibili 葡萄数据集 第一个文件夹为 Grape Black Measles&#xff08;葡萄黑麻疹&#xff09;病害&#xff08;3783张&#xff09; Grape Black rot葡…...

Oracle drop删除表如何恢复

摘要&#xff1a; 在 Oracle 数据库管理中&#xff0c;DROP 命令的误操作可能导致数据不可挽回的丢失。然而&#xff0c;Oracle 提供了回收站&#xff08;recycle bin&#xff09;功能&#xff0c;允许用户在删除对象后的一段时间内恢复它们。本文将介绍如何查询、启用和管理回…...

5、监测数据采集物联网应用开发步骤(5.1)

监测数据采集物联网应用开发步骤(4) Sqlite3数据库读写操作开发、异常信息统一处理类开发 本章节需要调用sqlite3及mysql-connector 安装sqlite3 Pip3 install sqlite3 安装mysql-connector pip3 install mysql-connector 验证是否安装成功&#xff0c;python中运行下列…...

ZZULIOJ 1148: 组合三位数之一,Java

ZZULIOJ 1148: 组合三位数之一&#xff0c;Java 题目描述 把1、2、3、4、5、6、7、8、9组合成3个3位数&#xff0c;要求每个数字仅使用一次&#xff0c;使每个3位数均为完全平方数。按从小到大的顺序输出这三个三位数。 输入 无 输出 按从小到大的顺序输出这三个三位数&a…...

k8s从入门到放弃之Ingress七层负载

k8s从入门到放弃之Ingress七层负载 在Kubernetes&#xff08;简称K8s&#xff09;中&#xff0c;Ingress是一个API对象&#xff0c;它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress&#xff0c;你可…...

关于nvm与node.js

1 安装nvm 安装过程中手动修改 nvm的安装路径&#xff0c; 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解&#xff0c;但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后&#xff0c;通常在该文件中会出现以下配置&…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

Qt Http Server模块功能及架构

Qt Http Server 是 Qt 6.0 中引入的一个新模块&#xff0c;它提供了一个轻量级的 HTTP 服务器实现&#xff0c;主要用于构建基于 HTTP 的应用程序和服务。 功能介绍&#xff1a; 主要功能 HTTP服务器功能&#xff1a; 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

网络编程(UDP编程)

思维导图 UDP基础编程&#xff08;单播&#xff09; 1.流程图 服务器&#xff1a;短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南

精益数据分析&#xff08;97/126&#xff09;&#xff1a;邮件营销与用户参与度的关键指标优化指南 在数字化营销时代&#xff0c;邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天&#xff0c;我们将深入解析邮件打开率、网站可用性、页面参与时…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

html css js网页制作成品——HTML+CSS榴莲商城网页设计(4页)附源码

目录 一、&#x1f468;‍&#x1f393;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站效果 五、&#x1fa93; 代码实现 &#x1f9f1;HTML 六、&#x1f947; 如何让学习不再盲目 七、&#x1f381;更多干货 一、&#x1f468;‍&#x1f…...

基于SpringBoot在线拍卖系统的设计和实现

摘 要 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统&#xff0c;主要的模块包括管理员&#xff1b;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...