加解密添加

This commit is contained in:
haozq 2025-09-11 15:11:17 +08:00
parent 4d35e32ed5
commit e4effd6b3c
14 changed files with 411 additions and 13 deletions

View File

@ -3,6 +3,7 @@ package com.bonus.base.controller.system;
import java.util.List;
import java.util.Set;
import com.bonus.common.encryption.Sm4Utils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@ -45,7 +46,6 @@ public class SysLoginController
public AjaxResult sendPhone(@RequestBody String phone) {
// 下发短信
AjaxResult ajax= loginService.sendPhone(phone);
return ajax;
}
@ -58,17 +58,18 @@ public class SysLoginController
*/
@PostMapping("/login")
public AjaxResult login(@RequestBody LoginBody loginBody) {
String token;
AjaxResult ajax = AjaxResult.success();
if("2".equals(loginBody.getLoginType())){
token = loginService.login(loginBody.getUsername(), loginBody.getCode());
}else{
token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
loginBody.getUuid());
}
// 生成令牌
ajax.put(Constants.TOKEN, token);
return ajax;
}

View File

@ -13,7 +13,17 @@
</description>
<dependencies>
<!--视频转换-->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.5.10</version>
</dependency>
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv-platform</artifactId>
<version>1.5.10</version>
</dependency>
<!-- 通用工具-->
<dependency>
<groupId>com.bonus</groupId>

View File

@ -0,0 +1,61 @@
package com.bonus.business.controller;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
public class VideoToMp4Converter {
/**
* 将视频文件转换为MP4格式
* @param inputPath 输入视频文件路径
* @param outputPath 输出MP4文件路径
* @throws Exception 转换过程中的异常
*/
public static void convertToMp4(String inputPath, String outputPath) throws Exception {
// 创建FFmpegFrameGrabber对象读取输入视频
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(inputPath);
grabber.start();
// 创建FFmpegFrameRecorder对象设置输出视频参数
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputPath,
grabber.getImageWidth(),
grabber.getImageHeight());
// 设置视频编码为H.264
recorder.setVideoCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_H264);
// 设置输出格式为MP4
recorder.setFormat("mp4");
// 设置帧率与原视频保持一致
recorder.setFrameRate(grabber.getFrameRate());
// 设置音频通道数
recorder.setAudioChannels(grabber.getAudioChannels());
// 设置音频编码
recorder.setAudioCodec(org.bytedeco.ffmpeg.global.avcodec.AV_CODEC_ID_AAC);
recorder.start();
// 循环读取视频帧并进行录制
Frame frame;
while ((frame = grabber.grabFrame()) != null) {
recorder.record(frame);
}
// 关闭抓取器和录制器
recorder.stop();
grabber.stop();
System.out.println("视频转换完成!输出文件:" + outputPath);
}
// 测试方法
public static void main(String[] args) {
try {
String inputVideo = "input_video.flv"; // 输入视频文件可以是任何格式
String outputMp4 = "output_video.mp4"; // 输出MP4文件
convertToMp4(inputVideo, outputMp4);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -107,4 +107,11 @@ public interface ProductMapper {
* @return
*/
int delProduct(TbProduct product);
/**
* 判断名称是否存在
* @param product
* @return
*/
Integer getProductByName(TbProduct product);
}

View File

@ -56,10 +56,14 @@ public class ProductScreenImpl implements ProductScreenService {
@Override
public AjaxResult getProductDetails(TbProduct product) {
try{
//详情
TbProduct vo=mapper.getProductDetails(product);
if(vo!=null){
//封面图
vo.setLinkImage(minioConfig.getUrl()+"/"+minioConfig.getBucketName()+vo.getLinkImage());
List<TbProductCase> productCases=productMapper.getProductCaseList(product.getId());
for (TbProductCase productCase:productCases) {
//产品案例
List<ProductCaseImage> caseImages=productMapper.getCaseImageByTable(productCase.getId(),"tb_product_case");
if(StringUtils.isNotEmpty(caseImages)){
caseImages.forEach(image->{
@ -68,12 +72,14 @@ public class ProductScreenImpl implements ProductScreenService {
productCase.setImageList(caseImages);
}
}
vo.setList(productCases);
//查询 宣传手册和宣传视频
List<ProductScreenVo> list=mapper.getMaterialList(vo);
List<ProductScreenVo> videoList=new ArrayList<>();
List<ProductScreenVo> fileList=new ArrayList<>();
if(StringUtils.isNotEmpty(list)){
list.forEach(vo1->{
vo1.setImage(minioConfig.getUrl()+"/"+minioConfig.getBucketName()+vo1.getImage());
vo1.setUrl(minioConfig.getUrl()+"/"+minioConfig.getBucketName()+vo1.getFilePath());
if("0".equals(vo1.getFileType())){
videoList.add(vo1);
@ -85,9 +91,10 @@ public class ProductScreenImpl implements ProductScreenService {
vo.setFileList(fileList);
}
}
return AjaxResult.success(vo);
}catch (Exception e){
log.error(e.toString());
}
return null;
return AjaxResult.success(product);
}
}

View File

@ -98,6 +98,10 @@ public class ProductServiceImpl implements ProductService {
product.setCreateUser(SecurityUtils.getUserId().toString());
product.setUpdateUser(SecurityUtils.getUserId().toString());
//新增产品及产品文件
Integer isName=mapper.getProductByName(product);
if(isName!=null && isName>0){
return AjaxResult.error("产品名称已存在");
}
int num=mapper.addProduct(product);
List<MultipartFile> prFile=map.get("s");
AjaxResult ajaxResult1=uploadFile(prFile,"tb_product",product.getId(),"产品封面");
@ -157,6 +161,10 @@ public class ProductServiceImpl implements ProductService {
//修改产品
List<MultipartFile> proList=map.get("s");
product.setUpdateUser(SecurityUtils.getUserId().toString());
Integer isName=mapper.getProductByName(product);
if(isName!=null && isName>0){
return AjaxResult.error("产品名称已存在");
}
int isSuccess=mapper.updateProduct(product);
//未跟新文件
if(StringUtils.isNotEmpty(proList)){

View File

@ -26,14 +26,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
where tpt.id=#{id}
</select>
<select id="getMaterialList" resultType="com.bonus.business.domain.ProductScreenVo">
select tpm.id, tpm.type_id typeId ,tpm.type_name typeName,tpm.name ,tpm.version ,tpm.description ,tpm.image ,
pmf.file_type fileType ,pmf.file_path filePath, pmf.bucket_name bucketName,pmf.original_name originalName
from tb_promotion_material tpm
left join sys_dict_data sdd on sdd.dict_value=tpm.type_id and sdd.dict_type='tb_product_type'
left join tb_promotion_material_files pmf on tpm.id=pmf.material_id and pmf.del_flag=0 and pmf.type_id=1
select tpm.id, tpm.type_id,tpm.type_name,tpm.name ,tpm.version ,tpm.description ,tpm.image ,
pmf.file_type fileType ,pmf.file_path filePath, pmf.bucket_name bucketName,pmf.original_name originalName
from tb_promotion_material_product pmp
left join tb_promotion_material tpm on tpm.id=pmp.material_id
left join tb_promotion_material_files pmf on tpm.id=pmf.material_id and pmf.del_flag=0 and pmf.type_id=1
where tpm.del_flag=0
<if test="typeId!=null and typeId!=''">
and tpm.type_id=#{typeId}
<if test="id!=null and id!=''">
and pmp.product_id=#{id}
</if>
</select>
</mapper>

View File

@ -59,6 +59,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
from tb_product_case
where product_id=#{id} and del_flag=0
</select>
<select id="getProductByName" resultType="java.lang.Integer">
select count(1)
from tb_product
where name=#{name} and del_flag=0
<if test="id!=null and id!=''">
and id!=#{id}
</if>
</select>
<insert id="addProduct" parameterType="com.bonus.business.domain.TbProduct" keyProperty="id" useGeneratedKeys="true" >
insert into tb_product
@ -120,7 +129,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="isLink != null">is_link = #{isLink},</if>
<if test="introduction != null">introduction = #{introduction},</if>
<if test="delFlag != null">del_flag = #{delFlag},</if>
<if test="delFlag != null">isAccess = #{isAccess},</if>
<if test="isAccess != null">is_access = #{isAccess},</if>
update_time =now(), update_user=#{updateUser}
</trim>
where id = #{id}

View File

@ -16,6 +16,11 @@
</description>
<dependencies>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.70</version> <!-- 使用最新稳定版本 -->
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>

View File

@ -0,0 +1,120 @@
package com.bonus.common.encryption;
import com.bonus.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.Security;
/**
* AES加密工具类
*
* @author HeiZi
*/
@Slf4j
public class AesCbcUtils {
//使用AES-256-CBC加密模式key需要为16位,key和iv可以相同
/**
* 密钥算法
*/
private static final String KEY_ALGORITHM = "AES";
/**
* 加密/解密算法 / 工作模式 / 填充方式
* Java 6支持PKCS5Padding填充方式
* Bouncy Castle支持PKCS7Padding填充方式
*/
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS7Padding";
/**
* 偏移量只有CBC模式才需要
*/
private final static String IV_PARAMETER = "1234567812345678";
/**
* AES要求密钥长度为128位或192位或256位java默认限制AES密钥长度最多128位
*/
public static String sKey = "zhgd@bonus@zhgd@bonus@1234567890";
/**
* 编码格式导出
*/
public static final String ENCODING = "utf-8";
static {
//如果是PKCS7Padding填充方式则必须加上下面这行
Security.addProvider(new BouncyCastleProvider());
}
/**
* AES加密
* CBC模式
*
* @param source 源字符串
* @param
* @return 加密后的密文
* @throws Exception
*/
public static String encrypt(String source, String key, String encoding, String ivParameter, String cipherAlgorithm, String keyAlgorithm) {
try {
byte[] sourceBytes = source.getBytes(encoding);
byte[] keyBytes = key.getBytes(encoding);
Cipher cipher = Cipher.getInstance(cipherAlgorithm, "BC");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(encoding));
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, keyAlgorithm), iv);
byte[] decrypted = cipher.doFinal(sourceBytes);
return Base64.encodeBase64String(decrypted);
} catch (Exception e) {
log.error(e.toString(), e);
}
return null;
}
// public static void main(String[] args) {
// // String json="";
//
// String json="{\"username\":\"guest\",\"password\":\"admin@123\"}";
// String data=encrypt(json);
// System.err.println(data);
// String jm=decrypt("\"yeCxaGhmdDt+zDsKPr1prukR15BfIMLMOYIFKdgffGpMV76qVD8ANU4zsLiRZ87+7hd1Yje182nHhUOp/TeYCRuuUPQzmuXH7ikYVEWR1Rmc8uLq3G/BTMU6wFMSRFDBXARRl+dvnpyfX+MleF0KB1OAeuOIKv1gQPskmvDiFAniUlowf/96ZzMl7Bokqc/Lse8lMV92IQB14yQNa0+u/2kvdirzrcq+HCt9K8Ot3C59mjDqg49WoM65LEmaHmZqzdmmjbQlGH7ZOAFTLvF5kPzUsMz5Uim1uNvByB3eLFohc1UgB28DWoTyh43sRMPpq3S1BB20gcrBf3uVra/4qehBr3z98CGhGRyKHbjsCKl0Ri6YO1rp5aMRd9Y3wbOJFrZXFag5iifQx+ooDBeu6h1KCb5JfCjyAmw9+pgEL6X3eELPzK13XjblDyEikjx2Edv45MGsC0DUcjvz/Sb4E/8rn3o1Ep7W31xNCdn5mzZ8VO9POhE3DMK6woeN2C7TW+7YO/Zs9e4zKLS4vThvk5urCn2Ff2HkVBzoPtP2imuqQrY8898sbLllyaJEG0DPSrCf985ZgVa03JsO/EkMr3KAiHV5SHBZS1XEXqjdpL+YEdOnlfBXUk83kJhLj9rhUrTFza7ednQSzjq4XpIJJVy2aJhhj1chsmIM1Xl//0Dbak9Lb6VUq5Xr2IFAjNTgyxwtcFCdEvp4YZCSP6kqWgEpeAVlejyYOcNckUnWkjeHjtfgwvVsvUjWzyIRFCa7m/oY28xBV16RmW/r4XXquqKVdbPtATzrmf7pJCynXZ3IPd9ZGc1OTLnss9Ln9XNTH0E/I4Ma95fn9uxA+sOQkQ==\"");
// String jiemi=decrypt(data);
// System.err.println(jm);
// System.err.println(jiemi);
// }
/**
* AES解密
* CBC模式
*
* @param data 加密后的密文
* @param
* @return 源字符串
* @throws Exception
*/
public static String decrypt(String data, String key, String encoding, String ivParameter, String cipherAlgorithm, String keyAlgorithm) {
try {
String encryptStr = "";
if (StringUtils.isNotEmpty(data)) {
encryptStr = data.replace(" ", "+");
}
byte[] sourceBytes = Base64.decodeBase64(encryptStr);
byte[] keyBytes = key.getBytes(encoding);
Cipher cipher = Cipher.getInstance(cipherAlgorithm, "BC");
IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(encoding));
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(keyBytes, keyAlgorithm), iv);
byte[] decoded = cipher.doFinal(sourceBytes);
return new String(decoded, encoding);
} catch (Exception e) {
log.info("------------------->请求加密参数不正确");
log.error(e.toString(), e);
}
return null;
}
}

View File

@ -0,0 +1,68 @@
package com.bonus.common.encryption;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
/**
* @author 黑子
* SM2加解密
*/
public class Sm2Util {
static SM2 sm2 = SmUtil.sm2();
/**
* 获取公钥
* @return
*/
public static String getPublicKey(){
return HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
}
/**
* 获取私钥
* @return
*/
public static String getPrivateKey(){
return HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
}
// public static void main(String[] args) {
// String privateKey = getPrivateKey();
// String publicKey = getPublicKey();
// String msg= encrypt(publicKey,"1234567890");
//// String msg2= decrypt(privateKey,msg);
// System.err.println(msg);
//// System.err.println(msg2);
// }
/**
* 加密
*公钥加密
* @param publicKey 公钥
* @param data 明文
* @return 密文
*/
public static String encrypt(String publicKey, String data) {
return SmUtil.sm2(null, publicKey)
.encryptHex(data.getBytes(), KeyType.PublicKey)
// 加密后密文前面会有04需要去掉
.substring(2);
}
/**
* 解密
* 私钥解密
* @param privateKey 私钥
* @param data 密文
* @return 明文
*/
public static String decrypt(String privateKey, String data) {
// 前端加密是没有04的所以解析的时候要加04
data = "04" + data;
return SmUtil.sm2(privateKey, null)
.decryptStr(data, KeyType.PrivateKey);
}
}

View File

@ -0,0 +1,31 @@
package com.bonus.common.encryption;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.digest.SM3;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* @author weiweiw
* SM3加解密
*/
public class Sm3Util {
static SM3 sm3 = SmUtil.sm3WithSalt("2cc0c5f9f1749f1632efa9f63e902323".getBytes(StandardCharsets.UTF_8));
public static String encrypt(String data) {
return Sm3Util.sm3.digestHex(data);
}
public static String encrypt(InputStream data) {
return Sm3Util.sm3.digestHex(data);
}
public static String encrypt(File dataFile) {
return Sm3Util.sm3.digestHex(dataFile);
}
}

View File

@ -0,0 +1,67 @@
package com.bonus.common.encryption;
import cn.hutool.core.util.HexUtil;
import cn.hutool.crypto.Mode;
import cn.hutool.crypto.Padding;
import cn.hutool.crypto.symmetric.SM4;
/**
* @author bonus
*/
public class Sm4Utils {
/**
* 必须是16字节
*/
private static final String KEY = "78d1295afa99449b99d6f83820e6965c";
private static final String IV = "f555adf6c01d0ab0761e626a2dae34a2";
/**
* 加密数据使用固定盐
*
* @param plainText 明文待加密的字符串
* @return 加密后的密文包含盐Hex 编码格式如果加密异常就返回传入的字符串
*/
public static String encrypt(String plainText) {
try {
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(KEY),HexUtil.decodeHex(IV));
// 加密带盐的明文
byte[] encryptedData = sm4.encrypt(plainText);
// 返回带盐的加密结果Hex编码
return HexUtil.encodeHexStr(encryptedData);
} catch (Exception e) {
return plainText; // 发生异常时返回传入字符串
}
}
/**
* 解密数据使用固定盐
*
* @param cipherText 密文包含盐Hex 编码格式的字符串
* @return 解密后的明文字符串如果解密异常就返回传入的字符串
*/
public static String decrypt(String cipherText) {
try {
// 初始化SM4解密工具
SM4 sm4 = new SM4(Mode.CBC, Padding.PKCS5Padding, HexUtil.decodeHex(KEY),HexUtil.decodeHex(IV));
// 解密数据
byte[] decryptedData = sm4.decrypt(cipherText);
return new String(decryptedData);
} catch (Exception e) {
return cipherText; // 发生异常时返回传入字符串
}
}
// 测试方法演示加密和解密过程
public static void main(String[] args) {
String plainText = "15398187429";
System.out.println("原文: " + plainText);
// 加密明文
String encryptedText = Sm4Utils.encrypt(plainText);
System.out.println("加密后: " + encryptedText);
// 解密密文
String decryptedText = Sm4Utils.decrypt(plainText);
System.out.println("解密后: " + decryptedText);
}
}

View File

@ -3,6 +3,7 @@ package com.bonus.framework.web.service;
import javax.annotation.Resource;
import com.bonus.common.core.domain.AjaxResult;
import com.bonus.common.encryption.Sm4Utils;
import com.bonus.common.utils.PhoneUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
@ -76,6 +77,8 @@ public class SysLoginService
*/
public String login(String username, String password, String code, String uuid)
{
username= Sm4Utils.decrypt(username);
password= Sm4Utils.decrypt(password);
// 验证码校验
validateCaptcha(username, code, uuid);
// 登录前置校验
@ -226,6 +229,7 @@ public class SysLoginService
* @return
*/
public AjaxResult sendPhone(String phone) {
phone= Sm4Utils.decrypt(phone);
//验证手机手机号是否存在
String thisUser=userService.getUserInfo(phone);
if(!phone.equals(thisUser)){