微信支付有专门的文档:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1
当时找的时候都是前台如何,后来才发现后台需要做的就是统一下单
一、
先到微信下载两个证书,然后把证书放到resources下,cart是我自己建的
二、因为需要调用微信接口所以我们需要一个调用接口的工具类,下面是我的工具类
1.工具类需要的pom文件
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.48</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
2.工具类
package com.weizhang.until;
import net.sf.json.JSONObject;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.Set;
/**
*HttpClient为网络请求的工具类,网络请求的超时时间为5秒。超时、连接出现错误等,响应码非200均返回null。
*
* <b>传入的Map参数会自动转换成json格式的数据发送<b/>
*
*/
public class HttpClient {
private HttpClient(){}
public static final String METHOD_POST = "POST";
public static final String METHOD_GET = "GET";
private static final int TIME_OUT = 5000;
/**
* POST请求url,返回String 类型的结果,5秒超时,出现异常返回null
* @param url 请求路径
* @param map 请求参数封装到map中
* @return
*/
public static String forStringResult(String url,Map<String,Object> map){
return forStringResult(url,map,METHOD_POST);
}
/**
* 获取网络请求,5秒超时,出现异常返回null
* @param urlStr 请求地址
* @param map 参数封装到map
* @param method 请求方式GET或POST
* @return
*/
public static String forStringResult(String urlStr,Map<String,Object> map,String method){
String param = null;
if(map!=null){
JSONObject obj = new JSONObject();
Set<Map.Entry<String, Object>> set = map.entrySet();
for(Map.Entry<String,Object> entry :set){
obj.put(entry.getKey(),entry.getValue());
}
param = obj.toString();
}
return getResult(urlStr,param,method);
}
/**
* 返回JSON格式的结果,5秒超时,出现异常返回null
* @param url 请求url
* @param map 将参数封装到map中
* @return
*/
public static JSONObject forJsonResult(String url, Map<String,Object> map){
return forJsonResult(url,map,METHOD_POST);
}
/**
* 返回json格式的结果,5秒超时,出现异常返回null
* @param urlStr 请求url
* @param map 参数封装到map中
* @param method 请求方式GET或POST
* @return
*/
public static JSONObject forJsonResult(String urlStr,Map<String,Object> map,String method){
String result = forStringResult(urlStr,map,method);
if(result==null){
return null;
}
JSONObject jsonObject = JSONObject.fromObject(result);
return jsonObject;
}
/**
*获取网路请求,5秒超时,出现异常返回null
* @param url 请求地址
* @param param 请求参数
* @return
*/
public static String forStringResult(String url,String param){
return getResult(url,param,null);
}
/**
* 获取网络请求结果,5秒超时,出现异常返回null
* @param urlStr
* @param param
* @param method
* @return
*/
private static String getResult(String urlStr,String param,String method){
String result = null;
HttpURLConnection connection = null;
try {
if(method==null){
method = METHOD_POST;
}
// 创建连接
URL url = new URL(urlStr);
connection = (HttpURLConnection) url.openConnection();
connection.setConnectTimeout(TIME_OUT);//5秒超时
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setRequestMethod(method);
connection.setUseCaches(false);
connection.setInstanceFollowRedirects(true);
connection.setRequestProperty("Content-Type", "multipart/form-data");
connection.connect();
if(param!=null){
// POST请求
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
out.writeBytes(param);
out.flush();
out.close();
}
int responseCode = connection.getResponseCode();
if(responseCode==200){
result = inputStreamToString(connection.getInputStream());
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally{
// 断开连接
connection.disconnect();
}
return result;
}
/**
* 输入流转为String
* @param is
* @return
*/
private static String inputStreamToString(InputStream is){
// 读取响应
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String lines = "";
StringBuffer sb = new StringBuffer();
try {
while ((lines = reader.readLine()) != null) {
lines = new String(lines.getBytes(), "utf-8");
sb.append(lines);
}
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
}
三、因为微信有签名所以需要加密工具,我这里使用的事md5加密
1.pom文件
<!--MD5-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
2.md5工具类
package com.weizhang.until;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* Created by admin on 2019/7/31.
*/
public class DM5 {
//写一个md5加密的方法
public static String md5(String plainText) {
//定义一个字节数组
byte[] secretBytes = null;
try {
// 生成一个MD5加密计算摘要
MessageDigest md = MessageDigest.getInstance("MD5");
//对字符串进行加密
md.update(plainText.getBytes());
//获得加密后的数据
secretBytes = md.digest();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("没有md5这个算法!");
}
//将加密后的数据转换为16进制数字
String md5code = new BigInteger(1, secretBytes).toString(16);// 16进制数字
// 如果生成数字未满32位,需要前面补0
for (int i = 0; i < 32 - md5code.length(); i++) {
md5code = "0" + md5code;
}
return md5code;
}
}
四、下面开始正文,上代码
1.因为微信里有很多参数是固定值,所以创建一个实体类放这些值
package com.weizhang.wxpay;
/**
* Created by admin on 2019/11/11.
*/
public class Aaa {
public static String appid="小程序appid";
public static String mch_id="商户号";
public static String pay_key="商户号key";
public static String body="描述";
public static String out_trade_no="订单号";
public static Integer total_fee=金额;
public static String notify_url="回调地址,必须是外网能访问到的地址,微信需要根据这个地址调用我们的接口";
public static String trade_type="JSAPI";//请求类型 JSAPI是小程序 其他去微信文档里找
}
2.准备工作都做好了就可以直接调用了
package com.weizhang.wxpay;
import com.weizhang.until.DM5;
import com.weizhang.until.HttpClient;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* Created by admin on 2019/11/11.
*/
public class WeiXinPay {
private String url="https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单接口
public void WeiXinPayA(String IP,String openid){
Map<String,String> map = new HashMap<>();//我将所有参数放到map中了
map.put("appid",Aaa.appid);
map.put("mch_id",Aaa.mch_id);
try {
map.put("body",new String(Aaa.body.getBytes("UTF-8")));//这里需要注意,body需要提前进行utf-8转换,否则微信会报错
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
map.put("out_trade_no",Aaa.out_trade_no);
map.put("total_fee",String.valueOf(Aaa.total_fee*100));
map.put("notify_url",Aaa.notify_url);
map.put("trade_type",Aaa.trade_type);
map.put("spbill_create_ip",IP);
map.put("openid",openid);//小程序必须穿openid
String nonce_str = UUID.randomUUID().toString().substring(0,32);//生成的32位随机数
map.put("nonce_str",nonce_str);
/*这里需要将上面我们所有的参数按照字典顺序排序,必须严格按照微信文档里签名规则来*/
String signA="appid="+map.get("appid")+"&body="+map.get("body")+"&mch_id="+map.get("mch_id")+"&nonce_str="+
map.get("nonce_str")+"¬ify_url="+map.get("notify_url")+"&openid="+map.get("openid")+"&out_trade_no="+map.get("out_trade_no")+
"&spbill_create_ip="+map.get("spbill_create_ip")+"&total_fee="+map.get("total_fee")+"&trade_type="+
map.get("trade_type");
String signB=signA+"&key="+Aaa.pay_key;//前面拼接完,最后拼接商户号的key
String sign= DM5.md5(signB).toUpperCase();//将所有拼接的字符串进行md5加密,加密完转成大写
map.put("sign",sign);
/*微信传参需要穿xml格式,所以要将所有参数拼接成xml格式*/
StringBuilder xml = new StringBuilder();
xml.append("<xml>\n");
for (Map.Entry<String, String> entry : map.entrySet()) {
if ("body".equals(entry.getKey()) || "sign".equals(entry.getKey())) {
xml.append("<" + entry.getKey() + "><![CDATA[").append(entry.getValue()).append("]]></" + entry.getKey() + ">\n");
} else {
xml.append("<" + entry.getKey() + ">").append(entry.getValue()).append("</" + entry.getKey() + ">\n");
}
}
xml.append("</xml>");
String cc = HttpClient.forStringResult(url,xml.toString());//调用微信统一下单接口
System.out.println(cc);
}
}
这样主要的工作就完成了,微信回调我们接口传的也是xml格式参数,只需要接收进行一下验证是否成功就行了,然后将前台需要的参数传给前台就OK了