JAVA-WEB项目中,前后台结合AES和RSA对数据加密处理

2023-11-19

实际项目中为了系统安全,我们经常需要对请求数据和响应数据做加密处理,这里以spring后台,vue前台的java web为例,记录一个实现过程

一、为什么要结合AES和RSA?

因为AES是对称加密,即加密解密用的秘钥是一样,这样一来AES的秘钥保管尤其重要,但是AES有个很好的优点,就是处理效率高。而RSA是不对称加密,即加密解密用的秘钥不一样,分别叫公钥和私钥,通常用公钥加密,然后用私钥解密,其中公钥可以公开,只需要保管好私钥即可,而相比AES而言RSA速度慢效率低。所以,通常我们结合这两种加密方式的优点来完成数据的安全传输。

二、AES和RSA的结合使用过程

1.前端随机动态生成aesKey:因为AES的加密解密秘钥需要一致,如果整个系统写死AES的秘钥会很不安全,所以每次请求动态生成aesKey会比较好

2.前端用RSA对动态aesKey加密:动态aesKey需要传到后端供解密,传输过程用RSA加密

3.前端保存动态aesKey:因为同一个请求的响应需要一样的aesKey解密,所以前端还得把动态aesKey保存下来,可以再随机生成一个id,然后按键值对的方式保存在前端变量中{id: aesKey}

4.把加密的aesKey和id放到请求头

5.后端用RSA私钥解密得明文aesKey:后端从请求头取出加密的aesKey,然后用私钥解密拿到明文的aesKey,然后对请求数据解密

6.后端用明文aesKey加密响应数据

7.后端把请求过来的id放到响应头

8.前端根据响应头的id,取到对应的aesKey,对响应数据解密

9.前端删除动态的aesKey

三、具体实现案例

1.前端实现AES和RSA的公共方法

        aesUtils.js:


 const CryptoJS = require('crypto-js')

 function GetRandomNum (n) {
    let chars = [
      '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F',
      'G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V',
      'W','X','Y','Z','.','?','~','!','@','#','$','%','^','&','*']
    if(n == null) {
      n = 16
    }
    let res = ""
    for(let i = 0; i < n ; i++) {
      let id = Math.ceil(Math.random()*46)
      res += chars[id]
    }
    return res
 }

function GetUuid () {
  let s = []
  const hexDigits = '0123456789abcdef'
  for (let i = 0; i < 36; i++) {
    let indexStart = Math.floor(Math.random() * 0x10)
    s[i] = hexDigits.substring(indexStart, indexStart+1)
  }
  s[14] = '4'
  let indexStart = (s[19] & 0x3) | 0x8
  s[19] = hexDigits.substring(indexStart, indexStart+1)
  s[8] = s[13] = s[18] = s[23] = '-'
  return s.join('')
}

function Decrypt (word, key, iv) {
  let key = CryptoJS.enc.Utf8.parse(key)
  let base64 = CryptoJS.enc.Base64.parse(word)
  let src = CryptoJS.enc.Base64.stringify(base64)
  var decrypt = CryptoJS.AES.decrypt(src, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding })
  var decryptedStr = decrypt.toString(CryptoJS.enc.Utf8)
  return decryptedStr.toString()
}

function Encrypt (word, key, iv) {
  let key = CryptoJS.enc.Utf8.parse(key)
  let src = CryptoJS.enc.Utf8.parse(word)
  var encrypted = CryptoJS.AES.encrypt(src, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.ZeroPadding })
  return CryptoJS.enc.Base64.stringify(encrypted.ciphertext)
}

export default {
  Decrypt,
  Encrypt,
  GetRandomNum,
  GetUuid,
}

        rsaUtils.js:

import JSEncrypt from 'jsencrypt'

const pubKey = `MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMYWwlqtkWIdA0I/54TP/k1VLgyNwzQB1IvrVKdNfobivHzN02VFGAED1hDSLDiSp4yYrFcXmMFReJJOJ1zjvWECAwEAAQ==`

const encrypt = new JSEncrypt()
encrypt.setPublicKey(pubKey)

function Encrypt(str) {
	let data = encrypt.encrypt(str.toString())
	return data
}

function Decrypt(str) {
	let data = encrypt.decrypt(str.toString())
	return data
}

export default {
  Encrypt,
  Decrypt,
}

 2.前端在拦截请求处,生成AES随机秘钥并加密请求数据,再用RSA加密AES秘钥并放到请求头
        fetch.js:

const aesKeys = {}

instance.interceptors.request.use(function(request) {
	let randomKey = aes.GetRandomNum()

	let reqData
	if (request.data instanceof Object) {
		reqData = JSON.stringify(request.data)
	} else {
		reqData = request.data
	}

	request.data = aes.Encrypt(reqData, randomKey, randomKey)

	let uuid = aes.GetUuid()
	let encryptAesKey = rsa.Encrypt(randomKey)
	request.headers['EncryptAesKey'] = encryptAesKey
	request.headers['uuid'] = uuid

	aesKeys[uuid] = randomKey

	return request
}, function(err) {
	Message({
		message: err,
		type: 'error'
	})
	return Promise.reject(err)
})

instance.interceptors.response.use(function(response) {
	try {
		let uuid = response.headers['uuid']

		let aesKey = aesKeys[uuid]

		delete aesKeys[uuid]

		return JSON.parse(aes.Decrypt(response.data, aesKey, aesKey))
	} catch (e) {
		return response.data
	}
}, function(err) {
	Message({
		message: err,
		type: 'error'
	})
	return Promise.reject(err)
})

3.后端实现AES和RSA的公共方法
        AesUtils.java:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
 
import org.apache.commons.codec.binary.Base64;

public class AesUtil {
    
    public static String encrypt(String data, String key, String iv) throws Exception {
        try {
 
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            int blockSize = cipher.getBlockSize();
            byte[] dataBytes = data.getBytes();
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
            byte[] encrypted = cipher.doFinal(plaintext);
            return new Base64().encodeToString(encrypted);
 
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    
    public static String desEncrypt(String data, String key, String iv) throws Exception {
        try {
            byte[] encrypted1 = new Base64().decode(data);
            Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
            SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
            IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
            cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
            byte[] original = cipher.doFinal(encrypted1);
            String originalString = new String(original);
            return originalString.trim();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String encryptWithKey(String data, String key) throws Exception {
        return encrypt(data, key, key);
    }

    public static String desEncryptWithKey(String data, String key) throws Exception {
        return desEncrypt(data, key, key);
    }

}

        RsaUtils.java:

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.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.springframework.util.Base64Utils;

import javax.crypto.Cipher;

public class RSAUtils {
    
    /** 算法名称 */
    private static final String     ALGORITHM        = "RSA";
    /** 默认密钥大小 */
    private static final int        KEY_SIZE         = 4096;
    /** 密钥对生成器 */
    private static KeyPairGenerator keyPairGenerator = null;
    
    private static KeyFactory       keyFactory       = null;
    /** 缓存的密钥对 */
    private static KeyPair          keyPair          = null;
    
    /** Base64 编码/解码器 JDK1.8 */
    private static Base64.Decoder   decoder          = Base64.getDecoder();
    private static Base64.Encoder   encoder          = Base64.getEncoder();

    private static final String PRI_KEY = "MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAxhbCWq2RYh0DQj/nhM/+TVUuDI3DNAHUi+tUp01+huK8fM3TZUUYAQPWENIsOJKnjJisVxeYwVF4kk4nXOO9YQIDAQABAkEArOrHJBLpm0UKSDWyq2xJaEZYGVtSsD58xNtcHWN3dNRFWLZWZ9+D31OT0yE0T+dUhBVQFzHh3uDPd3Ax4STIwQIhAOPcBuFP4hoLcCPGvnvl+Co79XRKVkFtlduimiMzxg65AiEA3o2CjUz6TN51P8Q/kkPLHZHj4kB3ZPjNLNdKQusfj+kCIDe6z9/5psZR99p4OIybIYhK4+zOZaxY/ica7PIhLpbZAiEAupudZC2vktTVK2q6g0IlBd5WXlf/xMJ6B6ddtU7BYEECIEzbfR1Ac5zTrxTQ5icmD/ZRChgfhdxToGa21SQscW+K";

    public static final String PEM_CODE_PUB = "MEEwDQYJKoZIhvcNAQEBBQADMAAwLQImDr5/bK6tmdEMYTJXsD/AXIOwE2a9/bfkPvtWUR7vzkvB33tPcEsCAwEAAQ==";

    public static final String PEM_CODE_PRI = "";

    /** 初始化密钥工厂 */
    static {
        try {
            keyPairGenerator = KeyPairGenerator.getInstance(ALGORITHM);
            keyFactory = KeyFactory.getInstance(ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
    
    private RSAUtils() {
    }
    
    public static synchronized Map<String, Object> generateKeyPair() {
        try {
            keyPairGenerator.initialize(KEY_SIZE,
                new SecureRandom(UUID.randomUUID().toString().replaceAll("-", "").getBytes()));
            keyPair = keyPairGenerator.generateKeyPair();
        } catch (Exception e) {
            e.printStackTrace();
        }
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        String publicKeyString = encoder.encodeToString(rsaPublicKey.getEncoded());
        String privateKeyString = encoder.encodeToString(rsaPrivateKey.getEncoded());
        Map<String, Object> keyPairMap = new HashMap<String, Object>();
        keyPairMap.put("public", publicKeyString);
        keyPairMap.put("private", privateKeyString);
        return keyPairMap;
    }
    
    public static synchronized Map<String, Object> generatePKS1KeyPair() {
        Map<String, Object> keyPairMap = new HashMap<String, Object>();
        try {
            keyPairGenerator.initialize(KEY_SIZE,
                new SecureRandom(UUID.randomUUID().toString().replaceAll("-", "").getBytes()));
            keyPair = keyPairGenerator.generateKeyPair();
            PublicKey pub = keyPair.getPublic();
            byte[] pubBytes = pub.getEncoded();
            SubjectPublicKeyInfo spkInfo = SubjectPublicKeyInfo.getInstance(pubBytes);
            ASN1Primitive pubprimitive = spkInfo.parsePublicKey();
            byte[] publicKeyPKCS1 = pubprimitive.getEncoded();
            System.out.println(publicKeyPKCS1.toString());
            
            PrivateKey priv = keyPair.getPrivate();
            byte[] privBytes = priv.getEncoded();
            PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);
            ASN1Encodable encodable = pkInfo.parsePrivateKey();
            ASN1Primitive priprimitive = encodable.toASN1Primitive();
            byte[] privateKeyPKCS1 = priprimitive.getEncoded();
            System.out.println(privateKeyPKCS1.toString());
          
            keyPairMap.put("public", publicKeyPKCS1);
            keyPairMap.put("private", privateKeyPKCS1.toString());
        
        } catch (Exception e) {
            e.printStackTrace();
        }
        return keyPairMap;
    }
    
    public static PublicKey getPublicKey(String pubKey) {
        try {
            byte[] keyBytes = decoder.decode(pubKey);
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(keyBytes);
            return keyFactory.generatePublic(x509EncodedKeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public static PrivateKey getPrivateKey(String priKey) {
        try {
            byte[] keyBytes = decoder.decode(priKey);
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(keyBytes);
            return (java.security.interfaces.RSAPrivateKey) keyFactory
                .generatePrivate(pkcs8EncodedKeySpec);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public static String encryptByPublic(byte[] content, PublicKey publicKey) {
        if (publicKey == null) {
            publicKey = (PublicKey) getPublicKey(PEM_CODE_PUB);
        }
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            //该密钥能够加密的最大字节长度
            int splitLength = ((RSAPublicKey) publicKey).getModulus().bitLength() / 8 - 11;
            byte[][] arrays = splitBytes(content, splitLength);
            StringBuffer stringBuffer = new StringBuffer();
            for (byte[] array : arrays) {
                stringBuffer.append(Base64Utils.encodeToString(cipher.doFinal(array)));
            }
            return stringBuffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String encryptByPrivate(byte[] content, PrivateKey privateKey) {
        if (privateKey == null) {
            privateKey = (PrivateKey) getPrivateKey(PEM_CODE_PRI);
        }
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            //该密钥能够加密的最大字节长度
            int splitLength = ((RSAPrivateKey) privateKey).getModulus().bitLength() / 8 - 11;
            byte[][] arrays = splitBytes(content, splitLength);
            StringBuffer stringBuffer = new StringBuffer();
            for (byte[] array : arrays) {
                stringBuffer.append(Base64Utils.encodeToString(cipher.doFinal(array)));
            }
            return stringBuffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String decryptByPrivate(String content, PrivateKey privateKey) {
        if (privateKey == null) {
            privateKey = (PrivateKey) getPrivateKey(PEM_CODE_PRI);
        }
        try {
            Cipher cipher = Cipher.getInstance("RSA");
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            //该密钥能够加密的最大字节长度
            int splitLength = ((RSAPrivateKey) privateKey).getModulus().bitLength() / 8;
            byte[] contentBytes = Base64Utils.decodeFromString(content);
            byte[][] arrays = splitBytes(contentBytes, splitLength);
            StringBuffer stringBuffer = new StringBuffer();
            for (byte[] array : arrays) {
                stringBuffer.append(new String(cipher.doFinal(array)));
            }
            return stringBuffer.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public static byte[][] splitBytes(byte[] bytes, int splitLength) {
        //bytes与splitLength的余数
        int remainder = bytes.length % splitLength;
        //数据拆分后的组数,余数不为0时加1
        int quotient = remainder != 0 ? bytes.length / splitLength + 1
            : bytes.length / splitLength;
        byte[][] arrays = new byte[quotient][];
        byte[] array = null;
        for (int i = 0; i < quotient; i++) {
            //如果是最后一组(quotient-1),同时余数不等于0,就将最后一组设置为remainder的长度
            if (i == quotient - 1 && remainder != 0) {
                array = new byte[remainder];
                System.arraycopy(bytes, i * splitLength, array, 0, remainder);
            } else {
                array = new byte[splitLength];
                System.arraycopy(bytes, i * splitLength, array, 0, splitLength);
            }
            arrays[i] = array;
        }
        return arrays;
    }

}

4.后端重写HttpServletRequestWrapper中的getInputStream(),解密拿到请求的明文

import org.apache.commons.lang3.StringUtils;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class XssRequestWrappers extends HttpServletRequestWrapper {
    public XssRequestWrappers(HttpServletRequest request) {
        super(request);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        Map<String, String> headerMap = getHeadersInfo((HttpServletRequest) super.getRequest());

        String encryptAeskey = headerMap.get("encryptaeskey");
        String aesKey = RSAUtils.decryptByPrivate(encryptAeskey, RSAUtils.getPrivateKey(CommConstants.RSA.PRI_KEY));

        ServletInputStream servletInputStream = super.getInputStream();

        try {
            return decryptReqData(servletInputStream, aesKey);
        } catch (Exception e) {
            e.printStackTrace();
        }

        return servletInputStream;
    }

    private ServletInputStream decryptReqData(ServletInputStream servletInputStream, String aesKey)
            throws Exception {
        StringBuilder jb = new StringBuilder();
        String line;
        BufferedReader reader = new BufferedReader(new InputStreamReader(servletInputStream));
        while ((line = reader.readLine()) != null) {
            jb.append(line);
        }
        String encryptReqData = jb.toString();

        if(StringUtils.isNotBlank(encryptReqData)) {
            String reqData = AesUtil.desEncryptWithKey(encryptReqData, aesKey);
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(reqData.getBytes(StandardCharsets.UTF_8));
            return new ServletInputStream() {
                @Override
                public int read() {
                    return byteArrayInputStream.read();
                }
                @Override
                public boolean isFinished() {
                    return false;
                }
                @Override
                public boolean isReady() {
                    return false;
                }
                @Override
                public void setReadListener(ReadListener listener) {
                }
            };
        }
        return servletInputStream;
    }

    private Map<String, String> getHeadersInfo(HttpServletRequest request) {
        Map<String, String> map = new HashMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        Locale.setDefault(Locale.ENGLISH);
        while (headerNames.hasMoreElements()) {
            String key = headerNames.nextElement().toLowerCase(Locale.ENGLISH);
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return map;
    }
}

5.通过ResponseBodyAdvice给响应数据加密处理

import org.apache.commons.lang3.StringUtils;
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.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.annotation.ControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@ControllerAdvice
public class ResponseBodyAdvice implements org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice<Object> {
 
    @Override
    public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
 
    try {
           ServletServerHttpRequest request = (ServletServerHttpRequest)serverHttpRequest;
           HttpServletRequest servletRequest = request.getServletRequest();
           Map<String, String> headerNames = RequestUtils.getHeadersInfo(servletRequest);

           String encryptAeskey = headerNames.get("encryptaeskey");
           String aesKey = RSAUtils.decryptByPrivate(encryptAeskey, RSAUtils.getPrivateKey(CommConstants.RSA.PRI_KEY));

           String uuid = headerNames.get("uuid");
           serverHttpResponse.getHeaders().add("uuid", uuid);
           ArrayList<String> list = new ArrayList<>();
           list.add("uuid");
           serverHttpResponse.getHeaders().setAccessControlExposeHeaders(list);

           return AesUtil.encryptWithKey(String.valueOf(o), aesKey);
	   } catch (Exception e) {
		   e.printStackTrace();
	   }
       return o;
    }

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }
}


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA-WEB项目中,前后台结合AES和RSA对数据加密处理 的相关文章

  • AWS服务器,如何设置成密码登录

    公司一直有AWS服务器 但是每次启动的实例都是通过秘钥进行登录的 这里写个文章说明一下 如何将秘钥登录的服务器修改成密码登录 1 在新服务器中 创建root账户的密码 使用命令 sudo passwd root 按照步骤进行设置 2 设置完
  • 跨境独立站引流怎么做?必看的高转化教学

    熟悉跨境外贸的小伙伴应该清楚 不同于国内消费者习惯于在购物平台消费 国外买家大多喜欢登录品牌独立网站 独立站 进行购物 这也是许多跨境小伙伴入局独立站的原因之一 但是 即使你拥有一个精美的网站 如果没有足够的流量它也不会取得成功 因此 辛苦
  • 手把手实现语义分割项目

    手把手视频讲解 代码讲解 1 如何实现输入 完全免费解析直达 致力干货分享 2 如何实现模型 完全免费解析直达 致力干货分享 3 如何实现输出 完全免费解析直达 致力干货分享 截图如下 基础知识必备 Pytorch数据加载顺序 使用pyto

随机推荐

  • cf体验服老显示与服务器出现异常,穿越火线体验服出现网络异常

    我女神是taylor 回答数 4 被采纳数 133 2019 04 29 12 44 53 一天朋友求救说自己的机器无法运行游戏了 我询问具体情况 他刚买了一块赛扬 850 装上后DF3 DF1都不能玩了 二话没说拿起我的工具包就直奔现场
  • IT运维管理体系建设规划

    更多专业文档请访问 www itilzj com 公众号回复 218 获取高清pdf版本 福利 圈子构建 学习资料获取 1000 份重磅材料已分享 ITIL4 PPT教材 试题 视频 信息化 IT运维管理各类文档解决方案报告等 ITIL 培
  • HTML+CSS制作网页推广界面

    今天这个网页 其实用以前的基本方法也可以做出来 在这里主要是用到了CSS3的新特性font face以及fontawesome的应用 HTML部分 这一部分的主要框架如下图 黑色的div里面存放的是英文 h3和p标记存放的相应的文字 紫色的
  • 模型选择,深度学习常用定理,单层感知器实现多元输入一元输出的线性回归问题

    前言 这是补的昨天的学习内容总结 算下来有两天没更了 那两天 第一天我上午做了一上午实验 晚上开了一晚上的大创组会 收获也颇丰 第二天我码了一点代码 后来发现matlab有工具箱能直接预测 又试了下工具箱 因为内容较为简单 便没有写一篇总结
  • Linux终端连接工具-MobaXterm

    一 下载安装 1 下载地址 MobaXterm Xserver with SSH telnet RDP VNC and X11 Download 这里我下载的是左侧的免费版本 已经足够日志工作中查看日志了 二 基本操作 1 连接服务器 下载
  • GPIO引脚的模式设置:开漏、推挽、拉高、拉低、中断输入、串行通信、模拟输入输出、容错输入、PWM输出。过零检测介绍。

    开漏输出 软件 将GPIO口设置为开漏输出模式 可以实现开漏输出控制方式 输出电平只能被拉低 而不能被拉高 在使用开漏输出时 需要外部接上一个上拉电阻 将输出电平拉高到高电平 开漏输出常用于驱动I2C总线 LED灯等场景中 硬件设置为开漏输
  • a标签加入单击事件 屏蔽href跳转页面

    本文转载至 http blog 163 com huang qy blog static 615601452012101411625600 我们常用的在a标签中有点击事件 1 a href javascript js method 这是我们
  • Java 方法

    方法概述 方法 Method 是将具有独立功能的代码块组织成为一个整体 使其具有特殊功能的代码集 方法必须先创建才可以使用 该过程称为方法定义 方法创建后并不是直接运行的 需要手动使用后才执行 该过程称为方法调用 方法的定义和调用 格式 1
  • RAIN{INDIE} 自动寻路

    Unity游戏中有较多的自动寻路插件 看过几个 大同小异 而RAIN中的Behavior Tree感觉很好 听名字就知道很条理 下面 就用它做个简单的寻路小例子 首先 导入RAIN的包 结构如下 在使用的过程当中还会产生几个文件夹用来存放E
  • Go: 协程的生命周期管理

    协程的生命周期 1 定义 协程的创建等全部生命历程的管理 通俗的讲就是 保姆 它的作用是便于协程的回收利用 goroutine申请的代价很小 但是在go程序中 goroutine的总量是有上限 超过上限 多余出来的协程就得等到前面的协程完成
  • jszip 解压压缩包_一文彻底弄懂jszip中的压缩与解压

    最近在做一个类似离线包的需求 平时我们正常工作中是开发完成一个完整的SPA之后打包上线 由于我们暂时没有服务器的资源 所以目前采取的一个方案是把这个SPA打包为一个zip包 然后上传至CDN 别人用的时候直接从CDN拉包然后解压就可以了 这
  • equals,contentEquals

    直接看源码 还是挺好看的
  • docker配置nginx并绑定域名和映射网站目录

    1 拉取nginx镜像 docker pull nginx 2 映射docker中nginx容器html目录到服务器html配置目录 docker run name my nginx d p 80 80 v data nginx html
  • pip镜像源大全及配置

    在中国使用pip时 可以配置国内镜像源来提高安装速度和稳定性 以下是一些常见的国内镜像源 阿里云 https mirrors aliyun com pypi simple 清华大学 https pypi tuna tsinghua edu
  • Cpp学习——类与对象3

    目录 一 初始化列表 1 初始化列表的使用 2 初始化列表的特点 3 必须要使用初始化列表的场景 二 单参数构造函数的隐式类型转换 1 内置类型的隐式类型转换 2 自定义类型的隐式类型转换 3 多参数构造函数的隐式类型转换 4 当你不想要发
  • 0343基于STM32单片机的茶园大棚环境土壤湿度光强WiFi监测系统proteus仿真原理图PCB

    功能介绍 0 本系统采用STM32F103RCT6作为单片机 1 采用的LCD1602液晶实时显示当前光强土壤湿度等参数信息 2 当土壤湿度超过设定的阈值 蜂鸣器报警 同时控制水泵工作状态 3 按键可更改环境参数的阈值 4 通过WiFi模块
  • 简单对比一下Cookie和Session的主要区别

    一句话总结 Cookie是检查用户身上的 通行证 来确认用户的身份 Session就是通过检查服务器上的 客户明细表 来确认用户的身份的 Session相当于在服务器中建立了一份 客户明细表 注释 300 20 4kb
  • 记录使用fiddle对夜神模拟器抓包相关设置

    在网上百度很多 试了不少 最后试到这个时 成功实现对模拟器的抓包操作 以此记录 注意 设置完后 不开启 Fiddle 的话 模拟器就不能上网了 可以通过再把网络配置 改回去 就可以恢复网络正常访问了 一 配置Fiddle参数设置 1 Too
  • find命令详解

    前言 find命令是我们日常工作中比较常用的Linux命令 全面的掌握这个命令可以使很多操作达到事半功倍的效果 如果对find命令有以下这些疑惑 本文都能帮你解决 find命令的格式是什么 参数中出现 或 号是什么意思 比如find mti
  • JAVA-WEB项目中,前后台结合AES和RSA对数据加密处理

    实际项目中为了系统安全 我们经常需要对请求数据和响应数据做加密处理 这里以spring后台 vue前台的java web为例 记录一个实现过程 一 为什么要结合AES和RSA 因为AES是对称加密 即加密解密用的秘钥是一样 这样一来AES的