背景
商城项目客户需要提现功能,之前没有对接过,也遇到了一些小问题,防止以后出问题,这里做下简单记录。第一次写可能不是特别好,希望大家能够指出,一起进步。
准备
-
获取微信商户证书
获取方式:微信商户后台-》账户中心-》API安全-》申请证书
-
微信证书转16进制字符串存储(感谢 CS*N-代码风)
try {
FileInputStream file = new FileInputStream("E://xxx.p12");
String s1 = Hex.encodeHexString(StreamUtils.copyToByteArray(file));
System.out.println(s1);
} catch (Exception e) {
e.printStackTrace();
}
}
image.png
-
商户APIkey
微信商户后台-》账户中心-》API安全-》API秘钥(没有的话生成一个)
使用条件
- 商户号(或同主体其他非服务商商户号)已入驻90日
- 截止今日回推30天,商户号(或同主体其他非服务商商户号)连续不间断保持有交易
- 登录微信支付商户平台-产品中心,开通企业付款。
(否则接口会返回没有权限,而且需要注意的是,未达到条件的微信商户,无法在产品中心看到该功能)
1.企业付款到零钱
- API调用类
/**
* 企业付款到零钱
* @param vo
* @param mchApiKey
* 必传参数
* vo => mch_appid 申请商户号的appid或商户号绑定的appid 微信appid 小程序appid
* mchid 商户号id
* partner_trade_no 商户订单号
* openid 用户openid
* amount 金额 单位 分
* desc 备注
* @return
*/
public static Map<String,Object> cashTransfers(TransfresParamsVo vo, String mchApiKey){
Map<String,Object> returnMap = null; //返回结果
try {
//计算签名
vo.setNonce_str(RandomUtil.randomString(32)); //随机字符串
//实体类转map 工具包 hutool
Map<String,Object> paramMap = BeanUtil.beanToMap(vo);
//获取签名
String sign = WechatSginUtils.getWechatPaySignStr(paramMap , mchApiKey);
vo.setSign(sign); //设置签名
//对象转xml ture:是否去掉默认报文头 true去掉
String apiParamXml = XmlUtils.beanToXml(vo, TransfresParamsVo.class, true);
logger.info("transfresParams:{}", apiParamXml);
//提交请求
String reponseStr = HttpRequest.sendP12PostRequest(WECHAT_TRANSFRES_API, WECHAT_CRET_P12, apiParamXml, vo.getMchid());
//xml转map
returnMap = XmlUtils.xml2map(reponseStr, false);
} catch (JAXBException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return returnMap;
}
- 参数实体类
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* 微信提现到零钱参数
*/
@XmlRootElement(name = "xml") //实体转xml时的根节点
public class TransfresParamsVo {
private String mch_appid; //申请商户号的appid或商户号绑定的appid 微信appid 小程序appid
private String mchid; //商户号id
private String nonce_str; //随机字符串
private String sign; //签名
private String partner_trade_no; //商户订单号
private String openid; //用户openid
private String check_name = "NO_CHECK"; //校验用户姓名选项 NO_CHECK 不校验真实姓名 FORCE_CHECK:强校验真实姓名
private int amount; //金额 单位 分
private String desc; //备注
@XmlElement(name="mch_appid")
public String getMch_appid() {
return mch_appid;
}
public void setMch_appid(String mch_appid) {
this.mch_appid = mch_appid;
}
@XmlElement(name="mchid")
public String getMchid() {
return mchid;
}
public void setMchid(String mchid) {
this.mchid = mchid;
}
@XmlElement(name="nonce_str")
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
@XmlElement(name="sign")
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
@XmlElement(name="partner_trade_no")
public String getPartner_trade_no() {
return partner_trade_no;
}
public void setPartner_trade_no(String partner_trade_no) {
this.partner_trade_no = partner_trade_no;
}
@XmlElement(name="openid")
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
@XmlElement(name="check_name")
public String getCheck_name() {
return check_name;
}
public void setCheck_name(String check_name) {
this.check_name = check_name;
}
@XmlElement(name="amount")
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
@XmlElement(name="desc")
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
2.企业付款到银行卡
接口: https://api.mch.weixin.qq.com/mmpaysptrans/pay_bank
是否需要证书:需要
按照常用惯例,得吐槽一下,微信文档,真的有点折磨人,本来俩个小时搞定的事情,偏偏因为一个小问题多花了一个小时,微信文档真不适合小白看。
与付款到零钱不同,付款到银行卡需要提供 银行卡号,收款方用户名(废话),且在微信传参时 RSA加密,而这个RSA加密,需要调用 接口 获取 微信方的RSA公钥;然后按照下面的方式,对字符进行处理:
- 调用获取RSA公钥API获取RSA公钥,落地成本地文件,假设为public.pem
- 确定public.pem文件的存放路径,同时修改代码中文件的输入路径,加载RSA公钥
- 用标准的RSA加密库对敏感信息进行加密,选择RSA_PKCS1_OAEP_PADDING填充模式
(eg:Java的填充方式要选 " RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING")- 得到进行rsa加密并转base64之后的密文
- 将密文传给微信侧相应字段,如付款接口(enc_bank_no/enc_true_name)
(我星星特m的星星)
- 获取微信RSA公钥
public static void main(String[] args) throws Exception {
Map<String, Object> map = new HashMap<>();
map.put("mch_id","***");
map.put("nonce_str",RandomUtil.randomString(32));
map.put("sign_type","MD5");
String sign =WechatSginUtils.getWechatPaySignStr(map, "*****");
map.put("sign", sign);
Map<String, Object> map2 = map;
String apiParamXml = XmlUtils.map2XmlString(map2); //对象转xml
//带证书请求获取RSA公钥
String reponseStr = HttpRequest.sendP12PostRequest("https://fraud.mch.weixin.qq.com/risk/getpublickey", WECHAT_CRET_P12, apiParamXml, "1584991451");
System.out.println(reponseStr);
}
- 获取到的RSA公钥转一下 PKCS#8 这里我用的网页转的:传送门
- 转换前:
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQC9XrJWcWbj0LhDBzN4uwEOLA/UJKmCkkbvlVgN/qei3e/jVFpx
R6D3fzshnv5QNB4+BJ/rjRWbbxCJ0djzPxsLS1dJ+bDwagZWZ9hNXARTq4K0uxw6
Ol5jGD9Od6w5n5uxyaEk9/edvYwMhthIxC/uADRp2pNSutwyLX3bUJnHZwIDAQAB
AoGANN3S+7788my6hDvmarYKPWKfqKHzkLg1hX0z7/Q/6H/9EIHkHevZTD8AywoQ
BWQHbVjtLF1ewt3myBMFdiMP8UOx0WVErcyuVRh8AUcRZIEwz73jmLmpRd8fVAzy
8uoijKvExt/fdu9aIfVmV4nXvL5dDpsoL/mVRDgNCZ+9mMECQQDzWLnqty25mgEs
73rJ8mhehifwblg44uO+9xpmKZhG3NFZW+beG1iPZklBVlaQ6m53e77VbVotC+LF
efsaOtU7AkEAxzd3q0REhF/FaFcq9TV3Eu3C4B/aqARKgkpJKiaCC4tnAqny7Rvd
/anxLBf8DFPYjPMkPrNqXoDA8rAC9TwDxQJBAPF6mHOMdvl5E7WNp6GCxYMXScbT
GQTKUgoMl8vNdujK84vjIMRDCqyyaftGO/zuRdSXnZWZQCT3aH9iPoWW4EUCQB1r
NYLXK/8YXYCRDsjzQkhLUDHkwld5er9O1QsicKXfyjB8hGE7ckbZZ8IJMLFpWFtI
NJwFxrl57gRotacdW7kCP2r3MkJqtHdrjUbaCJJCnHmX9BhYcBhaYS2yGFW9uyNT
5TGOrrzjz+CXBNrif3JkDbDYv2z/cCgd7kqV1kPl/g==
-----END RSA PRIVATE KEY-----
- 转换后
-----BEGIN PRIVATE KEY-----
MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAL1eslZxZuPQuEMH
M3i7AQ4sD9QkqYKSRu+VWA3+p6Ld7+NUWnFHoPd/OyGe/lA0Hj4En+uNFZtvEInR
2PM/GwtLV0n5sPBqBlZn2E1cBFOrgrS7HDo6XmMYP053rDmfm7HJoST39529jAyG
2EjEL+4ANGnak1K63DItfdtQmcdnAgMBAAECgYA03dL7vvzybLqEO+Zqtgo9Yp+o
ofOQuDWFfTPv9D/of/0QgeQd69lMPwDLChAFZAdtWO0sXV7C3ebIEwV2Iw/xQ7HR
ZUStzK5VGHwBRxFkgTDPveOYualF3x9UDPLy6iKMq8TG399271oh9WZXide8vl0O
mygv+ZVEOA0Jn72YwQJBAPNYueq3LbmaASzvesnyaF6GJ/BuWDji4773GmYpmEbc
0Vlb5t4bWI9mSUFWVpDqbnd7vtVtWi0L4sV5+xo61TsCQQDHN3erRESEX8VoVyr1
NXcS7cLgH9qoBEqCSkkqJoILi2cCqfLtG939qfEsF/wMU9iM8yQ+s2pegMDysAL1
PAPFAkEA8XqYc4x2+XkTtY2noYLFgxdJxtMZBMpSCgyXy8126Mrzi+MgxEMKrLJp
+0Y7/O5F1JedlZlAJPdof2I+hZbgRQJAHWs1gtcr/xhdgJEOyPNCSEtQMeTCV3l6
v07VCyJwpd/KMHyEYTtyRtlnwgkwsWlYW0g0nAXGuXnuBGi1px1buQI/avcyQmq0
d2uNRtoIkkKceZf0GFhwGFphLbIYVb27I1PlMY6uvOPP4JcE2uJ/cmQNsNi/bP9w
KB3uSpXWQ+X+
-----END PRIVATE KEY-----
-
获取到pks8私钥后你可以转存文件xxx.pem,或者用静态常量存储调用,常量存储需要去掉-----BEGIN PRIVATE KEY----- -----END PRIVATE KEY-----,只留下中间的字符
image.png -
API调用
/**
* 企业付款到银行卡
* @param vo
* @param mchApiKey
* @return
*/
public static Map<String, Object> cashPayBank(CashPayBankVo vo, String mchApiKey){
Map<String, Object> returnMap = null; //返回结果
try {
//银行卡用户名称 RSA加密
String enctrueName = WechatRsaUtils.encrypt(vo.getEnc_true_name().getBytes("UTF-8"), WechatRsaUtils.loadPublicKey(WECHAT_PUB_KEY));//rsa公钥加密 用户名称
String encBankNo = WechatRsaUtils.encrypt(vo.getEnc_bank_no().getBytes("UTF-8"), WechatRsaUtils.loadPublicKey(WECHAT_PUB_KEY)); //rsa公钥加密 用户银行卡
vo.setEnc_true_name(Base64.encode(enctrueName)); //用户名称 base64
vo.setEnc_bank_no(Base64.encode(encBankNo)); //用户银行卡 base64
vo.setNonce_str(RandomUtil.randomString(32)); //随机字符串
//获取签名
vo.setSign(WechatSginUtils.getWechatPaySignStr(BeanUtil.beanToMap(vo), mchApiKey)); //签名
//对象转xml
String apiParamXml = XmlUtils.beanToXml(vo, CashPayBankVo.class, true); //对象转xml
logger.info("cashPayBank:{}", apiParamXml);
//提交请求
String reponseStr = HttpRequest.sendP12PostRequest(WECHAT_PAYBANK_API, WECHAT_CRET_P12, apiParamXml, vo.getMch_id());
//xml转map
returnMap = XmlUtils.xml2map(reponseStr, false);
} catch (Exception e) {
e.printStackTrace();
}
return returnMap;
}
- 参数实体类
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* 企业付款到银行卡 参数对象
*/
@XmlRootElement(name = "xml")
public class CashPayBankVo {
private String mch_id; //商户号
private String partner_trade_no; //商户企业付款单号
private String nonce_str; //随机字符串
private String sign; //签名
private String enc_bank_no; //收款方银行卡号
private String enc_true_name; //收款方用户名
private String bank_code; //收款方开户行
private int amount; //付款金额 单位 分
private String desc; //付款说明
@XmlElement(name="sign")
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
@XmlElement(name="amount")
public int getAmount() {
return amount;
}
public void setAmount(int amount) {
this.amount = amount;
}
@XmlElement(name="desc")
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@XmlElement(name="mch_id")
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
@XmlElement(name="partner_trade_no")
public String getPartner_trade_no() {
return partner_trade_no;
}
public void setPartner_trade_no(String partner_trade_no) {
this.partner_trade_no = partner_trade_no;
}
@XmlElement(name="nonce_str")
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
@XmlElement(name="enc_bank_no")
public String getEnc_bank_no() {
return enc_bank_no;
}
public void setEnc_bank_no(String enc_bank_no) {
this.enc_bank_no = enc_bank_no;
}
@XmlElement(name="enc_true_name")
public String getEnc_true_name() {
return enc_true_name;
}
public void setEnc_true_name(String enc_true_name) {
this.enc_true_name = enc_true_name;
}
@XmlElement(name="bank_code")
public String getBank_code() {
return bank_code;
}
public void setBank_code(String bank_code) {
this.bank_code = bank_code;
}
}
3.工具类
工具包:Hutool
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.9</version>
</dependency>
- xml工具类
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.*;
/**
* xml工具类
*/
public class XmlUtils {
/**
* 实体转xml
* @param obj
* @param load
* @param is_fragment 是否去掉默认报文头
* @return
* @throws JAXBException
*/
public static String beanToXml(Object obj, Class<?> load, boolean is_fragment) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(load);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, is_fragment);
StringWriter writer = new StringWriter();
marshaller.marshal(obj,writer);
return writer.toString();
}
/**
* xml字符转对象
* @param xmlStr
* @param load
* @return
* @throws JAXBException
*/
public static Object xmlToBean(String xmlStr, Class<?> load) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(load);
// 进行将Xml转成对象的核心接口
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader sr = new StringReader(xmlStr);
return unmarshaller.unmarshal(sr);
}
/**
* map 转xml
* @param map
* @return
*/
public static String map2XmlString(Map<String, Object> map) {
String xmlResult = "";
StringBuffer sb = new StringBuffer();
sb.append("<xml>");
for (String key : map.keySet()) {
String value = "<![CDATA[" + map.get(key) + "]]>";
sb.append("<" + key + ">" + value + "</" + key + ">");
}
sb.append("</xml>");
xmlResult = sb.toString();
return xmlResult;
}
/**
* xml转map 不带属性
* @param xmlStr
* @param needRootKey 是否需要在返回的map里加根节点键
* @return
*/
public static Map xml2map(String xmlStr, boolean needRootKey) {
Map<String, Object> map = null;
try {
Document doc = DocumentHelper.parseText(xmlStr);
Element root = doc.getRootElement();
map = (Map<String, Object>) xml2map(root);
if(root.elements().size()==0 && root.attributes().size()==0){
return map;
}
if(needRootKey){
//在返回的map里加根节点键(如果需要)
Map<String, Object> rootMap = new HashMap<String, Object>();
rootMap.put(root.getName(), map);
return rootMap;
}
} catch (DocumentException e) {
e.printStackTrace();
}
return map;
}
/**
* xml转map 不带属性
* @param e
* @return
*/
private static Map xml2map(Element e) {
Map map = new LinkedHashMap();
List list = e.elements();
if (list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
Element iter = (Element) list.get(i);
List mapList = new ArrayList();
if (iter.elements().size() > 0) {
Map m = xml2map(iter);
if (map.get(iter.getName()) != null) {
Object obj = map.get(iter.getName());
if (!(obj instanceof List)) {
mapList = new ArrayList();
mapList.add(obj);
mapList.add(m);
}
if (obj instanceof List) {
mapList = (List) obj;
mapList.add(m);
}
map.put(iter.getName(), mapList);
} else
map.put(iter.getName(), m);
} else {
if (map.get(iter.getName()) != null) {
Object obj = map.get(iter.getName());
if (!(obj instanceof List)) {
mapList = new ArrayList();
mapList.add(obj);
mapList.add(iter.getText());
}
if (obj instanceof List) {
mapList = (List) obj;
mapList.add(iter.getText());
}
map.put(iter.getName(), mapList);
} else
map.put(iter.getName(), iter.getText());
}
}
} else
map.put(e.getName(), e.getText());
return map;
}
}
- 微信签名工具类
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.jeespring.common.security.MD5Tools;
import com.jeespring.common.weike.wechat.config.WechatApiContext;
import com.jeespring.common.weike.wechat.vo.pay.WechatSignVo;
import java.util.*;
public class WechatSginUtils {
/**
* 获取微信支付签名
* @param paramMap
* @param mchApiKey
* @return
* @throws Exception
*/
public static String getWechatPaySignStr(Map<String,Object> paramMap ,String mchApiKey) throws Exception{
StringBuffer sbuff = new StringBuffer();
//字典排序
List<String> paramsList = new ArrayList<>(paramMap.keySet());
Collections.sort(paramsList);
for (int i = 0; i < paramsList.size(); i++){
String key = paramsList.get(i);
Object val = paramMap.get(key);
if (val != null){
sbuff.append(key);
sbuff.append("=");
sbuff.append(val);
sbuff.append("&");
}
}
//拼接商户APIkey
sbuff.append("key=".concat(mchApiKey));
//签名MD5转大写加密
String sign = MD5Tools.MD5(sbuff.toString()).toUpperCase();
return sign;
}
/**
* 预支付返回签名
* @param vo
* @param mchApiKey
* @throws Exception
*/
public static void getWechatReturnSgin(WechatSignVo vo , String mchApiKey) throws Exception{
StringBuffer sbuff = new StringBuffer();
//随机字符串
vo.setNonceStr(RandomUtil.randomString(32));
//字典排序
Map<String,Object> paramMap = BeanUtil.beanToMap(vo);
List<String> paramsList = new ArrayList<>(paramMap.keySet());
Collections.sort(paramsList);
for (int i = 0; i < paramsList.size(); i++){
String key = paramsList.get(i);
Object val = paramMap.get(key);
if (val != null){
if ((WechatApiContext.WECHAT_PAY_SGIN_PACKAGE_SGINSTR.concat("Str")).equals(key)){
key = WechatApiContext.WECHAT_PAY_SGIN_PACKAGE_SGINSTR;
}
sbuff.append(key);
sbuff.append("=");
sbuff.append(val);
sbuff.append("&");
}
}
//拼接商户APIkey
sbuff.append("key=".concat(mchApiKey));
//签名MD5转大写加密
String sign = MD5Tools.MD5(sbuff.toString()).toUpperCase();
vo.setPaySign(sign);
}
}
- RSA工具类
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import static com.jeespring.common.utils.Encodes.decodeBase64;
public class WechatRsaUtils {
private static String RSA = "RSA";
private static final int KEYLENGTH = 2048;
private static final int RESERVESIZE = 11;
/**
* 指定填充模式
*/
private static final String CIPHERALGORITHM = "RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING";
/**
* 用公钥加密 <br>
* 每次加密的字节数,不能超过密钥的长度值减去11
*
* @param plainBytes 需加密数据的byte数据
* @param publicKey 公钥
* @return 加密后的byte型数据
*/
public static String encrypt(byte[] plainBytes, PublicKey publicKey) throws Exception {
int keyByteSize = KEYLENGTH / 8;
int encryptBlockSize = keyByteSize - RESERVESIZE;
int nBlock = plainBytes.length / encryptBlockSize;
if ((plainBytes.length % encryptBlockSize) != 0) {
nBlock += 1;
}
ByteArrayOutputStream outbuf = null;
try {
Cipher cipher = Cipher.getInstance(CIPHERALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
outbuf = new ByteArrayOutputStream(nBlock * keyByteSize);
for (int offset = 0; offset < plainBytes.length; offset += encryptBlockSize) {
int inputLen = plainBytes.length - offset;
if (inputLen > encryptBlockSize) {
inputLen = encryptBlockSize;
}
byte[] encryptedBlock = cipher.doFinal(plainBytes, offset, inputLen);
outbuf.write(encryptedBlock);
}
outbuf.flush();
byte[] encryptedData = outbuf.toByteArray();
return Base64.encodeBase64String(encryptedData);
} catch (Exception e) {
throw new Exception("ENCRYPT ERROR:", e);
} finally {
try {
if (outbuf != null) {
outbuf.close();
}
} catch (Exception e) {
throw new Exception("CLOSE ByteArrayOutputStream ERROR:", e);
}
}
}
/**
* 从字符串中加载公钥
*
* @param publicKeyStr 公钥数据字符串
* @throws Exception 加载公钥时产生的异常
*/
public static PublicKey loadPublicKey(String publicKeyStr){
PublicKey publicKey = null;
try {
byte[] buffer = decodeBase64(publicKeyStr);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
publicKey = keyFactory.generatePublic(keySpec);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
} catch (NullPointerException e) {
e.printStackTrace();
}
return publicKey;
}
}
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Hex;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
import java.util.Map;
public class HttpRequest {
/**
* 向指定URL发送GET方法的请求
*
* @param url
* 发送请求的URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return URL 所代表远程资源的响应结果
*/
public static String sendGet(String url, String param) {
String result = "";
BufferedReader in = null;
try {
String urlNameString = url + "?" + param;
URL realUrl = new URL(urlNameString);
// 打开和URL之间的连接
URLConnection connection = realUrl.openConnection();
// 设置通用的请求属性
connection.setRequestProperty("accept", "*/*");
connection.setRequestProperty("connection", "Keep-Alive");
connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 建立实际的连接
connection.connect();
// 获取所有响应头字段
//Map<String, List<String>> map = connection.getHeaderFields();
// 遍历所有的响应头字段
//for (String key : map.keySet()) {
// System.out.println(key + "--->" + map.get(key));
//}
// 定义 BufferedReader输入流来读取URL的响应
in = new BufferedReader(new InputStreamReader(
connection.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送GET请求出现异常!" + e.toString());
result="Down";
//e.printStackTrace();
}
// 使用finally块来关闭输入流
finally {
try {
if (in != null) {
in.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
return result;
}
/**
* 向指定 URL 发送POST方法的请求
*
* @param url
* 发送请求的 URL
* @param param
* 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
* @return 所代表远程资源的响应结果
*/
public static String sendPost(String url, String param) {
PrintWriter out = null;
BufferedReader in = null;
String result = "";
try {
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
// 获取URLConnection对象对应的输出流
out = new PrintWriter(conn.getOutputStream());
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
// 定义BufferedReader输入流来读取URL的响应
in = new BufferedReader(
new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result += line;
}
} catch (Exception e) {
System.out.println("发送 POST 请求出现异常!"+e.toString());
//e.printStackTrace();
}
//使用finally块来关闭输出流、输入流
finally{
try{
if(out!=null){
out.close();
}
if(in!=null){
in.close();
}
}
catch(IOException ex){
ex.printStackTrace();
}
}
return result;
}
public static String sendP12PostRequest(String url, String cretCode, String param, String cretkey){
CloseableHttpClient client = null;
HttpPost httpPost = null;
try {
//解析证书
byte[] bytes = Hex.decodeHex(cretCode.toCharArray()); //解密出16进制原证书文件内容为字节数组
ByteArrayInputStream input = new ByteArrayInputStream(bytes); //读取字节数组
KeyStore clientTrustKeyStore = KeyStore.getInstance("PKCS12"); //获取PKCS12秘钥库实例
clientTrustKeyStore.load(input, cretkey.toCharArray()); //秘钥解析
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(clientTrustKeyStore, cretkey.toCharArray());
TrustManager[] tm = {new MyX509TrustManager()};
SSLContext sslContext = SSLContext.getInstance("TLSv1");
sslContext.init(kmf.getKeyManagers(), tm, new java.security.SecureRandom());
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
client = HttpClients.custom().setSSLSocketFactory(sslsf).build();
httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(param, "utf-8"));
CloseableHttpResponse response = client.execute(httpPost);
StatusLine statusLine = response.getStatusLine();
HttpEntity entity = response.getEntity();
if (statusLine.getStatusCode() == 200) {
return EntityUtils.toString(entity, "utf-8");
}
} catch (DecoderException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return null;
}
public static String getParameterMapString(HttpServletRequest request){
if(request.getQueryString()!=null){
if(request.getQueryString().length()>0){
return request.getQueryString();
}
}
Map map = request.getParameterMap();
java.util.Enumeration enumx = request.getParameterNames();
String result="";
while(enumx.hasMoreElements()){
String paramName=(String)enumx.nextElement();
String[] values=request.getParameterValues(paramName);
for(int i=0;i<values.length;i++){
result+=paramName+"="+values[i]+"&";
}
}
return result;
}
private static class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
}
网友评论