提供微信支付接口,需要先在微信开放平台(https://open.weixin.qq.com/)申请账号,进行开发者资格认证通过后创建应用。
创建成功后会有对应应用的AppID和AppSecret这个ios需要。我们需要的是商户平台的账号、初始密码、对应应用的AppID等,在开发者资格认证成功后微信会发到绑定的邮箱上。收到邮箱后需要登录到微信商户平台(https://pay.weixin.qq.com/index.php/core/home/login?return_url=%2F)修改初始密码并进行设置api密钥。
关于登录微信商户平台,我在进行登录时候火狐和谷歌经常不行,证书安装不好,后来试用qq浏览器才能登上,但是退款时候下载证书又不行,后来用了uc才可以的。配置好后我们就可以进行编码。首先看一下微信官方的文档上app支付需要的参数。
ios要在app中调起微信支付,需要一下几个参数:
这些参数由后台传送给ios,后台需要先传入以下必填参数进行第一次签名:
注意:对于同一帐号的不同应用,每次申请均需填写资料,均需签署合同。
接下来就是代码部分:微信的配置文件:
#weixin apy
##appid
weixin.appid=
##应用id 认证成功后微信官方给你返回
weixin.mch_id=
##回调url
weixin.notify_url=
##退款的回调url
weixin.refund_notify_url=
提供给ios接口代码:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.security.Security;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.UUID;
import javax.annotation.Resource;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.util.EntityUtils;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Results;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
/**
* 微信支付的接口
*
*/
@Namespace("/out/weixinPay")
@Results({ @Result(name = "500", location = "/WEB-INF/views/500.jsp") })
@SuppressWarnings("unused")
public class WeixinPayAction extends OutInterfaceBasicAction<Consult> {
private static final long serialVersionUID = 1L;
private Map<String, Object> msg = new HashMap<String, Object>();
/*
* @Resource private UnifiedOrderService unifiedOrderService;
*/
@Resource
private MemberService memberService;
@Resource
private ALiPayService aLiPayService;
private ALiPay aLiPay = new ALiPay();
@Resource
private IMessageService iMessageService;
@Resource
private RefundOrderService refundOrderService;
private static DecimalFormat df = new DecimalFormat("0.00");
// 构造签名的map
private SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
// 构造向微信发送参数的实体类
private Unifiedorder unifiedorder = new Unifiedorder();
// 微信的参数
private WeixinConfigUtils config = new WeixinConfigUtils();
public static final String ALGORITHM = "AES/ECB/PKCS7Padding";
private RefundOrder refundOrder = new RefundOrder();
@Resource
private AESDecodeUtil aesDecodeUtil;
@Resource
private OrderService orderService;
/**
* 微信充值
*/
@Action("weChatPayRecharge")
public String weChatPayRecharge() {
try {
df.setRoundingMode(RoundingMode.HALF_UP);
// 获取用户ID
String memberId = etRequest().getParameter("memberId");
String integer = getRequest().getParameter("integer");
if (StringUtils.isNotBlank(memberId)
&& StringUtils.isNotBlank(integer)) {
Integer score = Integer.valueOf(integer);
// 产生订单号
String outTradeNo = UuIdUtils.getUUID();
// 参数组
String appid = config.appid;
String mch_id = config.mch_id;
String nonce_str = RandCharsUtils.getRandomString(16);
String body = "";
body = "购买" + score + "积分,支付" + df.format(score / 100)+ "元";
String detail = score / 100 + "元支付开始";
String attach = "暂时无用(这个用于区分不同版本)";
String out_trade_no = outTradeNo;
int total_fee = score;// 单位是分,现在按照ios传递过来的参数进行
String spbill_create_ip = "127.0.0.1";
String time_start = RandCharsUtils.timeStart();
String time_expire = RandCharsUtils.timeExpire();
String notify_url = config.notify_url;
String trade_type = "APP";
// 参数:开始生成第一次签名
parameters.put("appid", appid);
parameters.put("mch_id", mch_id);
parameters.put("body", body);
parameters.put("nonce_str", nonce_str);
parameters.put("detail", detail);
parameters.put("attach", attach);
parameters.put("out_trade_no", out_trade_no);
parameters.put("total_fee", total_fee);
parameters.put("time_start", time_start);
parameters.put("time_expire", time_expire);
parameters.put("notify_url", notify_url);
parameters.put("trade_type", trade_type);
parameters.put("spbill_create_ip", spbill_create_ip);
String sign = WXSignUtils.createSign("UTF-8", parameters);
// 微信统一下单
unifiedorder.setAppid(appid);
unifiedorder.setMch_id(mch_id);
unifiedorder.setNonce_str(nonce_str);
unifiedorder.setSign(sign);
unifiedorder.setBody(body);
unifiedorder.setDetail(detail);
unifiedorder.setAttach(attach);
unifiedorder.setOut_trade_no(out_trade_no);
unifiedorder.setTotal_fee(total_fee);
unifiedorder.setSpbill_create_ip(spbill_create_ip);
unifiedorder.setTime_start(time_start);
unifiedorder.setTime_expire(time_expire);
unifiedorder.setNotify_url(notify_url);
unifiedorder.setTrade_type(trade_type);
try {
// 微信第二次签名
SortedMap<Object, Object> parameter2 = new TreeMap<Object, Object>();
parameter2.put("appid", appid);
parameter2.put("noncestr", nonce_str);
parameter2.put("package", "Sign=WXPay");
parameter2.put("partnerid", mch_id);
String prepareId = HttpXmlUtils.getPrepareId(unifiedorder);
parameter2.put("prepayid", prepareId);
long timestamp = System.currentTimeMillis() / 1000;
parameter2.put("timestamp", timestamp);
String sign2 = WXSignUtils.createSign("UTF-8", parameter2);
unifiedorder = null;
// 订单信息存入数据库
aLiPay.setApp_id(appid);
aLiPay.setSubject(body);
aLiPay.setScore(integer);
aLiPay.setGmt_create(time_start);
if (null != memberId && !"".equals(memberId)) {
aLiPay.setMember(memberService.getMemberById(Integer
.valueOf(memberId)));
}
aLiPay.setOut_trade_no(out_trade_no);
aLiPay.setPayStatus(PayStatusEnum.WAITPAY.getComment());
aLiPay.setPayType(PayTypeEnum.WEIXIN.getComment());
aLiPay.setState(0);
aLiPay.setTotal_amount(String.valueOf(total_fee / 100));
aLiPay.setTrade_no(prepareId);
aLiPay.setSign(sign);
aLiPay.setTotalFee(total_fee);
aLiPayService.addALiPay(aLiPay);
// 传递给ios的参数
msg.put("prepay_id", prepareId);
msg.put("appid", appid);
msg.put("mch_id", mch_id);
msg.put("timestamp", timestamp);
msg.put("nonce_str", nonce_str);
msg.put("sign", sign2);
msg.put("stateCode", MsgCode.SUCCESS);
msg.put("message ", "请求成功并返回数据!");
} catch (Exception e) {
msg.put("stateCode", MsgCode.ERROR);
msg.put("message ", "请求失败");
}
} else {
msg.put("stateCode", MsgCode.GET_PARAM_ERROR);
msg.put("message ", "获取参数失败!");
}
Struts2Utils.renderJson(JSONObject.toJSONString(msg,
SerializerFeature.DisableCircularReferenceDetect));
return NONE;
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
return "500";
}
}
*/
/**
* 微信回调url
*
* @throws IOException
*/
@Action("notifyUrl")
public String notifyUrl() throws IOException {
try {
Map<String, String> resultMap = JdomParseXmlUtils.getWeixinResult(
Struts2Utils.getRequest(), Struts2Utils.getResponse());
aLiPay = aLiPayService.searchALiPayByOutTradeNo(resultMap
.get("out_trade_no"));
String resutlTotal = String.valueOf(Integer.valueOf(resultMap
.get("total_fee")) / 100);
if (aLiPay.getState() == 0) {
if (aLiPay.getOut_trade_no().equals(
resultMap.get("out_trade_no"))
&& aLiPay.getTotal_amount().equals(resutlTotal)) {
aLiPay.setGmt_payment(resultMap.get("time_end"));
aLiPay.setPayStatus(PayStatusEnum.PAYOVER.getComment());
aLiPay.setState(1);
aLiPayService.updateALiPay(aLiPay);
iMessageService.sendUserscoreMsg(new IntegrationContent(
aLiPay.getMember().getMemberId(), Integer
.valueOf(aLiPay.getScore()), "微信充值"
+ aLiPay.getScore() + "积分", 1));
unifiedorder.setReturn_code("SUCCESS");
}
} else {
unifiedorder.setReturn_code("FAIL");
}
String refundXml = HttpXmlUtils.refundXml(unifiedorder);
Struts2Utils.getResponse().getWriter().write(refundXml);
Struts2Utils.getResponse().getWriter().flush();
return null;
} catch (Exception e) {
log.error(e.getMessage());
e.printStackTrace();
return "500";
}
}
}
使用到的工具类代码:
uuidUtis用于生成订单号:
import java.util.UUID;
public class UuIdUtils {
public static String getUUID() {
return UUID.randomUUID().toString().replace("-", "");
}
}
WeixinConfigUtils加载weixin.properties文件。
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.ResourceBundle;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* 微信的配置参数
* @author
* @date 2017/08/10
*/
@SuppressWarnings("unused")
public class WeixinConfigUtils {
private static final Log log = LogFactory.getLog(WeixinConfigUtils.class);
public static String appid;
public static String mch_id;
public static String notify_url;
public static String order_notify_url;
public static String doctor_notify_url;
static {
try{
InputStream is = WeixinConfigUtils.class.getResourceAsStream("/weixin.properties");
Properties properties = new Properties();
properties.load(is);
appid = properties.getProperty("weixin.appid");
mch_id = properties.getProperty("weixin.mch_id");
notify_url = properties.getProperty("weixin.notify_url");
order_notify_url = properties.getProperty("weixin.order_notify_url");
doctor_notify_url = properties.getProperty("weixin.doctor_notify_url");
}catch(Exception ex){
log.debug("加载配置文件:"+ex.getMessage());
}
}
}
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
/**
* nonce_str随即字符串
* @author
* @date 2017/08/10
*/
public class RandCharsUtils {
private static SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
public static String getRandomString(int length) { //length表示生成字符串的长度
String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz";
Random random = new Random();
StringBuffer sb = new StringBuffer();
int number = 0;
for (int i = 0; i < length; i++) {
number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
/*
* 订单开始交易的时间
*/
public static String timeStart(){
return df.format(new Date());
}
/*
* 订单开始交易的时间
*/
public static String timeExpire(){
Calendar now=Calendar.getInstance();
now.add(Calendar.MINUTE,30);
return df.format(now.getTimeInMillis());
}
}
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
/**
* 微信支付签名
* @author yangfuren
* @date 2017/08/10
*/
public class WXSignUtils {
/**
* 微信支付签名算法sign
* @param characterEncoding
* @param parameters
* @return
*/
@SuppressWarnings("rawtypes")
public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters){
StringBuffer sb = new StringBuffer();
Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序(升序)
Iterator it = es.iterator();
while(it.hasNext()) {
Map.Entry entry = (Map.Entry)it.next();
String k = (String)entry.getKey();
Object v = entry.getValue();
if(null != v && !"".equals(v)
&& !"sign".equals(k) && !"key".equals(k)) {
sb.append(k + "=" + v + "&");
}
}
sb.append("key=" + weixinConstant.KEY);
String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
return sign;
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import javax.net.ssl.HttpsURLConnection;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.xml.sax.InputSource;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
/**
* post提交xml格式的参数
* @author
* @date 2017/08/10
*/
public class HttpXmlUtils {
@Resource
private RefundOrderService refundOrderService;
public static XStream xStream = new XStream(new DomDriver("UTF-8",
new XmlFriendlyNameCoder("-_", "_")));
/**
* 开始post提交参数到接口
* 并接受返回
* @param url
* @param xml
* @param method
* @param contentType
* @return
*/
public static String xmlHttpProxy(String url,String xml,String method,String contentType){
InputStream is = null;
OutputStreamWriter os = null;
try {
URL _url = new URL(url);
HttpURLConnection conn = (HttpURLConnection) _url.openConnection();
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-type", "text/xml");
conn.setRequestProperty("Pragma:", "no-cache");
conn.setRequestProperty("Cache-Control", "no-cache");
conn.setRequestMethod("POST");
os = new OutputStreamWriter(conn.getOutputStream());
os.write(new String(xml.getBytes(contentType)));
os.flush();
//返回值
is = conn.getInputStream();
return getContent(is, "utf-8");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally{
try {
if(os!=null){os.close();}
if(is!=null){is.close();}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
/**
* 解析返回的值
* @param is
* @param charset
* @return
*/
public static String getContent(InputStream is, String charset) {
String pageString = null;
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer sb = null;
try {
isr = new InputStreamReader(is, charset);
br = new BufferedReader(isr);
sb = new StringBuffer();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line + "\n");
}
pageString = sb.toString();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null){
is.close();
}
if(isr!=null){
isr.close();
}
if(br!=null){
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
sb = null;
}
return pageString;
}
/**
* 解析申请退款之后微信返回的值并进行存库操作
* @throws IOException
* @throws JDOMException
*/
public static Map<String, String> parseRefundXml(String refundXml) throws JDOMException, IOException{
ParseXMLUtils.jdomParseXml(refundXml);
StringReader read = new StringReader(refundXml);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
org.jdom.Document doc;
doc = (org.jdom.Document) sb.build(source);
org.jdom.Element root = doc.getRootElement();// 指向根节点
List<org.jdom.Element> list = root.getChildren();
Map<String, String> refundOrderMap = new HashMap<String, String>();
if(list!=null&&list.size()>0){
for (org.jdom.Element element : list) {
refundOrderMap.put(element.getName(), element.getText());
}
return refundOrderMap;
}
return null;
}
/**
* 解析申请退款之后微信退款回调返回的字符串中内容
* @throws IOException
* @throws JDOMException
*/
public static Map<String, String> parseRefundNotifyXml(String refundXml) throws JDOMException, IOException{
ParseXMLUtils.jdomParseXml(refundXml);
StringReader read = new StringReader(refundXml);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
org.jdom.Document doc;
doc = (org.jdom.Document) sb.build(source);
org.jdom.Element root = doc.getRootElement();// 指向根节点
List<org.jdom.Element> list = root.getChildren();
Map<String, String> resultMap = new HashMap<>();
if(list!=null&&list.size()>0){
for (org.jdom.Element element : list){
resultMap.put(element.getName(), element.getText());
}
return resultMap;
}
return null;
}
/**
* h5支付时 解析返回的值并返回prepareid
* @throws IOException
* @throws JDOMException
*/
public static Map<String, String> getUrl(Unifiedorder unifiedorder) throws JDOMException, IOException{
String xmlInfo = HttpXmlUtils.xmlH5Info(unifiedorder);
String wxUrl = weixinConstant.URL;
String method = "POST";
String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();
ParseXMLUtils.jdomParseXml(weixinPost);
StringReader read = new StringReader(weixinPost);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
org.jdom.Document doc;
doc = (org.jdom.Document) sb.build(source);
org.jdom.Element root = doc.getRootElement();// 指向根节点
List<org.jdom.Element> list = root.getChildren();
String prepayId =null;
Map<String, String> msg = new HashMap<String, String>();
if(list!=null&&list.size()>0){
for (org.jdom.Element element : list) {
msg.put(element.getName(), element.getText());
}
}
return msg;
}
/**
* 解析返回的值并返回prepareid
* @throws IOException
* @throws JDOMException
*/
public static String getPrepareId(Unifiedorder unifiedorder) throws JDOMException, IOException{
String xmlInfo = HttpXmlUtils.xmlInfo(unifiedorder);
String wxUrl = weixinConstant.URL;
String method = "POST";
String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();
ParseXMLUtils.jdomParseXml(weixinPost);
StringReader read = new StringReader(weixinPost);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
org.jdom.Document doc;
doc = (org.jdom.Document) sb.build(source);
org.jdom.Element root = doc.getRootElement();// 指向根节点
List<org.jdom.Element> list = root.getChildren();
String prepayId =null;
if(list!=null&&list.size()>0){
for (org.jdom.Element element : list) {
if ( "prepay_id".equals(element.getName())) {
prepayId= element.getText();
break;
}
}
}
return prepayId;
}
/**
* 向微信发送企业付款请求并解析返回结果
* @throws IOException
* @throws JDOMException
*/
public static Map<String, String> getTransfersMap(Transfers transfers) throws JDOMException, IOException{
String xmlInfo = HttpXmlUtils.xmlTransfer(transfers);
String wxUrl = weixinConstant.WITHDRAW_URL;
String method = "POST";
String weixinPost = HttpXmlUtils.httpsRequest(wxUrl, method, xmlInfo).toString();
ParseXMLUtils.jdomParseXml(weixinPost);
StringReader read = new StringReader(weixinPost);
// 创建新的输入源SAX 解析器将使用 InputSource 对象来确定如何读取 XML 输入
InputSource source = new InputSource(read);
// 创建一个新的SAXBuilder
SAXBuilder sb = new SAXBuilder();
// 通过输入源构造一个Document
org.jdom.Document doc;
doc = (org.jdom.Document) sb.build(source);
org.jdom.Element root = doc.getRootElement();// 指向根节点
List<org.jdom.Element> list = root.getChildren();
Map<String, String> transferMap=new HashMap<>();
if(list!=null&&list.size()>0){
for (org.jdom.Element element : list) {
transferMap.put(element.getName(), element.getText());
}
}
return transferMap;
}
/**
* 构造退款xml参数
* @param xml
* @return
*/
public static String refundXml(Unifiedorder unifiedorder){
xStream.autodetectAnnotations(true);
xStream.alias("xml", Unifiedorder.class);
return xStream.toXML(unifiedorder);
}
/**
* 构造企业付款xml参数
* @param xml
* @return
*/
public static String transferXml(Transfers transfers){
xStream.autodetectAnnotations(true);
xStream.alias("xml", Transfers.class);
return xStream.toXML(transfers);
}
/**
* 构造xml参数
* @param xml
* @return
*/
public static String xmlInfo(Unifiedorder unifiedorder){
if(unifiedorder!=null){
StringBuffer bf = new StringBuffer();
bf.append("<xml>");
bf.append("<appid><![CDATA[");
bf.append(unifiedorder.getAppid());
bf.append("]]></appid>");
bf.append("<mch_id><![CDATA[");
bf.append(unifiedorder.getMch_id());
bf.append("]]></mch_id>");
bf.append("<nonce_str><![CDATA[");
bf.append(unifiedorder.getNonce_str());
bf.append("]]></nonce_str>");
bf.append("<sign><![CDATA[");
bf.append(unifiedorder.getSign());
bf.append("]]></sign>");
bf.append("<body><![CDATA[");
bf.append(unifiedorder.getBody());
bf.append("]]></body>");
bf.append("<detail><![CDATA[");
bf.append(unifiedorder.getDetail());
bf.append("]]></detail>");
bf.append("<attach><![CDATA[");
bf.append(unifiedorder.getAttach());
bf.append("]]></attach>");
bf.append("<out_trade_no><![CDATA[");
bf.append(unifiedorder.getOut_trade_no());
bf.append("]]></out_trade_no>");
bf.append("<total_fee><![CDATA[");
bf.append(unifiedorder.getTotal_fee());
bf.append("]]></total_fee>");
bf.append("<spbill_create_ip><![CDATA[");
bf.append(unifiedorder.getSpbill_create_ip());
bf.append("]]></spbill_create_ip>");
bf.append("<time_start><![CDATA[");
bf.append(unifiedorder.getTime_start());
bf.append("]]></time_start>");
bf.append("<time_expire><![CDATA[");
bf.append(unifiedorder.getTime_expire());
bf.append("]]></time_expire>");
bf.append("<notify_url><![CDATA[");
bf.append(unifiedorder.getNotify_url());
bf.append("]]></notify_url>");
bf.append("<trade_type><![CDATA[");
bf.append(unifiedorder.getTrade_type());
bf.append("]]></trade_type>");
bf.append("</xml>");
return bf.toString();
}
return "";
}
/**
* 构造xml参数
* @param xml
* @return
*/
public static String xmlH5Info(Unifiedorder unifiedorder){
if(unifiedorder!=null){
StringBuffer bf = new StringBuffer();
bf.append("<xml>");
bf.append("<appid><![CDATA[");
bf.append(unifiedorder.getAppid());
bf.append("]]></appid>");
bf.append("<mch_id><![CDATA[");
bf.append(unifiedorder.getMch_id());
bf.append("]]></mch_id>");
bf.append("<nonce_str><![CDATA[");
bf.append(unifiedorder.getNonce_str());
bf.append("]]></nonce_str>");
bf.append("<sign><![CDATA[");
bf.append(unifiedorder.getSign());
bf.append("]]></sign>");
bf.append("<body><![CDATA[");
bf.append(unifiedorder.getBody());
bf.append("]]></body>");
bf.append("<attach><![CDATA[");
bf.append(unifiedorder.getAttach());
bf.append("]]></attach>");
bf.append("<out_trade_no><![CDATA[");
bf.append(unifiedorder.getOut_trade_no());
bf.append("]]></out_trade_no>");
bf.append("<total_fee><![CDATA[");
bf.append(unifiedorder.getTotal_fee());
bf.append("]]></total_fee>");
bf.append("<spbill_create_ip><![CDATA[");
bf.append(unifiedorder.getSpbill_create_ip());
bf.append("]]></spbill_create_ip>");
bf.append("<notify_url><![CDATA[");
bf.append(unifiedorder.getNotify_url());
bf.append("]]></notify_url>");
bf.append("<trade_type><![CDATA[");
bf.append(unifiedorder.getTrade_type());
bf.append("]]></trade_type>");
bf.append("<scene_info><![CDATA[");
bf.append(unifiedorder.getScene_info());
bf.append("]]></scene_info>");
bf.append("</xml>");
return bf.toString();
}
return "";
}
/**
* 构造退款xml参数
* @param xml
* @return
*/
public static String xmlTransfer(Transfers transfers){
if(transfers!=null){
StringBuffer bf = new StringBuffer();
bf.append("<xml>");
bf.append("<mch_appid><![CDATA[");
bf.append(transfers.getMch_appid());
bf.append("]]></mch_appid>");
bf.append("<mchid><![CDATA[");
bf.append(transfers.getMchid());
bf.append("]]></mchid>");
bf.append("<nonce_str><![CDATA[");
bf.append(transfers.getNonce_str());
bf.append("]]></nonce_str>");
bf.append("<sign><![CDATA[");
bf.append(transfers.getSign());
bf.append("]]></sign>");
bf.append("<partner_trade_no><![CDATA[");
bf.append(transfers.getPartner_trade_no());
bf.append("]]></partner_trade_no>");
bf.append("<openid><![CDATA[");
bf.append(transfers.getOpenid());
bf.append("]]></openid>");
bf.append("<check_name><![CDATA[");
bf.append(transfers.getCheck_name());
bf.append("]]></check_name>");
bf.append("<amount><![CDATA[");
bf.append(transfers.getAmount());
bf.append("]]></amount>");
bf.append("<desc><![CDATA[");
bf.append(transfers.getDesc());
bf.append("]]></desc>");
bf.append("<spbill_create_ip><![CDATA[");
bf.append(transfers.getSpbill_create_ip());
bf.append("]]></spbill_create_ip>");
bf.append("</xml>");
return bf.toString();
}
return "";
}
/**
* post请求并得到返回结果
* @param requestUrl
* @param requestMethod
* @param output
* @return
*/
public static String httpsRequest(String requestUrl, String requestMethod, String output) {
try{
URL url = new URL(requestUrl);
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setDoInput(true);
connection.setUseCaches(false);
connection.setRequestMethod(requestMethod);
if (null != output) {
OutputStream outputStream = connection.getOutputStream();
outputStream.write(output.getBytes("UTF-8"));
outputStream.close();
}
// 从输入流读取返回内容
InputStream inputStream = connection.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str = null;
StringBuffer buffer = new StringBuffer();
while ((str = bufferedReader.readLine()) != null) {
buffer.append(str);
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
inputStream = null;
connection.disconnect();
return buffer.toString();
}catch(Exception ex){
ex.printStackTrace();
}
return "";
}
}
/**
* 微信支付相关的常量
* @author yangfuren
* @since 2017/08/16
*/
public class weixinConstant {
/**
* 微信支付API秘钥 第一次登录时设置的
*/
public static final String KEY = "";
/**
* url
*/
public static final String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
/**
* 退款url
*/
public static final String REFUND_URL = "https://api.mch.weixin.qq.com/secapi/pay/refund";
/**
* 证书地址 退款及h5支付使用
*/
public static final String PATH ="";
/**
* 付款url
*/
public static final String WITHDRAW_URL="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
}
import java.security.MessageDigest;
public class MD5Util {
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];
}
public static String MD5Encode(String origin, String charsetname) {
String resultString = null;
try {
resultString = new String(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;
}
private static final String hexDigits[] = { "0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
}
统一下单提交为微信的参数
import java.io.Serializable;
/**
* 统一下单提交为微信的参数
* @author
* @date 2017年08月11日
*/
public class Unifiedorder implements Serializable{
private static final long serialVersionUID = 1L;
//微信支付表id
private Integer weixinId;
//微信分配的公众账号ID(企业号corpid即为此appId)
private String appid;
//商户id
private String mch_id;
//终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB"
private String device_info;
//随机字符串:数字+大写字母的组合,32位
private String nonce_str;
//签名
private String sign;
//商品或支付单简要描述
private String body;
//商品名称明细列表
private String detail;
//附加参数(例如:用于区别本商户不同的分店)
private String attach;
//商户系统内部的订单号
private String out_trade_no;
//货币类型:符合ISO 4217标准的三位字母代码,默认人民币:CNY
private String fee_type;
//总金额
private int total_fee;
//APP和网页支付提交[用户端ip],Native支付填调用微信支付API的机器IP。
private String spbill_create_ip;
//订单生成时间,格式为yyyyMMddHHmmss,
private String time_start;
//订单失效时间,格式为yyyyMMddHHmmss,最短失效时间间隔必须大于5分钟[支付宝是30分钟,同样30分钟]
private String time_expire;
//商品标记,代金券或立减优惠功能的参数
private String goods_tag;
//接收微信支付异步通知回调地址
private String notify_url;
//交易类型:JSAPI,NATIVE,APP h5为 MWEB
private String trade_type;
//trade_type=NATIVE,此参数必传。此id为二维码中包含的商品ID,商户自行定义。
private String product_id;
//no_credit--指定不能使用信用卡支付
private String limit_pay;
//trade_type=JSAPI,此参数必传,用户在商户appid下的唯一标识
private String openid;
//商户内部自己的退款单号
private String out_refund_no;
//退款总金额单位为分
private int refund_fee;
//操作员的id默认为mch_id
private String op_user_id;
//微信官方提供的订单号
private String prepayid;
//记录所对应的member
private Member member;
//返回给微信的状态码(用于支付回调时)
public String return_code;
//微信h5支付时候的场景信息官方的信息模板 {"h5_info"://h5支付固定传"h5_info"
//{"type":"",//场景类型 "wap_url":"",//WAP网站URL地址"wap_name": ""//WAP 网站名}}
public String scene_info;
public String getScene_info() {
return scene_info;
}
public void setScene_info(String scene_info) {
this.scene_info = scene_info;
}
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 String getMch_id() {
return mch_id;
}
public String getDevice_info() {
return device_info;
}
public String getNonce_str() {
return nonce_str;
}
public String getSign() {
return sign;
}
public String getBody() {
return body;
}
public String getDetail() {
return detail;
}
public String getAttach() {
return attach;
}
public String getOut_trade_no() {
return out_trade_no;
}
public String getFee_type() {
return fee_type;
}
public int getTotal_fee() {
return total_fee;
}
public String getSpbill_create_ip() {
return spbill_create_ip;
}
public String getTime_start() {
return time_start;
}
public String getTime_expire() {
return time_expire;
}
public String getGoods_tag() {
return goods_tag;
}
public String getNotify_url() {
return notify_url;
}
public String getTrade_type() {
return trade_type;
}
public String getProduct_id() {
return product_id;
}
public String getLimit_pay() {
return limit_pay;
}
public String getOpenid() {
return openid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public void setMch_id(String mch_id) {
this.mch_id = mch_id;
}
public void setDevice_info(String device_info) {
this.device_info = device_info;
}
public void setNonce_str(String nonce_str) {
this.nonce_str = nonce_str;
}
public void setSign(String sign) {
this.sign = sign;
}
public void setBody(String body) {
this.body = body;
}
public void setDetail(String detail) {
this.detail = detail;
}
public void setAttach(String attach) {
this.attach = attach;
}
public void setOut_trade_no(String out_trade_no) {
this.out_trade_no = out_trade_no;
}
public void setFee_type(String fee_type) {
this.fee_type = fee_type;
}
public void setTotal_fee(int total_fee) {
this.total_fee = total_fee;
}
public void setSpbill_create_ip(String spbill_create_ip) {
this.spbill_create_ip = spbill_create_ip;
}
public void setTime_start(String time_start) {
this.time_start = time_start;
}
public void setTime_expire(String time_expire) {
this.time_expire = time_expire;
}
public void setGoods_tag(String goods_tag) {
this.goods_tag = goods_tag;
}
public void setNotify_url(String notify_url) {
this.notify_url = notify_url;
}
public void setTrade_type(String trade_type) {
this.trade_type = trade_type;
}
public void setProduct_id(String product_id) {
this.product_id = product_id;
}
public void setLimit_pay(String limit_pay) {
this.limit_pay = limit_pay;
}
public void setOpenid(String openid) {
this.openid = openid;
}
public String getOut_refund_no() {
return out_refund_no;
}
public void setOut_refund_no(String out_refund_no) {
this.out_refund_no = out_refund_no;
}
public int getRefund_fee() {
return refund_fee;
}
public void setRefund_fee(int refund_fee) {
this.refund_fee = refund_fee;
}
public Integer getWeixinId() {
return weixinId;
}
public void setWeixinId(Integer weixinId) {
this.weixinId = weixinId;
}
public Member getMember() {
return member;
}
public void setMember(Member member) {
this.member = member;
}
public String getPrepayid() {
return prepayid;
}
public void setPrepayid(String prepayid) {
this.prepayid = prepayid;
}
public String getOp_user_id() {
return op_user_id;
}
public void setOp_user_id(String op_user_id) {
this.op_user_id = op_user_id;
}
}
将参数传递给ios,ios会通过我们传递的参数调起微信支付。在生成签名时,可以将生成的sign和传入的appid,随机字符串,时间戳,微信官方的订单号,输入到https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1中按照顺序输入参数并生成sign看和你的sign是否一致。