1. 帮助工具
1.1. 图片上传Demo
业务中提供了图片文件上传接口,为了方便第三方业务集成图片文件上传接口,固此提供Demo示例:
1.1.1. Java版本
import com.megvii.bbu.common.util.bone.MegviiCommonErrorCode;
import com.megvii.bbu.common.util.bone.MegviiException;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import javax.net.ssl.*;
import java.io.File;
import java.net.URLEncoder;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
;
@Slf4j
public class OkHttpUtil {
private static final byte[] LOCKER = new byte[0];
private static OkHttpUtil instance;
private static OkHttpUtil httpsInstance;
private OkHttpClient okHttpClient;
private OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
TrustAllManager trustAllManager = new TrustAllManager();
TrustManager[] trustManagers = {trustAllManager};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustManagers, new java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory, trustAllManager);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private OkHttpUtil(boolean https) {
OkHttpClient.Builder builder;
if (https) {
builder = getUnsafeOkHttpClient().newBuilder();
} else {
builder = new OkHttpClient.Builder();
}
okHttpClient = builder
// 10秒连接超时
.connectTimeout(10, TimeUnit.SECONDS)
// 写入超时
.writeTimeout(900, TimeUnit.SECONDS)
// 读取超时
.readTimeout(900, TimeUnit.SECONDS).build();
}
public static OkHttpUtil getInstance() {
if (instance == null) {
synchronized (LOCKER) {
if (instance == null) {
instance = new OkHttpUtil(false);
}
}
}
return instance;
}
/**
* true -https
* false -http
*
* @param https
* @return
*/
public static OkHttpUtil getInstance(boolean https) {
if (!https) {
return getInstance();
}
if (httpsInstance == null) {
synchronized (LOCKER) {
if (httpsInstance == null) {
httpsInstance = new OkHttpUtil(https);
}
}
}
return httpsInstance;
}
public String doPostFormMultipart(String targetUrl, String fileUrl, Map<String, String> headers) {
if (isBlankUrl(targetUrl) || isBlankUrl(fileUrl)) {
return null;
}
Request request = getRequestForPostFormMultipart(targetUrl, fileUrl, headers);
return commonRequest(request);
}
private Boolean isBlankUrl(String url) {
if (StringUtils.isBlank(url)) {
log.info("url is not blank");
return true;
} else {
return false;
}
}
private String commonRequest(Request request) {
String re = "";
try (Response response = okHttpClient.newCall(request).execute()) {
if (response.isSuccessful()) {
re = response.body().string();
log.info("request url:{};response:{}", request.url().toString(), re);
} else {
log.info("request failure url:{};message:{}", request.url().toString(), response.message());
throw new Exception("code:" + response.code() + "request failure url:" + request.url().toString()
+ ";message:" + response.message());
}
} catch (Exception e) {
e.printStackTrace();
log.error("request execute failure", e);
throw new MegviiException(MegviiCommonErrorCode.SYSTEM_ERROR);
}
return re;
}
private Request getRequestForPostFormMultipart(String serverUrl, String fileUrl, Map<String, String> headers) {
if (headers == null) {
headers = new HashMap<>();
}
File file = new File(fileUrl);//文件路径(本地)
String filename = file.getName();
MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);
builder.addFormDataPart("file", filename, RequestBody.create(MediaType.parse("multipart/form-data"), file));
Request request = new Request.Builder().url(serverUrl).post(builder.build())
.addHeader("File-Length", String.valueOf(file.length())).addHeader("Content-Type", "multipart/form-data")
.header("Connection", "close").header("Accept-Encoding", "identity")
//签名
.header("cappkey", headers.get("cappkey"))
.header("ctimestamp", headers.get("ctimestamp"))
.header("cnonce", headers.get("cnonce"))
.header("csign", headers.get("csign"))
.build();
return request;
}
private Request getRequestForGet(String url, HashMap<String, String> params) {
Request request = new Request.Builder().url(getUrlStringForGet(url, params)).build();
return request;
}
private String getUrlStringForGet(String url, HashMap<String, String> params) {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(url);
urlBuilder.append("?");
if (params != null && params.size() > 0) {
for (Map.Entry<String, String> entry : params.entrySet()) {
try {
urlBuilder.append("&").append(entry.getKey()).append("=")
.append(URLEncoder.encode(entry.getValue(), "UTF-8"));
} catch (Exception e) {
urlBuilder.append("&").append(entry.getKey()).append("=").append(entry.getValue());
}
}
}
return urlBuilder.toString();
}
public static class TrustAllManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
public static void main(String[] args) {
//服务端上传接口,假设鸿图服务器地址为:10.171.16.76,以图片上传接口为例,如下:
String targetUrl = "http://10.171.16.76/v1/api/person/uploadImage";
//本地要上传的文件
String fileUrl = "C:\\Users\\work\\Desktop/2.jpg";
//签名信息
Map<String, String> files = new HashMap<>();
files.put("cappkey", "appkey1");
files.put("cnonce", "1234344");
files.put("ctimestamp", "1234344");
files.put("csign", "974228f6c7c56bb1320f8501c01aa991");
//http 地址请求 ;false 表示
String ret = OkHttpUtil.getInstance(false).doPostFormMultipart(targetUrl, fileUrl, files);
System.out.println(ret);
//https 地址请求 ;true 表示
String rets = OkHttpUtil.getInstance(true).doPostFormMultipart(targetUrl, fileUrl, files);
System.out.println(rets);
}
}
1.2. AES加解密工具类
1.2.1. Java版本
密钥需要通过Web端【系统管理-全局参数配置-完全参数配置-加密因子配置】下查看
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
/**
* AES加密器
*/
public class AESUtil {
public static final String CHAR_ENCODING = "UTF-8";
public static final String AES_ALGORITHM = "AES";
/**
* 加密
*
* @param data
* 待加密内容
* @param key
* 加密秘钥
* @return 十六进制字符串
*/
public static String encrypt(String data, String key) {
if (key.length() < 16) {
throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
} else if (key.length() > 16) {
key = key.substring(0, 16);
}
try {
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);// 创建密码器
byte[] byteContent = data.getBytes(CHAR_ENCODING);
cipher.init(Cipher.ENCRYPT_MODE, genKey(key));// 初始化
byte[] result = cipher.doFinal(byteContent);
return parseByte2HexStr(result); // 加密
} catch (Exception e) {
}
return null;
}
/**
* 解密
*
* @param data
* 待解密内容(十六进制字符串)
* @param key
* 加密秘钥
* @return
*/
public static String decrypt(String data, String key) {
if (key.length() < 16) {
throw new RuntimeException("Invalid AES key length (must be 16 bytes)");
} else if (key.length() > 16) {
key = key.substring(0, 16);
}
try {
byte[] decryptFrom = parseHexStr2Byte(data);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);// 创建密码器
cipher.init(Cipher.DECRYPT_MODE, genKey(key));// 初始化
byte[] result = cipher.doFinal(decryptFrom);
return new String(result, "utf-8"); // 加密
} catch (Exception e) {
}
return null;
}
/**
* 创建加密解密密钥
*
* @param key
* 加密解密密钥
* @return
*/
private static SecretKeySpec genKey(String key) {
SecretKeySpec secretKey;
try {
secretKey = new SecretKeySpec(key.getBytes(CHAR_ENCODING), AES_ALGORITHM);
byte[] enCodeFormat = secretKey.getEncoded();
SecretKeySpec seckey = new SecretKeySpec(enCodeFormat, AES_ALGORITHM);
return seckey;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("genKey fail!", e);
}
}
/**
* 将二进制转换成16进制
*
* @param buf
* @return
*/
private static String parseByte2HexStr(byte buf[]) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < buf.length; i++) {
String hex = Integer.toHexString(buf[i] & 0xFF);
if (hex.length() == 1) {
hex = '0' + hex;
}
sb.append(hex.toUpperCase());
}
return sb.toString();
}
/**
* 将16进制转换为二进制
*
* @param hexStr
* @return
*/
private static byte[] parseHexStr2Byte(String hexStr) {
if (hexStr.length() < 1)
return null;
byte[] result = new byte[hexStr.length() / 2];
for (int i = 0; i < hexStr.length() / 2; i++) {
int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
result[i] = (byte) (high * 16 + low);
}
return result;
}
}
AES 使用demo:
public class AesDemo {
public static void main(String[] args) {
aesEncryptDemo();
aesDecryptDemo();
}
/**
* aes解密demo
*/
public static void aesDecryptDemo() {
// 加密因子:
String key = "64d64143a0973fb8";
// 从OpenAPI 获取到的密文身份证号
String encryptIdentifyNumFromOpenAPI = "9397D1730FE8F05B391CDBADA3A2B0135DA552D20978757513C14BE3D57019D2";
// 使用aes解密得到明文身份证号
String identifyNumAfterDecrypt = AESUtil.decrypt(encryptIdentifyNumFromOpenAPI, key);
System.out.println(identifyNumAfterDecrypt);
}
/**
* aes加密demo
*/
public static void aesEncryptDemo() {
// 加密因子:
String key = "64d64143a0973fb8";
// 明文身份证号
String identifyNum = "510222199809076543";
// 使用aes加密得到密文身份证号
String encryptIdentifyNum = AESUtil.encrypt(identifyNum, key);
System.out.println(encryptIdentifyNum);
}
}
1.2.2. Go版本
密钥需要通过Web端【系统管理-全局参数配置-完全参数配置-加密因子配置】下查看
package helper
import (
"bytes"
"crypto/aes"
"encoding/hex"
"strings"
)
//使用PKCS7进行填充,IOS也是7
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
padding := blockSize - len(ciphertext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(ciphertext, padtext...)
}
func PKCS7UnPadding(origData []byte) []byte {
length := len(origData)
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}
func AESDecrypt(data, key string) string {
// 截取key的前16位
if len(key) < 16 {
panic("invalid key")
}
if len(key) > 16 {
key = key[0 : 16]
}
// 将字符串都转换成小写
data = strings.ToLower(data)
// 将字符串从16进制转换成字节数组
dataByte, err := hex.DecodeString(data)
if err != nil {
panic("hex decode error")
}
// 解密
block, _ := aes.NewCipher([]byte(key))
decrypted := make([]byte, len(dataByte))
size := block.BlockSize()
for bs, be := 0, size; bs < len(dataByte); bs, be = bs+size, be+size {
block.Decrypt(decrypted[bs:be], dataByte[bs:be])
}
decrypted = PKCS7UnPadding(decrypted)
// 将解密后的字节数组转换成字符串
return string(decrypted)
}
func AESEncrypt(data, key string) string {
// 截取key的前16位
if len(key) < 16 {
panic("invalid key")
}
if len(key) > 16 {
key = key[0 : 16]
}
// 将data 转换成字节数组
dataByte := []byte(data)
// 加密
block, _ := aes.NewCipher([]byte(key))
dataByte = PKCS7Padding(dataByte, block.BlockSize())
decrypted := make([]byte, len(dataByte))
size := block.BlockSize()
for bs, be := 0, size; bs < len(dataByte); bs, be = bs+size, be+size {
block.Encrypt(decrypted[bs:be], dataByte[bs:be])
}
// 加密后转换成十六进制并都转换成大写
return strings.ToUpper(hex.EncodeToString(decrypted))
}
AES 使用demo:
package main
import (
"fmt"
"practice/helper"
)
func main() {
// 明文
plaintext := "12300199809087766"
// 秘钥
key := "W8p102YW9AZQ117g4t4z241pr6IM9oF49Q3L4pwsuWRE0E7Z04GM1819A217"
// 进行加密
encrypt := helper.AESEncrypt(plaintext, key)
fmt.Println("加密后:", encrypt)
// 将密文进行解密
decrypt := helper.AESDecrypt(encrypt, key)
fmt.Println("解密后:", decrypt)
}