1、基本配置
package com.jbossjf.bootproject.common.weixin;
public class Configure {
private static String appID = "2222b78a36297d4444";
private static String secret = "3333ce6787950b8e98d6371b7777777";
//商户号
private static String mch_id = "7771978999";//"你的商户号";
private static String key = "66662ac5b14cc3ad76ef9d77777777";//"你的商户的api秘钥";
//
public static String getSecret() {
return secret;
}
public static void setSecret(String secret) {
Configure.secret = secret;
}
public static String getKey() {
return key;
}
public static void setKey(String key) {
Configure.key = key;
}
public static String getAppID() {
return appID;
}
public static void setAppID(String appID) {
Configure.appID = appID;
}
public static String getMch_id() {
return mch_id;
}
public static void setMch_id(String mch_id) {
Configure.mch_id = mch_id;
}
}
2、帮助类
package com.jbossjf.bootproject.common.weixin;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
public class HttpRequest {
//连接超时时间,默认10秒
private static final int socketTimeout = 10000;
//传输超时时间,默认30秒
private static final int connectTimeout = 30000;
/**
* post请求
* @throws IOException
* @throws ClientProtocolException
* @throws NoSuchAlgorithmException
* @throws KeyStoreException
* @throws KeyManagementException
* @throws UnrecoverableKeyException
*/
public static String sendPost(String url, Object xmlObj) throws ClientProtocolException, IOException, UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException {
HttpPost httpPost = new HttpPost(url);
//解决XStream对出现双下划线的bug
XStream xStreamForRequestPostData = new XStream(new DomDriver("UTF-8", new XmlFriendlyNameCoder("-_", "_")));
xStreamForRequestPostData.alias("xml", xmlObj.getClass());
//将要提交给API的数据对象转换成XML格式数据Post给API
String postDataXML = xStreamForRequestPostData.toXML(xmlObj);
//得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
StringEntity postEntity = new StringEntity(postDataXML, "UTF-8");
httpPost.addHeader("Content-Type", "text/xml");
httpPost.setEntity(postEntity);
//设置请求器的配置
RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
httpPost.setConfig(requestConfig);
HttpClient httpClient = HttpClients.createDefault();
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity, "UTF-8");
return result;
}
/**
* 自定义证书管理器,信任所有证书
* @author pc
*
*/
public static class MyX509TrustManager implements X509TrustManager {
@Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] arg0, String arg1)
throws CertificateException {
// TODO Auto-generated method stub
}
@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
// TODO Auto-generated method stub
return null;
}
}
}
package com.jbossjf.bootproject.common.weixin;
import java.security.MessageDigest;
/**
* User: rizenguo
* Date: 2014/10/23
* Time: 15:43
*/
public class MD5 {
private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "a", "b", "c", "d", "e", "f"};
/**
* 转换字节数组为16进制字串
* @param b 字节数组
* @return 16进制字串
*/
public static String byteArrayToHexString(byte[] b) {
StringBuilder resultSb = new StringBuilder();
for (byte aB : b) {
resultSb.append(byteToHexString(aB));
}
return resultSb.toString();
}
/**
* 转换byte到16进制
* @param b 要转换的byte
* @return 16进制格式
*/
private static String byteToHexString(byte b) {
int n = b;
if (n < 0) {
n = 256 + n;
}
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
/**
* MD5编码
* @param origin 原始字符串
* @return 经过MD5加密之后的结果
*/
public static String MD5Encode(String origin) {
String resultString = null;
try {
resultString = origin;
MessageDigest md = MessageDigest.getInstance("MD5");
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
} catch (Exception e) {
e.printStackTrace();
}
return resultString;
}
}
package com.jbossjf.bootproject.common.weixin;
public class QueryOrderRequest {
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
// 公众账号id
private String appid;
// 商户号
private String mch_id;
// 商户订单号,32位以内,不重复
private String out_trade_no;
// 随机字符串,32位以内
private String nonce_str;
// 签名,遵循签名算法
private String sign;
}
package com.jbossjf.bootproject.common.weixin;
public class QueryOrderRequestExt extends QueryOrderRequest {
// 签名类型,默认MD5
private String sign_type;
}
package com.jbossjf.bootproject.common.weixin;
public class QueryOrderResponse {
public String getReturn_code() {
return return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getMch_id() {
return mch_id;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public String getNonce_str() {
return nonce_str;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getResult_code() {
return result_code;
}
public void setResult_code(String result_code) {
this.result_code = result_code;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getTrade_state() {
return trade_state;
}
public void setTrade_state(String trade_state) {
this.trade_state = trade_state;
}
public String getBank_type() {
return bank_type;
}
public void setBank_type(String bank_type) {
this.bank_type = bank_type;
}
public int getTotal_fee() {
return total_fee;
}
public void setTotal_fee(int total_fee) {
this.total_fee = total_fee;
}
public int getCash_fee() {
return cash_fee;
}
public void setCash_fee(int cash_fee) {
this.cash_fee = cash_fee;
}
public String getTransaction_id() {
return transaction_id;
}
public void setTransaction_id(String transaction_id) {
this.transaction_id = transaction_id;
}
public String getOut_trade_no() {
return out_trade_no;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public String getTime_end() {
return time_end;
}
public void setTime_end(String time_end) {
this.time_end = time_end;
}
public String getTrade_state_desc() {
return trade_state_desc;
}
public void setTrade_state_desc(String trade_state_desc) {
this.trade_state_desc = trade_state_desc;
}
// 返回状态码,通信标识,SUCCESS/FAIL
private String return_code;
// 公众账号id
private String appid;
// 商户号
private String mch_id;
// 随机字符串
private String nonce_str;
// 签名
private String sign;
// 业务结果,交易标识,SUCCESS/FAIL
private String result_code;
// 用户标识
private String openid;
// 交易类型,JSAPI,NATIVE,APP
private String trade_type;
// SUCCESS--支付成功
// REFUND--转入退款
// NOTPAY--未支付
// CLOSED--已关闭
// REVOKED--已撤销(刷卡支付)
// USERPAYING--用户支付中
// PAYERROR--支付失败(其他原因,如银行返回失败)
// ACCEPT--已接收,等待扣款
private String trade_state;
// 付款银行
private String bank_type;
// 标价金额,单位分
private int total_fee;
// 现金支付金额
private int cash_fee;
// 微信支付订单号
private String transaction_id;
// 商户订单号
private String out_trade_no;
// 支付完成时间
private String time_end;
// 交易状态描述
private String trade_state_desc;
}
package com.jbossjf.bootproject.common.weixin;
public class QueryOrderResponseExt extends QueryOrderResponse {
// 返回信息,非空则表示返回了错误信息
private String return_msg;
// 错误代码
private String err_code;
// 错误代码描述
private String err_code_des;
// 设备号
private String device_info;
// 是否关注公众号
private String is_subscribe;
// 应结订单金额
private String settlement_total_fee;
// 标价币种
private String fee_type;
// 现金支付币种
private String cash_fee_type;
// 附加数据
private String attach;
}
package com.jbossjf.bootproject.common.weixin;
import java.util.Random;
/**
* 随机字符串生成
* @author zuoliangzhu
*
*/
public class RandomStringGenerator {
/**
* 获取一定长度的随机字符串
* @param length 指定字符串长度
* @return 一定长度的字符串
*/
public static String getRandomStringByLength(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}
package com.jbossjf.bootproject.common.weixin;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
/**
* 签名
* @author zuoliangzhu
*
*/
public class Signature {
private static final Logger L = LoggerFactory.getLogger(Signature.class);
/**
* 签名算法
* @param o 要参与签名的数据对象
* @return 签名
* @throws IllegalAccessException
*/
public static String getSign(Object o) throws IllegalAccessException {
ArrayList<String> list = new ArrayList<String>();
Class cls = o.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field f : fields) {
f.setAccessible(true);
if (f.get(o) != null && f.get(o) != "") {
String name = f.getName();
XStreamAlias anno = f.getAnnotation(XStreamAlias.class);
if(anno != null)
name = anno.value();
list.add(name + "=" + f.get(o) + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
result += "key=" + Configure.getKey();
System.out.println("签名数据:"+result);
result = MD5.MD5Encode(result).toUpperCase();
return result;
}
public static String getSign(Map<String,Object> map){
ArrayList<String> list = new ArrayList<String>();
for(Map.Entry<String,Object> entry:map.entrySet()){
if(entry.getValue()!=""){
list.add(entry.getKey() + "=" + entry.getValue() + "&");
}
}
int size = list.size();
String [] arrayToSort = list.toArray(new String[size]);
Arrays.sort(arrayToSort, String.CASE_INSENSITIVE_ORDER);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < size; i ++) {
sb.append(arrayToSort[i]);
}
String result = sb.toString();
result += "key=" + Configure.getKey();
//Util.log("Sign Before MD5:" + result);
result = MD5.MD5Encode(result).toUpperCase();
//Util.log("Sign Result:" + result);
return result;
}
}
package com.jbossjf.bootproject.common.weixin;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public class StreamUtil {
public static String read(InputStream is){
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len = 0;
byte[] buffer = new byte[512];
while((len = is.read(buffer)) != -1){
baos.write(buffer, 0, len);
}
return new String(baos.toByteArray(), 0, baos.size(), "utf-8");
}catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return "";
}
}
package com.jbossjf.bootproject.common.weixin;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class WechatConnection {
// 成功标志
public static final String SUCCESS_CODE = "SUCCESS";
/**
* 建立微信连接,并返回结果
*
* @param url
* @param info
* @param object
* @return
* @throws IOException
*/
public static Object connect(String url, String info, Class<?> object) throws IOException {
// 建立连接
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setConnectTimeout(8000);
conn.setRequestMethod("POST");
conn.setDoOutput(true);
// 发送数据
BufferedOutputStream bos = new BufferedOutputStream(conn.getOutputStream());
bos.write(info.getBytes());
bos.flush();
bos.close();
// 获取数据
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
// 接收数据
String line;
StringBuffer str = new StringBuffer();
while ((line = reader.readLine()) != null) {
str.append(line);
}
return WechatUtil.truncateDataFromXML(object, str.toString());
}
}
package com.jbossjf.bootproject.common.weixin;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.XmlFriendlyReplacer;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.beans.BeanMap;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
public class WechatUtil {
private static Logger logger = LoggerFactory.getLogger(WechatUtil.class);
/**
* 数据转换为xml格式
*
* @param object
* @param obj
* @return
*/
public static String truncateDataToXML(Class<?> object, Object obj) {
XStream xStream = new XStream(new XppDriver(new XmlFriendlyReplacer("_-", "_")));
xStream.alias("xml", object);
return xStream.toXML(obj);
}
/**
* 数据转换为对象
*
* @param object
* @param str
* @return
*/
public static Object truncateDataFromXML(Class<?> object, String str) {
XStream xStream = new XStream(new XppDriver(new XmlFriendlyReplacer("_-", "_")));
xStream.alias("xml", object);
return xStream.fromXML(str);
}
/**
* 生成随机字符串
*
* @return
*/
public static String makeNonceStr() {
SimpleDateFormat sdf1=new SimpleDateFormat("yyyyMMddHHmmssS");
StringBuffer str = new StringBuffer(sdf1.format(new Date()));
str.append((new Random().nextInt(900) + 100));
return str.toString();
}
/**
* 拼接签名数据
*
* @return
*/
public static String makeSign(BeanMap beanMap) {
SortedMap<String, String> signMaps =new TreeMap();;
for (Object key : beanMap.keySet()) {
Object value = beanMap.get(key);
// 排除空数据
if (value == null) {
continue;
}
signMaps.put(key + "", String.valueOf(value));
}
// 生成签名
return generateSign(signMaps);
}
/**
* 生成签名
*
* @param signMaps
* @return
* @throws Exception
*/
public static String generateSign(SortedMap<String, String> signMaps) {
StringBuffer sb = new StringBuffer();
// 字典序
for (Map.Entry signMap : signMaps.entrySet()) {
String key = (String) signMap.getKey();
String value = (String) signMap.getValue();
// 为空不参与签名、参数名区分大小写
if (null != value && !"".equals(value) && !"sign".equals(key) && !"key".equals(key)) {
sb.append(key).append("=").append(value).append("&");
}
}
// 拼接key
sb.append("key=").append(Configure.getKey());
// MD5加密
return Objects.requireNonNull(encoderByMd5(sb.toString())).toUpperCase();
}
/**
* 利用MD5进行加密
*
* @param str 待加密的字符串
* @return 加密后的字符串
*/
private static String encoderByMd5(String str) {
// 生成一个MD5加密计算摘要
MessageDigest md = null;
try {
md = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
logger.error("MD5加密失败!", e);
}
if (md == null) {
return null;
}
// 计算md5函数
md.update(str.getBytes());
// digest()最后确定返回md5 hash值,返回值为8为字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符
// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值
return new BigInteger(1, md.digest()).toString(16);
}
}
3、调用
package com.jbossjf.bootproject.controller;
import com.alibaba.fastjson.JSONObject;
import com.jbossjf.bootproject.common.weixin.*;
import com.jbossjf.bootproject.model.TrandeForm;
import com.jbossjf.bootproject.service.TrandeFormService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class WeixinSearchController
{
@Autowired
private TrandeFormService trandeFormService;
Logger logger = LoggerFactory.getLogger(getClass());
TrandeForm trandeForm = null;
private String generateOrderInfo(String orderId) {
trandeForm = trandeFormService.GetByTrandeNo(orderId);
QueryOrderRequestExt ext = new QueryOrderRequestExt();
ext.setAppid(Configure.getAppID());
ext.setMch_id(Configure.getMch_id());
ext.setOut_trade_no(trandeForm.getTradeNo());
ext.setNonce_str(WechatUtil.makeNonceStr());
ext.setSign(WechatUtil.makeSign(BeanMap.create(ext)));
return WechatUtil.truncateDataToXML(QueryOrderRequestExt.class, ext);
}
@CrossOrigin
@ResponseBody
@RequestMapping(value = "/API/SearchTrandeFormByOpenID", method = RequestMethod.POST, produces = "application/json;charset=UTF-8")
public Map<String, Object> SearchTrandeFormByOpenID(@RequestBody JSONObject jsonParam) {
Map<String, Object> map = new HashMap<>();
try{
String openid = jsonParam.getString("openid");
List<TrandeForm> trandeForms = trandeFormService.findByOpenid(openid);
for(int i=0;i<trandeForms.size();i++)
{
getPayResult(trandeForms.get(i).getTradeNo());
}
}catch (Exception ex)
{
}
return null;
}
public Boolean getPayResult(String orderId) {
try {
String orderInfo = generateOrderInfo(orderId);
QueryOrderResponseExt ext = null;
try {
ext = (QueryOrderResponseExt) WechatConnection.connect("https://api.mch.weixin.qq.com/pay/orderquery", orderInfo, QueryOrderResponseExt.class);
} catch (Exception e) {
logger.error("微信查询订单" + orderId + "失败!", e);
}
if (ext == null) {
return false;
}
if (WechatConnection.SUCCESS_CODE.equals(ext.getResult_code())) {
if (WechatConnection.SUCCESS_CODE.equals(ext.getResult_code()) && WechatConnection.SUCCESS_CODE.equals(ext.getTrade_state())) {
try {
// 更新订单状态
trandeForm.setTradeStatus("SUCCESS");
trandeFormService.UpdateBean(trandeForm);
} catch (Exception ex) {
return false;
}
return true;
} else {
logger.error("订单" + orderId + "交易失败,交易状态:" + ext.getTrade_state());
return false;
}
} else {
logger.error("订单" + orderId + "查询失败!");
return false;
}
}catch (Exception ex)
{
return false;
}
}
}