小程序支付java_Java实现小程序微信支付

这是一个Java后端实现微信小程序支付的示例代码,包括预下单接口和支付回调处理。主要涉及微信支付的相关参数设置、签名生成、XML解析等操作。
摘要由CSDN通过智能技术生成

packagecom.card.mp.controller;importcom.alibaba.fastjson.JSON;importcom.alibaba.fastjson.JSONObject;importcom.card.dto.PaymentDto;import com.card.framework.utils.*;importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.io.SAXReader;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.annotation.RequestMapping;importorg.springframework.web.bind.annotation.RequestParam;importorg.springframework.web.bind.annotation.ResponseBody;importjavax.servlet.http.HttpServletRequest;importjava.io.ByteArrayInputStream;importjava.io.InputStream;importjava.io.UnsupportedEncodingException;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.HashMap;importjava.util.List;importjava.util.Map;

@Controllerpublic class WeiXinPaymentController extendsBaseController {private final String mch_id = "填写商户号";//商户号

private final String spbill_create_ip = "填写终端IP";//终端IP

private final String notify_url = "域名/weixin/paycallback.do";//通知地址

private final String trade_type = "JSAPI";//交易类型

private final String url = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单API接口链接

private final String key = "&key=填写商户支付密钥"; //商户支付密钥

private final String appid = "填写小程序AppId";/***

*@paramopenId

*@paramtotal_fee 订单总金额,单位为分。

*@parambody 商品简单描述,该字段请按照规范传递。 例:腾讯充值中心-心悦会员充值

*@paramattach 附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用。 例:广州分店

*@return*@throwsUnsupportedEncodingException

*@throwsDocumentException*/@RequestMapping("/weixin/payment.do")

@ResponseBodypublic JSONObject payment(@RequestParam(required = true) String openId, @RequestParam(required = true)String total_fee, @RequestParam(required = false) String body, @RequestParam(required = false) String attach) throwsUnsupportedEncodingException, DocumentException {

JSONObject JsonObject= newJSONObject() ;

body= new String(body.getBytes("UTF-8"),"ISO-8859-1");

String nonce_str= UUIDHexGenerator.generate();//随机字符串

String today = new SimpleDateFormat("yyyyMMddHHmmss").format(newDate());

String code= PayUtil.createCode(8);

String out_trade_no= mch_id + today + code;//商户订单号

String openid= openId;//用户标识

PaymentDto paymentPo = newPaymentDto();

paymentPo.setAppid(appid);

paymentPo.setMch_id(mch_id);

paymentPo.setNonce_str(nonce_str);

String newbody= new String(body.getBytes("ISO-8859-1"),"UTF-8");//以utf-8编码放入paymentPo,微信支付要求字符编码统一采用UTF-8字符编码

paymentPo.setBody(newbody);

paymentPo.setOut_trade_no(out_trade_no);

paymentPo.setTotal_fee(total_fee);

paymentPo.setSpbill_create_ip(spbill_create_ip);

paymentPo.setNotify_url(notify_url);

paymentPo.setTrade_type(trade_type);

paymentPo.setOpenid(openid);//把请求参数打包成数组

Map sParaTemp = newHashMap();

sParaTemp.put("appid", paymentPo.getAppid());

sParaTemp.put("mch_id", paymentPo.getMch_id());

sParaTemp.put("nonce_str", paymentPo.getNonce_str());

sParaTemp.put("body", paymentPo.getBody());

sParaTemp.put("out_trade_no", paymentPo.getOut_trade_no());

sParaTemp.put("total_fee",paymentPo.getTotal_fee());

sParaTemp.put("spbill_create_ip", paymentPo.getSpbill_create_ip());

sParaTemp.put("notify_url",paymentPo.getNotify_url());

sParaTemp.put("trade_type", paymentPo.getTrade_type());

sParaTemp.put("openid", paymentPo.getOpenid());//除去数组中的空值和签名参数

Map sPara =PayUtil.paraFilter(sParaTemp);

String prestr= PayUtil.createLinkString(sPara); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串//MD5运算生成签名

String mysign = PayUtil.sign(prestr, key, "utf-8").toUpperCase();

paymentPo.setSign(mysign);//打包要发送的xml

String respXml =XmlUtil.messageToXML(paymentPo);//打印respXml发现,得到的xml中有“__”不对,应该替换成“_”

respXml = respXml.replace("__", "_");

String param=respXml;//String result = SendRequestForUrl.sendRequest(url, param);//发起请求

String result = PayUtil.httpRequest(url, "POST", param);

System.out.println("请求微信预支付接口,返回 result:"+result);//将解析结果存储在Map中

Map map = newHashMap();

InputStream in=newByteArrayInputStream(result.getBytes());//读取输入流

SAXReader reader = newSAXReader();

Document document=reader.read(in);//得到xml根元素

Element root =document.getRootElement();//得到根元素的所有子节点

List elementList =root.elements();for(Element element : elementList) {

map.put(element.getName(), element.getText());

}//返回信息

String return_code = map.get("return_code").toString();//返回状态码

String return_msg = map.get("return_msg").toString();//返回信息

String result_code = map.get("result_code").toString;//返回状态码

System.out.println("请求微信预支付接口,返回 code:" +return_code);

System.out.println("请求微信预支付接口,返回 msg:" +return_msg);if("SUCCESS".equals(return_code) && "SUCCESS".equals(result_code)){//业务结果

String prepay_id = map.get("prepay_id").toString();//返回的预付单信息

String nonceStr =UUIDHexGenerator.generate();

JsonObject.put("nonceStr", nonceStr);

JsonObject.put("package", "prepay_id=" +prepay_id);

Long timeStamp= System.currentTimeMillis() / 1000;

JsonObject.put("timeStamp", timeStamp + "");

String stringSignTemp= "appId=" + appid + "&nonceStr=" + nonceStr + "&package=prepay_id=" + prepay_id + "&signType=MD5&timeStamp=" +timeStamp;//再次签名

String paySign = PayUtil.sign(stringSignTemp, key, "utf-8").toUpperCase();

JsonObject.put("paySign", paySign);

}returnJsonObject;

}/*** 预支付时填写的 notify_url ,支付成功后的回调接口

*@paramrequest*/@RequestMapping("/weixin/paycallback.do")

@ResponseBodypublic voidpaycallback(HttpServletRequest request) {try{

Map dataMap =XmlUtil.parseXML(request);

System.out.println(JSON.toJSONString(dataMap));//{"transaction_id":"4200000109201805293331420304","nonce_str":"402880e963a9764b0163a979a16e0002","bank_type":"CFT","openid":"oXI6G5Jc4D44y2wixgxE3OPwpDVg","sign":"262978D36A3093ACBE4B55707D6EA7B2","fee_type":"CNY","mch_id":"1491307962","cash_fee":"10","out_trade_no":"14913079622018052909183048768217","appid":"wxa177427bc0e60aab","total_fee":"10","trade_type":"JSAPI","result_code":"SUCCESS","time_end":"20180529091834","is_subscribe":"N","return_code":"SUCCESS"}

} catch(Exception e) {

e.printStackTrace();

}

}

}

后台业务逻辑涉及到的工具类及参数封装类

XmlUtilpackagecom.card.framework.utils;importcom.card.dto.PaymentDto;importcom.thoughtworks.xstream.XStream;importcom.thoughtworks.xstream.core.util.QuickWriter;importcom.thoughtworks.xstream.io.HierarchicalStreamWriter;importcom.thoughtworks.xstream.io.xml.PrettyPrintWriter;importcom.thoughtworks.xstream.io.xml.XppDriver;importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.io.SAXReader;importjavax.servlet.http.HttpServletRequest;importjava.io.IOException;importjava.io.Writer;importjava.util.HashMap;importjava.util.List;importjava.util.Map;public classXmlUtil {public static Map parseXML(HttpServletRequest request) throwsIOException, DocumentException {

Map map=new HashMap();/*通过IO获得Document*/SAXReader reader= newSAXReader();

Document doc=reader.read(request.getInputStream());//得到xml的根节点

Element root=doc.getRootElement();

recursiveParseXML(root,map);returnmap;

}private static void recursiveParseXML(Element root,Mapmap){//得到根节点的子节点列表

List elementList=root.elements();//判断有没有子元素列表

if(elementList.size()==0){

map.put(root.getName(), root.getTextTrim());

}else{//遍历

for(Element e:elementList){

recursiveParseXML(e,map);

}

}

}private static XStream xstream = new XStream(newXppDriver() {publicHierarchicalStreamWriter createWriter(Writer out) {return newPrettyPrintWriter(out) {//对所有xml节点都增加CDATA标记

boolean cdata = true;public voidstartNode(String name, Class clazz) {super.startNode(name, clazz);

}protected voidwriteText(QuickWriter writer, String text) {if(cdata) {

writer.write(text);

}else{

writer.write(text);

}

}

};

}

});public staticString messageToXML(PaymentDto paymentPo){

xstream.alias("xml",PaymentDto.class);returnxstream.toXML(paymentPo);

}

}

PaymentDto//封装支付参数实体

packagecom.card.dto;importjava.io.Serializable;public class PaymentDto implementsSerializable {private String appid;//小程序ID

private String mch_id;//商户号

private String device_info;//设备号

private String nonce_str;//随机字符串

private String sign;//签名

private String body;//商品描述

private String detail;//商品详情

private String attach;//附加数据

private String out_trade_no;//商户订单号

private String fee_type;//货币类型

private String spbill_create_ip;//终端IP

private String time_start;//交易起始时间

private String time_expire;//交易结束时间

private String goods_tag;//商品标记

private String total_fee;//总金额

private String notify_url;//通知地址

private String trade_type;//交易类型

private String limit_pay;//指定支付方式

private String openid;//用户标识

publicString getAppid() {returnappid;

}public voidsetAppid(String appid) {this.appid =appid;

}publicString getMch_id() {returnmch_id;

}public voidsetMch_id(String mch_id) {this.mch_id =mch_id;

}publicString getNonce_str() {returnnonce_str;

}public voidsetNonce_str(String nonce_str) {this.nonce_str =nonce_str;

}publicString getSign() {returnsign;

}public voidsetSign(String sign) {this.sign =sign;

}publicString getBody() {returnbody;

}public voidsetBody(String body) {this.body =body;

}publicString getOut_trade_no() {returnout_trade_no;

}public voidsetOut_trade_no(String out_trade_no) {this.out_trade_no =out_trade_no;

}publicString getTotal_fee() {returntotal_fee;

}public voidsetTotal_fee(String total_fee) {this.total_fee =total_fee;

}publicString getNotify_url() {returnnotify_url;

}public voidsetNotify_url(String notify_url) {this.notify_url =notify_url;

}publicString getTrade_type() {returntrade_type;

}public voidsetTrade_type(String trade_type) {this.trade_type =trade_type;

}publicString getOpenid() {returnopenid;

}public voidsetOpenid(String openid) {this.openid =openid;

}publicString getSpbill_create_ip() {returnspbill_create_ip;

}public voidsetSpbill_create_ip(String spbill_create_ip) {this.spbill_create_ip =spbill_create_ip;

}publicString getDevice_info() {returndevice_info;

}public voidsetDevice_info(String device_info) {this.device_info =device_info;

}publicString getDetail() {returndetail;

}public voidsetDetail(String detail) {this.detail =detail;

}publicString getAttach() {returnattach;

}public voidsetAttach(String attach) {this.attach =attach;

}publicString getFee_type() {returnfee_type;

}public voidsetFee_type(String fee_type) {this.fee_type =fee_type;

}publicString getTime_start() {returntime_start;

}public voidsetTime_start(String time_start) {this.time_start =time_start;

}publicString getTime_expire() {returntime_expire;

}public voidsetTime_expire(String time_expire) {this.time_expire =time_expire;

}publicString getGoods_tag() {returngoods_tag;

}public voidsetGoods_tag(String goods_tag) {this.goods_tag =goods_tag;

}publicString getLimit_pay() {returnlimit_pay;

}public voidsetLimit_pay(String limit_pay) {this.limit_pay =limit_pay;

}

}

PayUtilpackagecom.card.framework.utils;importorg.apache.commons.codec.digest.DigestUtils;import java.io.*;importjava.net.HttpURLConnection;importjava.net.URL;import java.util.*;public classPayUtil {/*** 签名字符串

*@paramtext 需要签名的字符串

*@paramkey 密钥

*@paraminput_charset 编码格式

*@return签名结果*/

public staticString sign(String text, String key, String input_charset) {

text= text +key;returnDigestUtils.md5Hex(getContentBytes(text, input_charset));

}/*** 签名字符串

*@paramtext 需要签名的字符串

*@paramsign 签名结果

*@paramkey 密钥

*@paraminput_charset 编码格式

*@return签名结果*/

public static booleanverify(String text, String sign, String key, String input_charset) {

text= text +key;

String mysign=DigestUtils.md5Hex(getContentBytes(text, input_charset));returnmysign.equals(sign);

}/***@paramcontent

*@paramcharset

*@return*@throwsUnsupportedEncodingException*/

public static byte[] getContentBytes(String content, String charset) {if (charset == null || "".equals(charset)) {returncontent.getBytes();

}try{returncontent.getBytes(charset);

}catch(UnsupportedEncodingException e) {throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" +charset);

}

}/*** 生成6位或10位随机数 param codeLength(多少位)

*@return

*/

public static String createCode(intcodeLength) {

String code= "";for (int i = 0; i < codeLength; i++) {

code+= (int) (Math.random() * 9);

}returncode;

}private static boolean isValidChar(charch) {if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'))return true;return (ch >= 0x4e00 && ch <= 0x7fff) || (ch >= 0x8000 && ch <= 0x952f);

}/*** 除去数组中的空值和签名参数

*@paramsArray 签名参数组

*@return去掉空值与签名参数后的新签名参数组*/

public static Map paraFilter(MapsArray) {

Map result= newHashMap();if (sArray == null || sArray.size() <= 0) {returnresult;

}for(String key : sArray.keySet()) {

String value=(String) sArray.get(key);if (value == null || value.equals("") || key.equalsIgnoreCase("sign")|| key.equalsIgnoreCase("sign_type")) {continue;

}

result.put(key, value);

}returnresult;

}/*** 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串

*@paramparams 需要排序并参与字符拼接的参数组

*@return拼接后字符串*/

public staticString createLinkString(Map params) {

List keys= newArrayList(params.keySet());

Collections.sort(keys);

String prestr= "";for (int i = 0; i < keys.size(); i++) {

String key=(String) keys.get(i);

String value=(String) params.get(key);if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符

prestr = prestr + key + "=" +value;

}else{

prestr= prestr + key + "=" + value + "&";

}

}returnprestr;

}/***

*@paramrequestUrl 请求地址

*@paramrequestMethod 请求方法

*@paramoutputStr 参数*/

public staticString httpRequest(String requestUrl,String requestMethod,String outputStr){//创建SSLContext

StringBuffer buffer=null;try{

URL url= newURL(requestUrl);

HttpURLConnection conn=(HttpURLConnection) url.openConnection();

conn.setRequestMethod(requestMethod);

conn.setDoOutput(true);

conn.setDoInput(true);

conn.connect();//往服务器端写内容

if(null !=outputStr){

OutputStream os=conn.getOutputStream();

os.write(outputStr.getBytes("utf-8"));

os.close();

}//读取服务器端返回的内容

InputStream is =conn.getInputStream();

InputStreamReader isr= new InputStreamReader(is, "utf-8");

BufferedReader br= newBufferedReader(isr);

buffer= newStringBuffer();

String line= null;while ((line = br.readLine()) != null) {

buffer.append(line);

}

}catch(Exception e){

e.printStackTrace();

}returnbuffer.toString();

}public staticString urlEncodeUTF8(String source){

String result=source;try{

result=java.net.URLEncoder.encode(source, "UTF-8");

}catch(UnsupportedEncodingException e) {//TODO Auto-generated catch block

e.printStackTrace();

}returnresult;

}

}

UUIDHexGenerator//生成随机数工具类

packagecom.card.framework.utils;importjava.net.InetAddress;public classUUIDHexGenerator {private static String sep = "";private static final intIP;private static short counter = (short) 0;private static final int JVM = (int) (System.currentTimeMillis() >>> 8);private static UUIDHexGenerator uuidgen = newUUIDHexGenerator();static{intipadd;try{

ipadd=toInt(InetAddress.getLocalHost().getAddress());

}catch(Exception e) {

ipadd= 0;

}

IP=ipadd;

}public staticUUIDHexGenerator getInstance() {returnuuidgen;

}public static int toInt(byte[] bytes) {int result = 0;for (int i = 0; i < 4; i++) {

result= (result << 8) - Byte.MIN_VALUE +bytes[i];//result = (result << - Byte.MIN_VALUE + (int) bytes);

}returnresult;

}protected static String format(intintval) {

String formatted=Integer.toHexString(intval);

StringBuffer buf= new StringBuffer("00000000");

buf.replace(8 - formatted.length(), 8, formatted);returnbuf.toString();

}protected static String format(shortshortval) {

String formatted=Integer.toHexString(shortval);

StringBuffer buf= new StringBuffer("0000");

buf.replace(4 - formatted.length(), 4, formatted);returnbuf.toString();

}protected static intgetJVM() {returnJVM;

}protected synchronized static shortgetCount() {if (counter < 0) {

counter= 0;

}return counter++;

}protected static intgetIP() {returnIP;

}protected static shortgetHiTime() {return (short) (System.currentTimeMillis() >>> 32);

}protected static intgetLoTime() {return (int) System.currentTimeMillis();

}public staticString generate() {return new StringBuffer(36).append(format(getIP())).append(sep).append(format(getJVM())).append(sep)

.append(format(getHiTime())).append(sep).append(format(getLoTime())).append(sep)

.append(format(getCount())).toString();

}/***@paramargs*/

public static voidmain(String[] args) {

String id="";

UUIDHexGenerator uuid=UUIDHexGenerator.getInstance();/*for (int i = 0; i < 100; i++) {

id = uuid.generate();

}*/id=generate();

System.out.println(id);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值