//微信扫码支付主要为返回预生成交易链接,所以需要生成二维码,前端可使用jquery.QRcode.js进行生成
//主要的Controller
package Controllers;
import Entity.UnifiedOrderRequest;
import Entity.UnifiedOrderRespose;
import com.alibaba.fastjson.JSONObject;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.thoughtworks.xstream.io.xml.XppDriver;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import utils.MD5Util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.*;
@Controller
@RequestMapping("/createQRCode")
public class createQRCode {
@RequestMapping(method = RequestMethod.GET, value = "/pay", produces = "text/plain;charset=GBK")
public ModelAndView createCheck(){
ModelAndView view = new ModelAndView();
view.setViewName("forward:/jsp/wxPay.jsp");
return view ;
}
/***
* 查询订单
* @param map
* @param response
* @param request
* @return
*/
@ResponseBody
@RequestMapping(method = RequestMethod.POST, value = "/payCheck", produces = "text/plain;charset=GBK")
public String payCheck(@RequestBody Map<String,String> map, HttpServletResponse response, HttpServletRequest request){
try {
String tradeNo = map.get("tradeNo");
//生成订单
String orderInfo = createSearchOrderInfo(tradeNo);
//调统一下单API
UnifiedOrderRespose code_return = httpSearchOrder(orderInfo);
JSONObject return_flag = new JSONObject();
if (code_return == null) {
return_flag.put("msg", 0);
} else {
return_flag.put("msg", code_return.getTrade_state_desc());
}
return return_flag.toString();
}catch (Exception e) {
e.printStackTrace();
JSONObject return_flag = new JSONObject();
return_flag.put("msg", 0);
return return_flag.toString();
}
}
/***
* 返回订单交易链接
* @param map
* @param response
* @param request
* @return
*/
@ResponseBody
@RequestMapping(method = RequestMethod.POST, value = "/check", produces = "text/plain;charset=GBK")
public String createCheck(@RequestBody Map<String,String> map, HttpServletResponse response, HttpServletRequest request){
try {
String Ip = null;
if (request.getHeader("x-forwarded-for") == null) {
Ip = request.getRemoteAddr();
} else {
Ip = request.getHeader("x-forwarded-for");
}
String money = map.get("money");
String tradeNo = map.get("tradeNo");
String name = map.get("name");
String realMoney = String.valueOf((int) (Float.parseFloat(money) * 100));
//生成订单
String orderInfo = createOrderInfo(Ip, realMoney, tradeNo, name);
//调统一下单API
String code_url = httpOrder(orderInfo);
JSONObject return_flag = new JSONObject();
if (code_url.equals("0")) {
return_flag.put("msg", 0);
} else {
return_flag.put("msg", code_url);
}
return return_flag.toString();
}catch (Exception e) {
e.printStackTrace();
JSONObject return_flag = new JSONObject();
return_flag.put("msg", 0);
return return_flag.toString();
}
}
/**
* 生成订单
* @param
* @return
*/
private String createOrderInfo(String IP, String money, String tradeNo, String name){
//生成订单对象
UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();
unifiedOrderRequest.setAppid("");//公众账号ID
unifiedOrderRequest.setMch_id("");//商户号
unifiedOrderRequest.setNonce_str(makeUUID());//随机字符串
unifiedOrderRequest.setBody(name);//商品描述
unifiedOrderRequest.setOut_trade_no(tradeNo);//商户订单号
unifiedOrderRequest.setTotal_fee(money); //金额需要扩大100倍:1代表支付时是0.01
unifiedOrderRequest.setSpbill_create_ip(IP);//终端IP
unifiedOrderRequest.setNotify_url("");//通知地址,虽然有,但仍需通过查询订单的方式进行确认状态
unifiedOrderRequest.setTrade_type("NATIVE");//JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付
unifiedOrderRequest.setSign(createSign(unifiedOrderRequest));//签名说明5(见文末,签名方法一并给出)
//将订单对象转为xml格式
XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
return xStream.toXML(unifiedOrderRequest);
}
/***
*生成查询订单序列化
* @param tradeNo
* @return
*/
private String createSearchOrderInfo(String tradeNo){
//生成订单对象
UnifiedOrderRequest unifiedOrderRequest = new UnifiedOrderRequest();
unifiedOrderRequest.setAppid("");//公众账号ID
unifiedOrderRequest.setMch_id("");//商户号
unifiedOrderRequest.setNonce_str(makeUUID());//随机字符串
unifiedOrderRequest.setOut_trade_no(tradeNo);//商户订单号
unifiedOrderRequest.setSign(createSearchSign(unifiedOrderRequest));//签名说明5(见文末,签名方法一并给出)
//将订单对象转为xml格式
XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));
xStream.alias("xml", UnifiedOrderRequest.class);//根元素名需要是xml
return xStream.toXML(unifiedOrderRequest);
}
/**
* 调统一下单API
* @param orderInfo
* @return
*/
private String httpOrder(String orderInfo) {
String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
//加入数据
conn.setRequestMethod("POST");
conn.setDoOutput(true);
BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());
buffOutStr.write(orderInfo.getBytes("UTF-8"));
buffOutStr.flush();
buffOutStr.close();
//获取输入流
InputStream is = null;
BufferedReader reader = null;
is = conn.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
// BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
StringBuffer sb = new StringBuffer();
while((line = reader.readLine())!= null){
sb.append(line);
}
XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));//说明3(见文末)
//将请求返回的内容通过xStream转换为UnifiedOrderRespose对象
xStream.alias("xml", UnifiedOrderRespose.class);
UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());
//根据微信文档return_code 和result_code都为SUCCESS的时候才会返回code_url
if(null!=unifiedOrderRespose
&& "SUCCESS".equals(unifiedOrderRespose.getReturn_code())
&& "SUCCESS".equals(unifiedOrderRespose.getResult_code())){
return unifiedOrderRespose.getCode_url();
}else{
return "0";
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 调统一下单API
* @param orderInfo
* @return
*/
private UnifiedOrderRespose httpSearchOrder(String orderInfo) {
String url = "https://api.mch.weixin.qq.com/pay/orderquery";
try {
HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
//加入数据
conn.setRequestMethod("POST");
conn.setDoOutput(true);
BufferedOutputStream buffOutStr = new BufferedOutputStream(conn.getOutputStream());
buffOutStr.write(orderInfo.getBytes("UTF-8"));
buffOutStr.flush();
buffOutStr.close();
//获取输入流
InputStream is = null;
BufferedReader reader = null;
is = conn.getInputStream();
reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
// BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line = null;
StringBuffer sb = new StringBuffer();
while((line = reader.readLine())!= null){
sb.append(line);
}
XStream xStream = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-", "_")));//说明3(见文末)
//将请求返回的内容通过xStream转换为UnifiedOrderRespose对象
xStream.alias("xml", UnifiedOrderRespose.class);
UnifiedOrderRespose unifiedOrderRespose = (UnifiedOrderRespose) xStream.fromXML(sb.toString());
//根据微信文档return_code 和result_code都为SUCCESS的时候
if(null!=unifiedOrderRespose
&& "SUCCESS".equals(unifiedOrderRespose.getReturn_code())
&& "SUCCESS".equals(unifiedOrderRespose.getResult_code())){
return unifiedOrderRespose;
}else{
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 创建UUID
* @return
*/
public static synchronized String makeUUID() {
Date date = new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
StringBuffer s = new StringBuffer(dateFormat.format(date));
return s.append((new Random().nextInt(900) + 100)).toString();
}
/**
* 生成签名
* @return
*/
private String createSign(UnifiedOrderRequest unifiedOrderRequest) {
//根据规则创建可排序的map集合
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", unifiedOrderRequest.getAppid());
packageParams.put("body", unifiedOrderRequest.getBody());
packageParams.put("mch_id", unifiedOrderRequest.getMch_id());
packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());
packageParams.put("notify_url", unifiedOrderRequest.getNotify_url());
packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());
packageParams.put("spbill_create_ip", unifiedOrderRequest.getSpbill_create_ip());
packageParams.put("trade_type", unifiedOrderRequest.getTrade_type());
packageParams.put("total_fee", unifiedOrderRequest.getTotal_fee());
StringBuffer sb = new StringBuffer();
Set es = packageParams.entrySet();//字典序
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
//为空不参与签名、参数名区分大小写
if (null != v && !"".equals(v) && !"sign".equals(k)
&& !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
//第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
sb.append("key=" +"");
String sign = MD5Util.MD5Encode(sb.toString(), "utf-8")
.toUpperCase();//MD5加密
return sign;
}
/***
* 生成查询订单签名
* @param unifiedOrderRequest
* @return
*/
private String createSearchSign(UnifiedOrderRequest unifiedOrderRequest) {
//根据规则创建可排序的map集合
SortedMap<String, String> packageParams = new TreeMap<String, String>();
packageParams.put("appid", unifiedOrderRequest.getAppid());
packageParams.put("mch_id", unifiedOrderRequest.getMch_id());
packageParams.put("nonce_str", unifiedOrderRequest.getNonce_str());
packageParams.put("out_trade_no", unifiedOrderRequest.getOut_trade_no());
StringBuffer sb = new StringBuffer();
Set es = packageParams.entrySet();//字典序
Iterator it = es.iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = (String) entry.getKey();
String v = (String) entry.getValue();
//为空不参与签名、参数名区分大小写
if (null != v && !"".equals(v) && !"sign".equals(k)
&& !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
//第二步拼接key,key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
sb.append("key=" +"");
String sign = MD5Util.MD5Encode(sb.toString(), "utf-8")
.toUpperCase();//MD5加密
return sign;
}
}
//定义请求的实体类
package Entity;
/**
* 统一下单请求参数(必填)
* @author moucong
*
*/
public class UnifiedOrderRequest {
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 getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
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 getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getSpbill_create_ip() {
return spbill_create_ip;
}
public void setSpbill_create_ip(String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public String getNotify_url() {
return notify_url;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
private String appid; //公众账号ID
private String mch_id; //商户号
private String nonce_str; //随机字符串
private String sign; //签名
private String body; //商品描述
private String out_trade_no; //商户订单号
private String total_fee; //总金额
private String spbill_create_ip; //终端IP
private String notify_url; //通知地址
private String trade_type; //交易类型
}
//返回接收数据的实体类
package Entity;
/**
* 统一下单返回参数
* @author moucong
*
*/
public class UnifiedOrderRespose {
private String return_code; //返回状态码
private String return_msg; //返回信息
private String appid; //公众账号ID
private String mch_id; //商户号
private String device_info; //设备号
private String nonce_str; //随机字符串
private String sign; //签名
private String result_code; //业务结果
private String err_code; //错误代码
private String err_code_des; //错误代码描述
private String trade_type; //交易类型
private String prepay_id; //预支付交易会话标识
private String code_url; //二维码链接
private String total_fee; //总金额
private String out_trade_no; //商户订单号
private String trade_state; //交易状态
private String trade_state_desc; //交易状态描述
private String openid; //用户标识
private String is_subscribe; //是否关注公众账号
private String bank_type; //付款银行
private String cash_fee; //现金支付金额
private String transaction_id; //微信支付订单号
private String time_end; //支付完成时间
private String fee_type; //标价币种
private String attach; //附加数据
private String cash_fee_type; //现金支付币种
private String coupon_fee; //代金券金额
private String coupon_count; //代金券使用数量
private String coupon_type_$n; //代金券类型
private String coupon_id_$n; //代金券ID
private String coupon_fee_$n; //单个代金券支付金额
public String getCash_fee_type() {
return cash_fee_type;
}
public void setCash_fee_type(String cash_fee_type) {
this.cash_fee_type = cash_fee_type;
}
public String getCoupon_fee() {
return coupon_fee;
}
public void setCoupon_fee(String coupon_fee) {
this.coupon_fee = coupon_fee;
}
public String getCoupon_count() {
return coupon_count;
}
public void setCoupon_count(String coupon_count) {
this.coupon_count = coupon_count;
}
public String getCoupon_type_$n() {
return coupon_type_$n;
}
public void setCoupon_type_$n(String coupon_type_$n) {
this.coupon_type_$n = coupon_type_$n;
}
public String getCoupon_id_$n() {
return coupon_id_$n;
}
public void setCoupon_id_$n(String coupon_id_$n) {
this.coupon_id_$n = coupon_id_$n;
}
public String getCoupon_fee_$n() {
return coupon_fee_$n;
}
public void setCoupon_fee_$n(String coupon_fee_$n) {
this.coupon_fee_$n = coupon_fee_$n;
}
public String getAttach() {
return attach;
}
public void setAttach(String attach) {
this.attach = attach;
}
public String getFee_type() {
return fee_type;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public String getReturn_code() {
return return_code;
}
public void setReturn_code(String return_code) {
this.return_code = return_code;
}
public String getReturn_msg() {
return return_msg;
}
public void setReturn_msg(String return_msg) {
this.return_msg = return_msg;
}
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 getDevice_info() {
return device_info;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
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 getErr_code() {
return err_code;
}
public void setErr_code(String err_code) {
this.err_code = err_code;
}
public String getErr_code_des() {
return err_code_des;
}
public void setErr_code_des(String err_code_des) {
this.err_code_des = err_code_des;
}
public String getTrade_type() {
return trade_type;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public String getPrepay_id() {
return prepay_id;
}
public void setPrepay_id(String prepay_id) {
this.prepay_id = prepay_id;
}
public String getCode_url() {
return code_url;
}
public void setCode_url(String code_url) {
this.code_url = code_url;
}
public String getIs_subscribe() {
return is_subscribe;
}
public void setIs_subscribe(String is_subscribe) {
this.is_subscribe = is_subscribe;
}
public String getBank_type() {
return bank_type;
}
public void setBank_type(String bank_type) {
this.bank_type = bank_type;
}
public String getCash_fee() {
return cash_fee;
}
public void setCash_fee(String 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 getTime_end() {
return time_end;
}
public void setTime_end(String time_end) {
this.time_end = time_end;
}
public String getOpenid() {
return openid;
}
public void setOpenid(String openid) {
this.openid = openid;
}
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;
}
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 getTotal_fee() {
return total_fee;
}
public void setTotal_fee(String total_fee) {
this.total_fee = total_fee;
}
public String getTrade_state() {
return trade_state;
}
public void setTrade_state(String trade_state) {
this.trade_state = trade_state;
}
}
//MD5算法
package utils;
import java.security.MessageDigest;
/**
* ***************************************************
*
* @Auther: zianY -.-- .- -. --. --.. .. .- -.
* @Descipion: MD5
* @CreateDate: 2019-12-19
* ****************************************************
*/
public class MD5Util {
public static void main(String[] args) {
// 99B26BE5F5F7AF4A576DFB6DF0DD38FF
System.out.println(MD5EncodeUtf8("123456"));
}
private static String byteArrayToHexString(byte b[]) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++)
resultSb.append(byteToHexString(b[i]));
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n += 256;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
/**
* 返回大写MD5
*
* @param origin
* @param charsetname
* @return
*/
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = origin;
MessageDigest md = MessageDigest.getInstance("MD5");
if (charsetname == null || "".equals(charsetname))
resultString = byteArrayToHexString(md.digest(resultString.getBytes()));
else
resultString = byteArrayToHexString(md.digest(resultString.getBytes(charsetname)));
} catch (Exception exception) {
}
return resultString.toUpperCase();
}
/**
* @param origin
* @return
*/
public static String MD5EncodeUtf8(String origin) {
origin = origin + "323@#@$1234da";
return MD5Encode(origin.trim(), "utf-8");
}
private static final String hexDigits[] = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
}