今年做了微信支付项目包括微信扫码支付、微信小程序支付和微信h5支付。
现在总结如下:
1、pom.xml
com.github.wxpay
wxpay-sdk
0.0.3
2、配置文件
2.1 扫码支付配置文件
public class PayConfigUtil implements Serializable {
//初始化
public final static String APP_ID = "==============";//公众账号appid(改为自己实际的)
//public final static String APP_SECRET = "";//"";
public final static String MCH_ID = "===========";//商户号(改为自己实际的)
public final static String API_KEY = "=================";//(改为自己实际的)key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
//有关url
public final static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
public final static String NOTIFY_URL = "https://=====================/Wxpay/weixinNotify.do"; //微信支付回调接口,就是微信那边收到(改为自己实际的)
public static String CREATE_IP = "";//发起支付ip(改为自己实际的)
}
2.2 微信小程序配置文件
public class XcxPayConfig {
//小程序appid
public static final String appid = "===============";
//微信支付的商户id
public static final String mch_id = "==================";
//微信支付的商户密钥
public static final String key = "====================";
//小程序secret
public static final String secret="===================";
//支付成功后的服务器回调url
public static final String notify_url = "https://====================/Wxpay/xcxNotify";
//签名方式,固定值
public static final String SIGNTYPE = "MD5";
//交易类型,小程序支付的固定值为JSAPI
public static final String TRADETYPE = "JSAPI";
//微信统一下单接口地址
public static final String pay_url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
}
2.3 微信H5支付配置文件
public class H5payConfig {
//初始化
public final static String APP_ID = "wx============";//; //公众账号appid(改为自己实际的)
public final static String APP_SECRET = "=============";//;
public final static String MCH_ID = "==========";//; //商户号(改为自己实际的)
public final static String API_KEY = "================";//; //(改为自己实际的)key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置
//有关url
public final static String UFDODER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";//统一下单
public final static String QURODER_URL = "https://api.mch.weixin.qq.com/pay/orderquery";//订单查询
public final static String NOTIFY_URL = "https://========/Wxpay/h5Notify"; //微信支付回调接口,就是微信那边收到(改为自己实际的)
public final static String REDIRECT_URL = "https://========/Wxpay/h5Redirect"; //微信支付回调接口,就是微信那边收到(改为自己实际的)
}
3、Controller
3.1、扫码支付
/**
* 扫码支付 生成二维码
* @param request
* @param response
* @param modelMap
*/
@ResponseBody
@RequestMapping("/qrcode.do")
public void qrcode(HttpServletRequest request, HttpServletResponse response,
ModelMap modelMap) {
try {
String amount = request.getParameter("amount");
String productId = request.getParameter("productId");
String userId= request.getParameter("userId");
String businessId = request.getParameter("businessId");
String userType = request.getParameter("userType");
String ip = getIpAddress(request);
String text = codeService.weixinPay(ip,amount, productId,userId,businessId,userType);
int width = 300;
int height = 300;
//二维码的图片格式
String format = "gif";
Hashtable hints = new Hashtable();
//内容所使用编码
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
BitMatrix bitMatrix = null;
try {
bitMatrix = new MultiFormatWriter().encode(text, BarcodeFormat.QR_CODE, width, height, hints);
QRUtil.writeToStream(bitMatrix, format, response.getOutputStream());
} catch (WriterException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 扫码支付 获取IP本机IP地址
* @param request
*/
public static String getIpAddress(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
if (ip.contains(",")) {
return ip.split(",")[0];
} else {
return ip;
}
}
/**
* 扫码支付 是否支付成功
* @param request
* @param response
* @param modelMap
* @return
*/
@ResponseBody
@RequestMapping("/hadPay.do")
public Map hadPay(HttpServletRequest request, HttpServletResponse response,
ModelMap modelMap) {
try {
//简单的业务逻辑:在微信的回调接口里面,已经定义了,回调返回成功的话,那么 _PAY_RESULT 不为空
if(request.getSession().getAttribute("_PAY_RESULT") != null ){
return success("支付成功!");
}
return error("没成功");
} catch (Exception e) {
return error(e);
}
}
/**
* 扫码支付 成功信息
* @param request
* @param response
* @param modelMap
* @return
*/
protected Map success(Object data) {
return toMap("data", data, "result", ConstantBean.SUCCESS);
}
/**
* 扫码支付 失败信息
* @param request
* @param response
* @param modelMap
* @return
*/
protected Map error(Object data) {
return toMap("data", data, "result", ConstantBean.ERROR);
}
/**
* 扫码支付 Object转换为Map
* @param request
* @param response
* @param modelMap
* @return
*/
public static Map toMap(Object... params) {
Map map = new LinkedHashMap();
Assert.notNull(params);
Assert.isTrue(params.length % 2 == 0);
for (int i = 0; i < params.length; i++) {
map.put(params[i++], params[i]);
}
return map;
}
/**
* 扫码支付
* 微信平台发起的回调方法,
* 调用我们这个系统的这个方法接口,将扫描支付的处理结果告知我们系统
* @throws JDOMException
* @throws Exception
*/
@ResponseBody
@RequestMapping("/weixinNotify.do")
public void weixinNotify(HttpServletRequest request, HttpServletResponse response) throws JDOMException, Exception{
//读取参数
InputStream inputStream ;
StringBuffer sb = new StringBuffer();
inputStream = request.getInputStream();
String s ;
BufferedReader in = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
while ((s = in.readLine()) != null){
sb.append(s);
}
in.close();
inputStream.close();
//解析xml成map
Map m = new HashMap();
m = XMLUtil4jdom.doXMLParse(sb.toString());
//过滤空 设置 TreeMap
SortedMap
3.2 小程序微信支付
/**
* 小程序支付
* 下单支付
* @param openid
* @param request
* @return
*/
@RequestMapping("xcxPay")
@ResponseBody
public JsonMsg xcxPay(String openid, HttpServletRequest request){
JsonMsg json = new JsonMsg();
try{
if(openid == null || ("").equals(openid)){
json.setSuccess(false);
json.setMsg("参数openid不能为空!");
return json;
}
//商品名称
String body = request.getParameter("body");
//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
String money = request.getParameter("money");
if(money == null || ("").equals(money)){
json.setSuccess(false);
json.setMsg("参数money不能为空!");
return json;
}
String businessId = request.getParameter("businessId");
String userType = request.getParameter("userType");
String userId = request.getParameter("userId");
String orderCode = request.getParameter("orderCode");
//插入 PrechargeRecords 表,并生成 out_trade_no
String orderNo = codeService.getOrderNo(openid,body,money,businessId,userType,userId,orderCode);
//生成的随机字符串
String nonce_str = StringUtils.getRandomStringByLength(32);
//获取本机的ip地址
String spbill_create_ip = IpUtils.getIpAddr(request);
Map packageParams = new HashMap();
packageParams.put("appid", XcxPayConfig.appid);
packageParams.put("mch_id", XcxPayConfig.mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", body);
packageParams.put("out_trade_no", orderNo.split(",")[0]);//商户订单号
packageParams.put("total_fee", getAmount(money).toString());//支付金额,这边需要转成字符串类型,否则后面的签名会失败
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", XcxPayConfig.notify_url);
packageParams.put("trade_type", XcxPayConfig.TRADETYPE);
packageParams.put("openid", openid);
// 除去数组中的空值和签名参数
packageParams = PayUtil.paraFilter(packageParams);
String prestr = PayUtil.createLinkString(packageParams); // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
//MD5运算生成签名,这里是第一次签名,用于调用统一下单接口
String mysign = PayUtil.sign(prestr, XcxPayConfig.key, "utf-8").toUpperCase();
logger.info("=======================第一次签名:" + mysign + "=====================");
//拼接统一下单接口使用的xml数据,要将上一步生成的签名一起拼接进去
String xml = "" + "" + XcxPayConfig.appid + " "
+ ""
+ "" + XcxPayConfig.mch_id + " "
+ "" + nonce_str + " "
+ "" + XcxPayConfig.notify_url + " "
+ "" + openid + " "
+ "" + orderNo.split(",")[0] + " "
+ "" + spbill_create_ip + " "
+ "" + getAmount(money).toString() + " "
+ "" + XcxPayConfig.TRADETYPE + " "
+ "" + mysign + " "
+ " ";
System.out.println("调试模式_统一下单接口 请求XML数据:" + xml);
//调用统一下单接口,并接受返回的结果
String result = PayUtil.httpRequest(XcxPayConfig.pay_url, "POST", xml);
System.out.println("调试模式_统一下单接口 返回XML数据:" + result);
// 将解析结果存储在HashMap中
Map map = PayUtil.doXMLParse(result);
String return_code = (String) map.get("return_code");//返回状态码
//返回给移动端需要的参数
Map response = new HashMap();
if(return_code == "SUCCESS" || return_code.equals("SUCCESS")){
// 业务结果
String prepay_id = (String) map.get("prepay_id");//返回的预付单信息
response.put("nonceStr", nonce_str);
response.put("package", "prepay_id=" + prepay_id);
Long timeStamp = System.currentTimeMillis() / 1000;
response.put("timeStamp", timeStamp + "");//这边要将返回的时间戳转化成字符串,不然小程序端调用wx.requestPayment方法会报签名错误
String stringSignTemp = "appId=" + XcxPayConfig.appid + "&nonceStr=" + nonce_str + "&package=prepay_id=" + prepay_id+ "&signType=" + XcxPayConfig.SIGNTYPE + "&timeStamp=" + timeStamp;
//再次签名,这个签名用于小程序端调用wx.requesetPayment方法
String paySign = PayUtil.sign(stringSignTemp, XcxPayConfig.key, "utf-8").toUpperCase();
logger.info("=======================第二次签名:" + paySign + "=====================");
response.put("signType",XcxPayConfig.SIGNTYPE);
response.put("paySign", paySign);
// response.put("appid", XcxPayConfig.appid);
if(orderCode!=null&&!orderCode.equals("")) {//继续支付
if(orderNo.split(",")[0].length()>0&&orderNo.split(",")[1].length()>0){
json.setSuccess(true);
json.setData(response);
return json;
}else{
json.setSuccess(false);
json.setData("orderNo不正确!");
return json;
}
}else{//支付
//更新订单信息
FinWeixinRecord f = new FinWeixinRecord();
f.setAppId(packageParams.get("appid"));
f.setMchId(packageParams.get("mch_id"));
f.setNonchStr(packageParams.get("nonce_str"));
f.setOutTradeNo(packageParams.get("out_trade_no"));
f.setTradeType("JSAPI");
f.setPrePayId(prepay_id);
f.setTotalFee(Long.parseLong(packageParams.get("total_fee")));
f.setBody("xcxPay");
f.setOpenId(packageParams.get("openid"));
f.setSpbllCreateIp(packageParams.get("spbill_create_ip"));
f.setGmtCreate(new Date());
f.setCreateUser(userId);
f.setOrderId(orderNo.split(",")[1]);
int i = codeService.xcxPay(f);
//业务逻辑代码
if(i>0){
json.setSuccess(true);
json.setData(response);
return json;
}else{
json.setSuccess(false);
json.setData("更新订单信息出错!");
return json;
}
}
}
json.setSuccess(false);
json.setData("returnCode FAIL");
return json;
}catch(Exception e){
e.printStackTrace();
json.setSuccess(false);
json.setMsg("发起失败");
}
return null;
}
/**
* 小程序支付 金额单位转换为分
* 更新订单信息
* @String recAmount
*/
private Integer getAmount(String recAmount){
return new BigDecimal(recAmount).multiply(new BigDecimal(100)).intValue();
}
/**
* 小程序支付
* 更新订单信息
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value="/xcxNotify")
@ResponseBody
public void xcxNotify(HttpServletRequest request,HttpServletResponse response) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader((ServletInputStream)request.getInputStream()));
String line = null;
StringBuilder sb = new StringBuilder();
while((line = br.readLine())!=null){
sb.append(line);
}
br.close();
//sb为微信返回的xml
String notityXml = sb.toString();
String resXml = "";
//System.out.println("接收到的报文:" + notityXml);
logger.info("接收到的报文:" + notityXml);
Map map = PayUtil.doXMLParse(notityXml);
String returnCode = null;
String sign = map.get("sign").toString();
map.remove("sign");
if(map!=null){
returnCode = (String) map.get("return_code");
}
if(returnCode != null && "SUCCESS".equals(returnCode)){
//验证签名是否正确
if(PayUtil.verify(PayUtil.createLinkString(map), sign, XcxPayConfig.key, "utf-8")){
/**此处添加自己的业务逻辑代码start**/
int i = codeService.updateRechargeInfo(map,"SUCCESS",(String)map.get("return_code"),"xcxPay");
/**此处添加自己的业务逻辑代码end**/
if(i>0){
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = "" + " "
+ " " + " ";
logger.info("支付成功");
}else{
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
resXml = "" + " "
+ " " + " ";
logger.info("支付失败");
}
// //通知微信服务器已经支付成功
// resXml = "" + " "
// + " " + " ";
}else{
logger.info("小程序验签失败!");
}
}else{
if(map!=null) {
codeService.updateRechargeInfo(map, "FAIL", (String) map.get("result_code"), "xcxPay");
}
resXml = "" + " "
+ " " + " ";
}
// System.out.println(resXml);
// System.out.println("微信支付回调数据结束");
logger.info(resXml);
logger.info("微信支付回调数据结束");
BufferedOutputStream out = new BufferedOutputStream(
response.getOutputStream());
out.write(resXml.getBytes());
out.flush();
out.close();
}
/**
* 小程序支付
* 小程序登录获取openId
* @param code
* @param request
* @return
* @throws WeixinException
* @throws IOException
*/
@RequestMapping("login")
@ResponseBody
public Map login(String code, HttpServletRequest request) throws WeixinException, IOException {
if (code == null || code.equals("")) {
throw new WeixinException("invalid null, code is null.");
}
Map ret = new HashMap();
//拼接参数
String param = "?grant_type=" + grant_type + "&appid=" + XcxPayConfig.appid + "&secret=" + XcxPayConfig.secret + "&js_code=" + code;
//创建请求对象
HttpsClient http = new HttpsClient();
//调用获取access_token接口
Response res = http.get("https://api.weixin.qq.com/sns/jscode2session" + param);
//根据请求结果判定,是否验证成功
JSONObject jsonObj = res.asJSONObject();
if (jsonObj != null) {
Object errcode = jsonObj.get("errcode");
if (errcode != null) {
//返回异常信息
throw new WeixinException(errcode.toString());
}
ObjectMapper mapper = new ObjectMapper();
OAuthJsToken oauthJsToken = mapper.readValue(jsonObj.toJSONString(),OAuthJsToken.class);
logger.info("openid=" + oauthJsToken.getOpenid());
ret.put("openid", oauthJsToken.getOpenid());
}
return ret;
}
3.3 微信H5支付
/**
* 微信H5支付
* @param request
* @param response
* @param model
* @return
*/
@ResponseBody
@RequestMapping(value = "/h5Pay")
public JsonMsg h5Pay(HttpServletRequest request, HttpServletResponse response, ModelMap model) {
JsonMsg json = new JsonMsg();
int tag = 0;//初始化
//商品名称
String subject = request.getParameter("body");//前端上送的支付主题
if("快递充值".equals(subject)){
tag = 1;
}else if("短信充值".equals(subject)){
tag = 2;
}else{
tag = 3;//缺少主题
}
//支付金额,单位:分,这边需要转成字符串类型,否则后面的签名会失败
String total_amount = request.getParameter("money");//前端上送的支付金额
if(total_amount == null || ("").equals(total_amount)){
json.setSuccess(false);
json.setMsg("参数money不能为空!");
return json;
}
String businessId = request.getParameter("businessId");
String userType = request.getParameter("userType");
String userId = request.getParameter("userId");
String token = request.getParameter("token");
if(token == null || ("").equals(token)){
json.setSuccess(false);
json.setMsg("参数token不能为空!");
return json;
}
logger.info("pay_toke="+token);
String orderCode = request.getParameter("orderCode");//继续支付
String APPID = H5payConfig.APP_ID;
String MERID = H5payConfig.MCH_ID;
String SIGNKEY = H5payConfig.APP_SECRET;
String spbill_create_ip = getIpAddress(request);//生产
logger.info("spbill_create_ip="+spbill_create_ip);
//String spbill_create_ip = "";//测试地址,也就是本地真是ip,用于本地测试用
String scene_info = "{\"h5_info\": {\"type\":\"Wap\",\"wap_url\": \"www.rrsjk.com\",\"wap_name\": \"乐农支付\"}}";//我这里是网页入口,app入口参考文档的安卓和ios写法
String tradeType = "MWEB";//H5支付标记
String MD5 = "MD5";//虽然官方文档不是必须参数,但是不送有时候会验签失败
//金额转化为分为单位 微信支付以分为单位
String finalmoney = com.haier.util.h5pay.StringUtils.getMoney(total_amount);
//插入 PrechargeRecords 表,并生成 out_trade_no
String orderNo = codeService.getOrderNo(null,subject,total_amount,businessId,userType,userId,orderCode);
String out_trade_no = orderNo.split(",")[0];
//随机数
String nonce_str= com.haier.util.h5pay.MD5Utils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
//签名数据
StringBuilder sb = new StringBuilder();
sb.append("appid="+APPID);
sb.append("&body="+subject);
sb.append("&mch_id="+MERID);
sb.append("&nonce_str="+nonce_str);
sb.append("¬ify_url="+H5payConfig.NOTIFY_URL);
sb.append("&out_trade_no="+out_trade_no);
sb.append("&scene_info="+scene_info);
sb.append("&sign_type="+"MD5");
sb.append("&spbill_create_ip="+spbill_create_ip);
sb.append("&total_fee="+finalmoney);
sb.append("&trade_type="+tradeType);
sb.append("&key="+H5payConfig.API_KEY);
logger.info("sb="+sb);
//签名MD5加密
String sign = com.haier.util.wxpay.MD5Util.MD5Encode(sb.toString(),"utf-8").toUpperCase();
logger.info("sign="+sign);
logger.info("签名数据:"+sign);
//封装xml报文
String xml=""+
""+ APPID+" "+
""+subject+""+//
""+ MERID+" "+
""+nonce_str+" "+
""+H5payConfig.NOTIFY_URL+" "+
""+out_trade_no+" "+
""+scene_info+" "+
""+sign+" "+
"MD5 "+
""+spbill_create_ip+" "+
""+Integer.parseInt(finalmoney)+" "+//
""+tradeType+" "+
" ";
String createOrderURL = H5payConfig.UFDODER_URL;//微信统一下单接口
String mweb_url = "";
Map map = new HashMap();
String callBackUrl = H5payConfig.REDIRECT_URL;
logger.info("微信支付回调链接为:" + callBackUrl);
try {
//预下单 获取接口地址
map = com.haier.util.h5pay.WebUtils.getMwebUrl(createOrderURL, xml);
String return_code = (String) map.get("return_code");
String return_msg = (String) map.get("return_msg");
if("SUCCESS".equals(return_code) && "OK".equals(return_msg)){
FinWeixinRecord f = new FinWeixinRecord();
f.setAppId(APPID);
f.setMchId(MERID);
f.setNonchStr(nonce_str);
f.setOutTradeNo(out_trade_no);
f.setTradeType(tradeType);
f.setPrePayId((String) map.get("prepay_id"));
f.setTotalFee(Long.parseLong(finalmoney));
f.setBody(subject);
f.setSpbllCreateIp(spbill_create_ip);
f.setGmtCreate(new Date());
f.setCreateUser(userId);
f.setOrderId(orderNo.split(",")[1]);
int i = codeService.h5Pay(f);
if(i>0) {
mweb_url = (String) map.get("mweb_url");//调微信支付接口地址
if (!"".equals(callBackUrl)) {
callBackUrl += "?out_trade_no="+out_trade_no+"&token="+token+"&tag="+tag;
callBackUrl = URLEncoder.encode(callBackUrl, "UTF-8");
mweb_url = mweb_url + "&redirect_url=" + callBackUrl;
}
logger.info("mweb_url=" + mweb_url);
json.setSuccess(true);
json.setMsg("" + " "
+ " " + " ");
json.setData(mweb_url);
logger.info(return_msg);
}else{
json.setSuccess(false);
json.setMsg("插入数据库订单失败,out_trade_no="+out_trade_no);
json.setData(i);
logger.info("插入数据库订单失败");
}
return json;
}else{
logger.info("统一支付接口获取预支付订单出错");
json.setSuccess(false);
json.setMsg(return_msg);
json.setData(return_code);
return json;
}
} catch (Exception e) {
logger.info("统一支付接口获取预支付订单出错");
json.setSuccess(false);
json.setMsg("支付错误!");
json.setData(e.getMessage());
return json;
}
}
/**
* 微信H5支付回调
* @param request
* @param response
* @throws Exception
*/
@RequestMapping(value = "/h5Notify")
public void h5Notify(HttpServletRequest request, HttpServletResponse response) throws Exception {
BufferedReader reader = request.getReader();
String line = "";
Map map = new HashMap();
String xml = " ";;
JSONObject dataInfo = new JSONObject();
StringBuffer inputString = new StringBuffer();
while ((line = reader.readLine()) != null) {
inputString.append(line);
}
request.getReader().close();
logger.info("----接收到的报文---"+inputString.toString());
if(inputString.toString().length()>0){
map = com.haier.util.h5pay.XMLUtils.parseXmlToList(inputString.toString());
}else{
logger.info("接受微信报文为空");
}
logger.info("map="+map);
if(map!=null && "SUCCESS".equals(map.get("result_code"))){
//成功的业务。。。
int i = codeService.updateRechargeInfo(map,"SUCCESS",(String)map.get("return_code"),"h5Pay");
/**此处添加自己的业务逻辑代码end**/
if(i>0){
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
xml = "" + " "
+ " "
+ ""+ map.get("out_trade_no") +" "
+ ""+ map.get("transaction_id") +" "
+ ""+ map.get("total_fee") +" "
+ " ";
logger.info("支付成功");
}else{
//通知微信.异步确认成功.必写.不然会一直通知后台.八次之后就认为交易失败了.
xml = "" + " "
+ " "
+ ""+ map.get("out_trade_no") +" "
+ ""+ map.get("transaction_id") +" "
+ ""+ map.get("total_fee") +" "
+ " ";
logger.info("支付失败");
}
}else{
//失败的业务。。。
if(map!=null) {
codeService.updateRechargeInfo(map, "FAIL", (String) map.get("result_code"), "h5Pay");
}
xml = "" + " "
+ " " + " ";
logger.info("支付失败");
}
//告诉微信端已经确认支付成功
response.getWriter().write(xml);
}
@RequestMapping(value = "/h5Result/{totalFee}")
public ModelAndView h5Result(@PathVariable("totalFee") String totalFee){
ModelAndView mav = new ModelAndView();
mav.getModel().put("totalFee", totalFee);
mav.getModel().put("num",-2);
mav.setViewName("page/paySuccess");
return mav;
}
@RequestMapping(value = "/h5Query")
@ResponseBody
public JsonMsg h5Query(HttpServletRequest request, HttpServletResponse response) throws Exception {
JsonMsg json = new JsonMsg();
Map map = new HashMap();
map.put("body",java.net.URLDecoder.decode(request.getParameter("body"),"utf-8"));
map.put("result_code",request.getParameter("result_code"));
map.put("return_code",request.getParameter("return_code"));
map.put("out_trade_no",request.getParameter("out_trade_no"));
map.put("transaction_id",request.getParameter("transaction_id"));
map.put("total_fee",request.getParameter("total_fee"));
logger.info("map="+map);
if(map!=null && "SUCCESS".equals(map.get("return_code"))){
json.setSuccess(true);
json.setMsg(""
+ ""+map.get("result_code")+" "
+ ""+map.get("return_code")+" "
+ ""+ map.get("total_fee") +" "
+" ");
json.setData("支付成功");
}else if(map!=null){
String nonce_str = com.haier.util.h5pay.MD5Utils.getMessageDigest(String.valueOf(new Random().nextInt(10000)).getBytes());
//签名数据
StringBuilder sb = new StringBuilder();
sb.append("appid="+H5payConfig.APP_ID);
sb.append("&mch_id="+H5payConfig.MCH_ID);
sb.append("&nonce_str="+nonce_str);
sb.append("&out_trade_no="+map.get("out_trade_no"));
sb.append("&transaction_id="+map.get("transaction_id"));
sb.append("&key="+H5payConfig.API_KEY);
logger.info("sb="+sb);
//签名MD5加密
String sign = com.haier.util.wxpay.MD5Util.MD5Encode(sb.toString(),"utf-8").toUpperCase();
String xml=""+
""+ H5payConfig.APP_ID+" "+
""+ H5payConfig.MCH_ID+" "+
""+nonce_str+" "+
""+map.get("out_trade_no")+" "+
""+map.get("transaction_id")+" "+
""+sign+" "+
" ";
String queryOrderURL = H5payConfig.QURODER_URL;
try{
Map qmap = new HashMap();
//查询订单
qmap = com.haier.util.h5pay.WebUtils.getMwebUrl(queryOrderURL, xml);
if(qmap!=null&&"SUCCESS".equals(qmap.get("return_code"))){
if("SUCCESS".equals(qmap.get("result_code"))){
if("SUCCESS".equals(qmap.get("trade_state"))){
json.setSuccess(true);
json.setMsg(""
+ ""+map.put("body",java.net.URLDecoder.decode(request.getParameter("body"),"utf-8"))+""
+ ""+qmap.get("trade_state")+" "
+ ""+qmap.get("out_trade_no")+" "
+ ""+ qmap.get("total_fee") +" "
+" ");
json.setData("支付成功");
}else{
//out_trade_no必须传回
json.setSuccess(true);
json.setMsg(""
+ ""+map.put("body",java.net.URLDecoder.decode(request.getParameter("body"),"utf-8"))+""
+ ""+qmap.get("trade_state")+" "
+ ""+qmap.get("out_trade_no")+" "
+ ""+ qmap.get("total_fee") +" "
+" ");
json.setData(qmap.get("trade_state"));
}
}else{
//传回err_code和err_code_des
json.setSuccess(false);
json.setMsg(""
+ ""+map.put("body",java.net.URLDecoder.decode(request.getParameter("body"),"utf-8"))+""
+ ""+qmap.get("err_code")+" "
+ ""+qmap.get("err_code_des")+" "
+" ");
json.setData(qmap.get("err_code_des"));
}
}else{
json.setSuccess(false);
json.setMsg((String) qmap.get("return_msg"));
json.setData(new Date());
}
}catch (Exception e){
json.setSuccess(false);
json.setMsg(e.getMessage());
json.setData("产生异常");
}
}else{
json.setSuccess(false);
json.setMsg("报文为空");
json.setData("报文为空");
}
return json;
}
@RequestMapping(value = "/h5Redirect")
public ModelAndView h5Redirect(HttpServletRequest request, HttpServletResponse response) throws Exception{
ModelAndView mav = new ModelAndView();
Map map = new HashMap();
String outTradeNo = request.getParameter("out_trade_no").toString();
String token = URLEncoder.encode(request.getParameter("token").toString());
String tag = request.getParameter("tag").toString();
logger.info("redirect_token="+token);
if(!"".equals(outTradeNo)){
logger.info("outTradeNo:"+outTradeNo);
try {
int index = 0;
final int count = 8;
do{
index++;
logger.info(""+index+" time "+new Date());
FinWeixinRecord f = codeService.getFinWeixinRecord(outTradeNo);
if("SUCCESS".equals(f.getReturnCode())){
String totalFee = f.getTotalFee().toString();
Double d = Double.parseDouble(totalFee)/100;
BigDecimal b = BigDecimal.valueOf(d).setScale(2,BigDecimal.ROUND_HALF_DOWN);
totalFee = b.toString();
mav.getModel().put("totalFee", totalFee);
mav.getModel().put("body",f.getBody());
mav.getModel().put("token",token);
mav.getModel().put("num",-1);
mav.setViewName("page/paySuccess");
index=8;
}else{
String totalFee = f.getTotalFee().toString();
Double d = Double.parseDouble(totalFee)/100;
BigDecimal b = BigDecimal.valueOf(d).setScale(2,BigDecimal.ROUND_HALF_DOWN);
totalFee = b.toString();
mav.getModel().put("return_code",f.getReturnCode());
mav.getModel().put("out_trade_no",f.getOutTradeNo());
mav.getModel().put("transaction_id",f.getTransactionId());
mav.getModel().put("total_fee",totalFee);
mav.getModel().put("token",token);
if("1".equals(tag)){
mav.getModel().put("body","充值");
}else if("2".equals(tag)){
mav.getModel().put("body","充值");
}else{
mav.getModel().put("body","充值没有主题!请联系管理员");
}
mav.getModel().put("num",-2);
if(index==8) {
mav.setViewName("page/waiting");
}
}
Thread.sleep(5*1000);
}while(index
4、微信服务接口
4.1微信接口
public interface CodeService {
//数据库操作
//根据交易号获取微信记录表
FinWeixinRecord getFinWeixinRecord(String out_trade_no) throws Exception;
//更新微信记录
int updateFinWeixinRecode(FinWeixinRecord weixinRecord) throws Exception;
//更新交易信息
int updateRechargeInfo(Map params, String result, String tradeStatus,String orign) throws Exception;
//微信支付
String weixinPay(String ip,String amount, String productId,String userId,String businessId,String userType) throws Exception;
//小程序支付
int xcxPay(FinWeixinRecord weixinRecord) throws Exception;
//小程序获取Out_trade_No
String getOrderNo(String openid,String body,String money,String businessId,String userType,String userId,String orderCode);
//h5支付
int h5Pay(FinWeixinRecord f);
}
4.2 接口实现类
@Service
public class CodeServiceImpl implements CodeService {
Logger logger = LoggerFactory.getLogger(CodeServiceImpl.class);
@Autowired
private FinWeixinRecordDao finWeixinRecordDao;
@Autowired
private PrechargeRecordsDao prechargeRecordsDao;
@Autowired
private PrechargeInfoDao prechargeInfoDao;
@Autowired
private FinSettleCustDetailDao finSettleCustDetailDao;
@Override
public String weixinPay(String ip,String amount, String productId,String userId,String businessId,String userType) throws Exception {
BigDecimal totalFee = null;
if(amount == null || "".equals(amount)){
totalFee = new BigDecimal("0");
}
else{
totalFee = new BigDecimal(Double.valueOf(amount) * 100);
BigDecimal feevalue = new BigDecimal("100");
BigDecimal totalFee2 = new BigDecimal(amount).multiply(feevalue);
logger.info("微信参数" + totalFee.intValue() + "," + totalFee2.intValue());
}
String out_trade_no = getOutTradeNo(amount,userId,businessId,userType); //订单号 (调整为自己的生产逻辑)
if(out_trade_no==null||"".equals(out_trade_no)){
throw new RuntimeException("out_trade_no 为空值");
}
// 账号信息
String appid = PayConfigUtil.APP_ID; // appid
//String appsecret = PayConfigUtil.APP_SECRET; // appsecret
String mch_id = PayConfigUtil.MCH_ID; // 商业号
String key = PayConfigUtil.API_KEY; // key
String currTime = PayToolUtil.getCurrTime();
String strTime = currTime.substring(8, currTime.length());
String strRandom = PayToolUtil.buildRandom(4) + "";
String nonce_str = strTime + strRandom;
// 获取发起电脑 ip
String spbill_create_ip = ip;
// 回调接口
String notify_url = PayConfigUtil.NOTIFY_URL;
String trade_type = "NATIVE";
FinWeixinRecord f = new FinWeixinRecord();
f.setAppId(appid);
f.setMchId(mch_id);
f.setNonchStr(nonce_str);
f.setSpbllCreateIp(spbill_create_ip);
f.setTradeType(trade_type);
f.setOutTradeNo(out_trade_no);
f.setTotalFee(Long.parseLong(totalFee.toString()));
f.setBody("wxPay");
f.setGmtCreate(new Date());
f.setCreateUser(userId);
int j = finWeixinRecordDao.insert(f);
if(j>0){
//nothing to do
}else{
throw new RuntimeException("插入记录出错");
}
SortedMap packageParams = new TreeMap();
packageParams.put("appid", appid);
packageParams.put("mch_id", mch_id);
packageParams.put("nonce_str", nonce_str);
packageParams.put("body", "CCT"); //(调整为自己的名称)
packageParams.put("out_trade_no", out_trade_no);
packageParams.put("total_fee", totalFee.toString()); //价格的单位为分
packageParams.put("spbill_create_ip", spbill_create_ip);
packageParams.put("notify_url", notify_url);
packageParams.put("trade_type", trade_type);
String sign = PayToolUtil.createSign("UTF-8", packageParams,key);
packageParams.put("sign", sign);
String requestXML = PayToolUtil.getRequestXml(packageParams);
// System.out.println(requestXML);
logger.info(requestXML);
String resXml = HttpUtil.postData(PayConfigUtil.UFDODER_URL, requestXML);
// System.out.println(resXml);
logger.info(resXml);
Map map = XMLUtil4jdom.doXMLParse(resXml);
String urlCode = (String) map.get("code_url");
// System.out.println(urlCode);
logger.info(urlCode);
return urlCode;
}
@Transactional(rollbackFor = {Exception.class, RuntimeException.class})
private String getOutTradeNo(String amount, String userId, String businessId, String userType) {
String orderCode = SNUtil.create15();
PrechargeRecords prechargeRecords = new PrechargeRecords();
prechargeRecords.setBusinessId(businessId);
prechargeRecords.setUserType(userType);
prechargeRecords.setPrechargeValue(getAmount(amount));
prechargeRecords.setPrechargeType("01");//充值
prechargeRecords.setComefromId(userId);
prechargeRecords.setCreateUser(userId);
prechargeRecords.setPrechargeState("00");
prechargeRecords.setGmtCreate(new Date());
prechargeRecords.setPrechargeOrderCode(orderCode);
prechargeRecords.setPayType("wxPay");
//t_precharge_info
prechargeRecordsDao.insert(prechargeRecords);
//生成 SELECT GETOUTTRADENO() from DUAL
String outTradeNo = finWeixinRecordDao.getKey();
return outTradeNo;
}
@Override
public FinWeixinRecord getFinWeixinRecord(String out_trade_no) throws Exception {
FinWeixinRecord weixinRecord = finWeixinRecordDao.selectByOutTradeNo(out_trade_no);
return weixinRecord;
}
@Override
public int updateFinWeixinRecode(FinWeixinRecord weixinRecord) throws Exception {
return finWeixinRecordDao.updateNotifyPay(weixinRecord);
}
@Override
@Transactional(rollbackFor = {Exception.class, RuntimeException.class})
public int updateRechargeInfo(Map packageParams, String result, String tradeStatus,String orign) throws Exception {
String mch_id = (String)packageParams.get("mch_id");
String openid = (String)packageParams.get("openid");
String is_subscribe = (String)packageParams.get("is_subscribe");
String out_trade_no = (String)packageParams.get("out_trade_no");
String nostr = (String)packageParams.get("nonce_str");
String body = (String)packageParams.get("body");
String spbill = (String)packageParams.get("spbill_create_ip");
String prepayid = (String)packageParams.get("prepay_id");
String tradetype = (String)packageParams.get("trade_type");
String transaction_id = (String)packageParams.get("transaction_id");
String result_code = (String)packageParams.get("result_code");
String return_code = (String)packageParams.get("return_code");
String time_end = (String)packageParams.get("time_end");
String err_code = (String)packageParams.get("err_code");
String err_code_des = (String)packageParams.get("err_code_des");
//验证价格是否正确
FinWeixinRecord finWeixinRecord = finWeixinRecordDao.selectByOutTradeNo(out_trade_no);//来自数据库
String total_fee = (String)packageParams.get("total_fee");//来自服务器返回
logger.info("服务器返回total_fee="+total_fee+";数据库返回fee="+finWeixinRecord.getTotalFee().toString());
if(Math.abs(Integer.parseInt(total_fee)-Integer.parseInt(finWeixinRecord.getTotalFee().toString()))<=1){
logger.info(finWeixinRecord.getTotalFee().toString() + "===支付金额" + Integer.parseInt(total_fee));
updateRechargeOrderInfo(finWeixinRecord, packageParams, "01",orign);//支付成功
}else{
updateRechargeOrderInfo(finWeixinRecord, packageParams, "02",orign);//支付成功金额对应不上
}
FinWeixinRecord weixinRecord = new FinWeixinRecord();
weixinRecord.setMchId(mch_id);
weixinRecord.setOpenId(openid);
weixinRecord.setOutTradeNo(out_trade_no);
weixinRecord.setTotalFee(finWeixinRecord.getTotalFee());
weixinRecord.setNonchStr(nostr);
weixinRecord.setBody(body);
weixinRecord.setSpbllCreateIp(spbill);
weixinRecord.setPrePayId(prepayid);
weixinRecord.setTradeType(tradetype);
weixinRecord.setReturnCode(return_code);
weixinRecord.setErrorCode(err_code);
weixinRecord.setErrorCodeDes(err_code_des);
weixinRecord.setTransactionId(transaction_id);
weixinRecord.setTimeEnd(time_end);
weixinRecord.setModifiedUser("微信回调");
weixinRecord.setGmtModified(new Date());
int num = 0;
if("FAIL".equals(result)){
weixinRecord.setErrorCode(tradeStatus);
weixinRecord.setErrorCodeDes(return_code);
updateRechargeOrderInfo(weixinRecord, packageParams, "02",orign);//支付失败
}
else{
num = finWeixinRecordDao.updateNotify(weixinRecord);
}
return num;
}
@Override
public int xcxPay(FinWeixinRecord weixinRecord) throws Exception {
return finWeixinRecordDao.insert(weixinRecord);
}
@Override
@Transactional(rollbackFor = {Exception.class, RuntimeException.class})
public String getOrderNo(String openid,String body,String money,String businessId,String userType,String userId,String tempOrderCode) {
String orderCode = SNUtil.create15();
if(tempOrderCode!=null&&!tempOrderCode.equals("")){//继续支付
orderCode = tempOrderCode;
FinWeixinRecord finWeixinRecord = finWeixinRecordDao.selectByOrderCode(orderCode);
String outTradeNo = finWeixinRecord.getOutTradeNo();
return outTradeNo+","+orderCode;
}else{//支付
PrechargeRecords prechargeRecords = new PrechargeRecords();
prechargeRecords.setBusinessId(businessId);
prechargeRecords.setUserType(userType);
prechargeRecords.setPrechargeValue(getAmount(money));
prechargeRecords.setPrechargeType("01");//充值
prechargeRecords.setComefromId(userId);
prechargeRecords.setCreateUser(userId);
prechargeRecords.setPrechargeState("00");
prechargeRecords.setGmtCreate(new Date());
prechargeRecords.setPrechargeOrderCode(orderCode);
if(openid==null){
prechargeRecords.setPayType("h5Pay");
}else {
prechargeRecords.setPayType("xcxPay");
}
//t_precharge_info
prechargeRecordsDao.insert(prechargeRecords);
//生成 SELECT GETOUTTRADENO() from DUAL
String outTradeNo = finWeixinRecordDao.getKey();
return outTradeNo+","+orderCode;
}
}
@Override
public int h5Pay(FinWeixinRecord f) {
return finWeixinRecordDao.insert(f);
}
private Integer getAmount(String recAmount){
return new BigDecimal(recAmount).multiply(new BigDecimal(100)).intValue();
}
@Transactional(rollbackFor = {Exception.class, RuntimeException.class})
private int updateRechargeOrderInfo(FinWeixinRecord weixinRecord, Map packageParams, String payState,String orign) {
int upNum = 0;
Map map = new HashMap<>();
map.put("outTradeNo", weixinRecord.getOutTradeNo());
List list = (List)finWeixinRecordDao.selectForList("selectByNO",map);
for(FinWeixinRecord finWeixinRecord : list){
PrechargeRecords prechargeRecordsParam = new PrechargeRecords();
prechargeRecordsParam.setPrechargeOrderCode(finWeixinRecord.getOrderId());
PrechargeRecords prechargeRecords = prechargeRecordsDao.getPrechargeRecordsByOrderCode(prechargeRecordsParam);
if("01".equals(payState)){
if(null != prechargeRecords && "00".equals(prechargeRecords.getPrechargeState())){
//更新客户可用额度
PrechargeInfo prechargeInfoParm = new PrechargeInfo();
prechargeInfoParm.setBusinessId(prechargeRecords.getBusinessId());
prechargeInfoParm.setUserType(prechargeRecords.getUserType());
PrechargeInfo prechargeInfo = prechargeInfoDao.get4UpdAmount(prechargeInfoParm);
Integer availableAmount = 0;
if(null != prechargeInfo){
availableAmount = prechargeInfo.getAvailableValue() + Integer.parseInt(weixinRecord.getTotalFee().toString());
prechargeInfo.setAvailableValue(availableAmount);
prechargeInfo.setPrechargeValue(prechargeInfo.getPrechargeValue() + Integer.parseInt(weixinRecord.getTotalFee().toString()));
prechargeInfo.setModifiedUser(orign);
prechargeInfo.setGmtModified(new Date());
prechargeInfoDao.update(prechargeInfo);
logger.info("updateRechargeOrderInfo 更新t_precharge_info");
}else{
availableAmount = 0+Integer.parseInt(weixinRecord.getTotalFee().toString());
prechargeInfoParm.setAvailableValue(availableAmount);
prechargeInfoParm.setPrechargeValue(0+Integer.parseInt(weixinRecord.getTotalFee().toString()));
prechargeInfoParm.setCreateUser(orign);
prechargeInfoParm.setGmtCreate(new Date());
if("h5Pay".equals(orign)){
prechargeInfoParm.setDepostValue(10000);
}
int z = prechargeInfoDao.insert("insertSelective",prechargeInfoParm);
if(z>0){
logger.info("insertRechargeOrderInfo 插入t_precharge_info成功");
}else{
logger.info("insertRechargeOrderInfo 插入t_precharge_info失败");
}
}
//更新充值记录状态
prechargeRecords.setBusinessId(prechargeRecords.getBusinessId());
prechargeRecords.setPrechargeState("01");
prechargeRecords.setModifiedUser(orign);
prechargeRecords.setGmtModified(new Date());
prechargeRecords.setCurrentAvailableValue(availableAmount);
prechargeRecordsDao.update(prechargeRecords);
}
}else if("02".equalsIgnoreCase(payState)){
if(null != prechargeRecords && "00".equals(prechargeRecords.getPrechargeState())){
prechargeRecords.setPrechargeState("02");
prechargeRecords.setModifiedUser(orign);
prechargeRecords.setGmtModified(new Date());
prechargeRecordsDao.update(prechargeRecords);
}
}
upNum++;
//更新结算收款明细付款渠道
FinSettleCustDetail fin = new FinSettleCustDetail();
fin.setOrderCode(finWeixinRecord.getOrderId());
FinSettleCustDetail dbcustdetail = (FinSettleCustDetail) finSettleCustDetailDao.select("selectByPrimaryKey",finWeixinRecord.getOrderId());
if(null != dbcustdetail){
FinSettleCustDetail custdetail = new FinSettleCustDetail();
custdetail.setOrderCode(finWeixinRecord.getOrderId());
custdetail.setPayChannel(orign);//付款渠道
finSettleCustDetailDao.update(custdetail);
}
}
if(upNum != list.size()){
logger.error("未将全部订单支付状态更新");
}
return upNum;
}
}
5、代码片段
代码片段