java 对接第三方接口

感想

这是我第一次要写对外的接口,一开始还是比较迷茫的,因为要考虑到数据的安全传输,很多技术我都还是比较的不熟悉,后来经过对每一个技术的了解,终于还是写出来了。

感觉一切都是从陌生到熟悉,再到亲切 哈哈哈哈哈

如有错误,希望指出, 共同学习

技术

我会把所有的封装的工具类都给出来

1: 使用Rsa非对称的加密算法,对传输的参数进行加密 (需要一个公钥和一个私钥)

2: 使用md5 进行加签,验证身份是否正确

3:使用hutool工具中的HttpUtil进行请求

4:http://web.chacuo.net/netrsakeypair 通过这个网址可以在线生成公钥和私钥的密钥对,一般1024位就足够了,我这边就随机生成了密钥如下

公钥:
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRgMigO0vUZCOXcSbylyBHssPh
4qNMwZLIM9pbAmUZldATE2QfI5XAwQuEeo8LapP9Mf+TxXpQytevYs+EYcvaExOe
BhJv9T6QFe2vxV6oJ+iDP2nMFGOqCK7+MJYWh4CYyl+PvuGnu+wMCDRGBI6u+09Z
w/RnlWP6MMv7KlvhawIDAQAB
私钥:
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANGAyKA7S9RkI5dx
JvKXIEeyw+Hio0zBksgz2lsCZRmV0BMTZB8jlcDBC4R6jwtqk/0x/5PFelDK169i
z4Rhy9oTE54GEm/1PpAV7a/FXqgn6IM/acwUY6oIrv4wlhaHgJjKX4++4ae77AwI
NEYEjq77T1nD9GeVY/owy/sqW+FrAgMBAAECgYBm4g+kYHpEu0ifPnoZ+A1qKGf5
rgrzzrv+hTheKTbs8Z1VQNiSUi9gkWzOikFlIdm7JaqVLw16T6LMBoJSSJSKiAwF
4KyWtbccupplAgE5LGp2tmukt4tIR+noMH/NHnxMgZ6BMGJvQd7R66hHzvU7bZkA
rNEoG78r7vBuhDPVAQJBAOl9IGCTpHxRqheiLKFxgbcdfb/3YjcjIFw4Y70BtImn
sTsykBOdPHZvWdVwT5Gg/mwhGMG10sEFXY7/xSlRXfECQQDls6bYEJXfxoHyZwFa
++NTTTEk0C9sPOl7MW6m7rLSDkUN6TS/qjyHnkPF/05FIq2LxdgX7dqpKvGI8hfu
kYkbAkBx8w8KEwQDaBeK0SrW335ez5W/Sgw0vH/egearJ1nklGJ6cYK/D82iP1Wo
RNeQSvHf84cRgpsIeIXgdBLUx1EBAkAsEFaFREk78DylX5Um+wMUy84NndI7FURE
2aq8YzXyjcI5dO8lhWavLXEa3msJYCmikoVtsbcslIxZFPf6T/jZAkBjG/bTsxDt
7v9tb20APb5O+8wHC1UKpUQ+24iAjXB4U+BXWMeTqkoYwVMv6cB/3eXSMcM2KB+M
xpFJK39x/Y9s

实战

直接上代码

//公钥, 我这边直接写在代码里面,你也可以写在一个文件里面,再去文件里面读取
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRgMigO0vUZCOXcSbylyBHssPh
4qNMwZLIM9pbAmUZldATE2QfI5XAwQuEeo8LapP9Mf+TxXpQytevYs+EYcvaExOe
BhJv9T6QFe2vxV6oJ+iDP2nMFGOqCK7+MJYWh4CYyl+PvuGnu+wMCDRGBI6u+09Z
w/RnlWP6MMv7KlvhawIDAQAB
//私钥 我这边直接写在代码里面,你也可以写在一个文件里面,再去文件里面读取
    MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANGAyKA7S9RkI5dx
JvKXIEeyw+Hio0zBksgz2lsCZRmV0BMTZB8jlcDBC4R6jwtqk/0x/5PFelDK169i
z4Rhy9oTE54GEm/1PpAV7a/FXqgn6IM/acwUY6oIrv4wlhaHgJjKX4++4ae77AwI
NEYEjq77T1nD9GeVY/owy/sqW+FrAgMBAAECgYBm4g+kYHpEu0ifPnoZ+A1qKGf5
rgrzzrv+hTheKTbs8Z1VQNiSUi9gkWzOikFlIdm7JaqVLw16T6LMBoJSSJSKiAwF
4KyWtbccupplAgE5LGp2tmukt4tIR+noMH/NHnxMgZ6BMGJvQd7R66hHzvU7bZkA
rNEoG78r7vBuhDPVAQJBAOl9IGCTpHxRqheiLKFxgbcdfb/3YjcjIFw4Y70BtImn
sTsykBOdPHZvWdVwT5Gg/mwhGMG10sEFXY7/xSlRXfECQQDls6bYEJXfxoHyZwFa
++NTTTEk0C9sPOl7MW6m7rLSDkUN6TS/qjyHnkPF/05FIq2LxdgX7dqpKvGI8hfu
kYkbAkBx8w8KEwQDaBeK0SrW335ez5W/Sgw0vH/egearJ1nklGJ6cYK/D82iP1Wo
RNeQSvHf84cRgpsIeIXgdBLUx1EBAkAsEFaFREk78DylX5Um+wMUy84NndI7FURE
2aq8YzXyjcI5dO8lhWavLXEa3msJYCmikoVtsbcslIxZFPf6T/jZAkBjG/bTsxDt
7v9tb20APb5O+8wHC1UKpUQ+24iAjXB4U+BXWMeTqkoYwVMv6cB/3eXSMcM2KB+M
xpFJK39x/Y9s
//这个key是md5加密的时候用的
 YUJDED15DDS65DHF12FHF125FHF5FFKF

controller对外接口

    //这边使用post的请求
	@PostMapping("hello")
    @Transactional
    public Object collectCpn(@RequestBody String body) {

        //这边使用jackson,将请求的json数据转为字符串
        String name = JacksonUtil.parseString(body, "name"); //名字
        String createTimeStamp = JacksonUtil.parseString(body, "create_time_stamp");//时间戳
        String sign = JacksonUtil.parseString(body, "sign");//签名

        //判断传过来的参数是否为空
        if(name.isEmpty()) {
            return "参数错误"
        }

        //参数 ascii排序 从小到大排序(除sign外)
        Map<String, Object> parameters = new TreeMap<>();
        parameters.put("name", name);
        parameters.put("create_time_stamp", createTimeStamp);
        //排序完的字符串后面添加 key的值
        String str = AsciiSortUtil.AsciiSort(parameters).append("key=" + key).toString();

        Map<String, Object> data = new HashMap<>();
        try {
            //私钥解密 请求的时候用公钥对签名进行加密,接收的时候,就需要用私钥解密
            sign = RsaUtils.decrypt(sign, rsaPrivateKey);
            //验签
            if(!Md5SignUtils.verifySign(str, key, sign)) {
                //验签失败
                return "签名错误";
            }
            //解密之后的数据 (私钥解密)
            name = RsaUtils.decrypt(name, rsaPrivateKey);

            //中间对数据库操作省略  可以对拿到的参数进行判断,处理(每个人都不同)

            //请求成功
            return "请求成功";
        }catch (Exception e){
            e.printStackTrace();
            //系统内部错误
            return ReturnUtil.errorSys(reqNo);
        }
    }

单元测试方法

private static String key = "YUJDED15DDS65DHF12FHF125FHF5FFKF";	
private static String rsaPublickKey="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDRgMigO0vUZCOXcSbylyBHssPh
4qNMwZLIM9pbAmUZldATE2QfI5XAwQuEeo8LapP9Mf+TxXpQytevYs+EYcvaExOe
BhJv9T6QFe2vxV6oJ+iDP2nMFGOqCK7+MJYWh4CYyl+PvuGnu+wMCDRGBI6u+09Z
w/RnlWP6MMv7KlvhawIDAQAB";
    
private static String url = "http://127.0.0.1:8080/hello"; //请求地址
    
	@Test
    public void test1() {
        String name = "小小";
        String create_time_stamp = DateTimeUtil.getTimeStamp(); //时间戳
        try {
            //参数加密
            name = RsaUtils.encrypt(ordnameer_no, rsaPublickKey);
            //参数 ascii排序 从小到大排序(除了sign外)
            Map<String, Object> parameters = new TreeMap<>();
            parameters.put("name", name);
            parameters.put("create_time_stamp", create_time_stamp);
			 //排序完的字符串后面添加 key的值
            String str = AsciiSortUtil.AsciiSort(parameters).append("key=" + key).toString();

            //使用md5对拼接完的字符串进行加密
            String sign = Md5SignUtils.sign(str, key).toUpperCase();
            //公钥加密
            sign = RsaUtils.encrypt(sign, rsaPublickKey); 

            Map<String, Object> data = new HashMap<>();
            data.put("name", name);
            data.put("create_time_stamp", create_time_stamp);
            data.put("sign", sign);
			//使用hutool工具包,发送post请求
            String post = HttpUtil.post(url, JSON.toJSONString(data));
			//这边就可以拿到请求返回的结果
            String code = JacksonUtil.parseString(post, "code");
            String returnSign = JacksonUtil.parseString(post, "sign");

        }catch (Exception e) {
            e.printStackTrace();
        }

    }

工具类

RsaUtils

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: Abe
 * Date: 2020/9/18 15:57
 */
public class RsaUtils {

    /**
     * RSA公钥加密
     *
     * @param str
     *            加密字符串
     * @param publicKey
     *            公钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encrypt( String str, String publicKey ) throws Exception{
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }


    /**
     * RSA私钥加密
     *
     * @param str
     *            加密字符串
     * @param privateKey
     *            私钥
     * @return 密文
     * @throws Exception
     *             加密过程中的异常信息
     */
    public static String encryptPrivateKey( String str, String privateKey) throws Exception{
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, priKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA私钥解密
     *
     * @param str
     *            加密字符串
     * @param privateKey
     *            私钥
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decrypt(String str, String privateKey) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    /**
     * RSA公钥解密
     *
     * @param str
     *            加密字符串
     * @param publicKey
     *            私钥
     * @return 铭文
     * @throws Exception
     *             解密过程中的异常信息
     */
    public static String decryptPubKey(String str, String publicKey) throws Exception{
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, pubKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

}

DateTimeUtil

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;

/**
 * 生成时间戳
 */
public class DateTimeUtil {

    /**
     * 生成时间戳
     * 格式: yyyyMMddHH24MISS 
     	说明:我这边加8个小时 是因为我线上环境的原因,你可以不用加
     *
     * @param
     * @return
     */
    public static String getTimeStamp() {
        LocalDateTime localDateTime = LocalDateTime.now().plusHours(8);
        Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());

        String timeStamp=new SimpleDateFormat("yyyyMMddHHmmss").
                format(date.getTime());
        return timeStamp;
    }

}

AsciiSortUtil

package org.linlinjava.litemall.core.util;

import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/**
 * @Author: Abe
 * Date: 2020/9/23 17:52
 */
public class AsciiSortUtil {

    /**
     * 参数名按ASCII码从小到大排序
     * @return
     */
    public static StringBuffer AsciiSort(Map<String,Object> parameters) {
        StringBuffer sbkey = new StringBuffer();
        // entrySet 所有参与传参的参数按照accsii排序(升序)
        Set es = parameters.entrySet();
        Iterator it = es.iterator();

        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            //空值不传递,不参与签名组串
            if (null != v && !"".equals(v)) {
                sbkey.append(k + "=" + v + "&");
            }
        }
//        sbkey = sbkey.append("key=" + key);
//        System.out.println(sbkey);
        return sbkey;
    }

}

Md5SignUtils

import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: Abe
 * Date: 2020/9/18 21:55
 */
public class Md5SignUtils {
    static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    static String MD5 = "MD5";//加签方式:MD5

    /*
     * @Author boy
     * @Description 数据签名
     * @Date 2019/8/31 1:57 PM
     * @Param [data, key]
     * @return java.lang.String
     */
    public static String sign(String data, String key) throws Exception {
        //得到明文的字节数组
        byte[] btInput = (data + key).getBytes();
        // 创建一个提供信息摘要算法的对象(MD5摘要算法)
        MessageDigest messageDigest = MessageDigest.getInstance(MD5);
        // 使用指定的字节更新摘要
        messageDigest.update(btInput);
        // 得到二进制的密文
        byte[] encryptData = messageDigest.digest();
        // 把密文转换成十六进制的字符串形式
        String encryptDataStr = bytesToHex(encryptData);
        return encryptDataStr;

    }

    /*
     * @Author boy
     * @Description 验签
     * @Date 2019/8/31 1:57 PM
     * @Param [data, key, sign][明文数据,签名key,接收到的签名]
     * @return boolean
     */
    public static boolean verifySign(String data, String key, String sign) throws Exception {
        //调用加签方法,看加签后的签名是否和接收到的一致
        String encryptData = sign(data, key);
        //转为大写
        encryptData = encryptData.toUpperCase();
        if (encryptData.equals(sign)) {
            return true;
        } else {
            return false;
        }
    }

    /*
     * @Author boy
     * @Description 将byte数组转化为16进制字符串
     * @Date 2019/8/31 1:58 PM
     * @Param [bytes]
     * @return java.lang.String
     */
    public static String bytesToHex(byte[] bytes) {
        int k = 0;
        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            byte byte0 = bytes[i];
            hexChars[k++] = hexDigits[byte0 >>> 4 & 0xf];
            hexChars[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(hexChars);
    }

}

JacksonUtil

package org.linlinjava.litemall.core.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.util.List;

import org.linlinjava.litemall.db.domain.LitemallUser;

public class JacksonUtil {
    public static String parseString(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);
            if (leaf != null)
                return leaf.asText();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static List<String> parseStringList(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);

            if (leaf != null)
                return mapper.convertValue(leaf, new TypeReference<List<String>>() {
                });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Integer parseInteger(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);
            if (leaf != null)
                return leaf.asInt();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static List<Integer> parseIntegerList(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);

            if (leaf != null)
                return mapper.convertValue(leaf, new TypeReference<List<Integer>>() {
                });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public static LitemallUser parseLitemallUser(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);

            if (leaf != null)
                return mapper.convertValue(leaf, new TypeReference<LitemallUser>() {
                });
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static Boolean parseBoolean(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);
            if (leaf != null)
                return leaf.asBoolean();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Short parseShort(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);
            if (leaf != null) {
                Integer value = leaf.asInt();
                return value.shortValue();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Byte parseByte(String body, String field) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            JsonNode leaf = node.get(field);
            if (leaf != null) {
                Integer value = leaf.asInt();
                return value.byteValue();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T parseObject(String body, String field, Class<T> clazz) {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode node = null;
        try {
            node = mapper.readTree(body);
            node = node.get(field);
            return mapper.treeToValue(node, clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static Object toNode(String json) {
        if (json == null) {
            return null;
        }
        ObjectMapper mapper = new ObjectMapper();
        try {
            JsonNode jsonNode = mapper.readTree(json);
            return jsonNode;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

}
  • 12
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值