栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

[微信支付] SpringMVC开发小案例

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

[微信支付] SpringMVC开发小案例

最近写了一个微信开发java版的,

先从微信支付官方(https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1)下载demo(java版),

1、服务号相关信息,填上相关的参数


public class ConfigUtil {

    
    public final static String APPID = "";
  
    public final static String MCH_ID = "";// 商户号
   
    public final static String API_KEY = "";// API密钥




}

2、因为微信支付的金额单位是元,所以在传输的时候需要将元转换为分,以下是转换包

import java.text.NumberFormat;
import java.text.ParseException;


//金额转换
public class moneyUtil{


    //分转元
    public static String changeY2F(Double amount){
        String currency =  amount.toString();
        int index = currency.indexOf(".");
        int length = currency.length();
        Long amLong = 0l;
        if(index == -1){
            amLong = Long.valueOf(currency+"00");
        }else if(length - index >= 3){
            amLong = Long.valueOf((currency.substring(0, index+3)).replace(".", ""));
        }else if(length - index == 2){
            amLong = Long.valueOf((currency.substring(0, index+2)).replace(".", "")+0);
        }else{
            amLong = Long.valueOf((currency.substring(0, index+1)).replace(".", "")+"00");
        }
        return amLong.toString();
    }


    //元转分
    public static String fenToYuan(String amount){
        NumberFormat format = NumberFormat.getInstance();
        try{
            Number number = format.parse(amount);
            double temp = number.doubleValue() / 100.0;
            format.setGroupingUsed(false);
            // 设置返回的小数部分所允许的最大位数
            format.setMaximumFractionDigits(2);
            amount = format.format(temp);
        } catch (ParseException e){
            e.printStackTrace();
        }
        return amount;
    }

}

3、其中也sign用到了md5加密,还有16位随机字符串,获取ip地址方法

    //md5大写
    public static String MD5Encode(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {

        StringBuilder sign = new StringBuilder();
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] bytes = md.digest(str.getBytes("utf-8"));

        for (int i = 0; i < bytes.length; i++) {
            String hex = Integer.toHexString(bytes[i] & 0xFF);
            if (hex.length() == 1) {
                sign.append("0");
            }
            sign.append(hex.toUpperCase());
        }
        return sign.toString();
    }


    
    public static String CreateNoncestr() {
        String chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        String res = "";
        for (int i = 0; i < 16; i++) {
            Random rd = new Random();
            res += chars.charAt(rd.nextInt(chars.length() - 1));
        }
        return res;
    }

 
    public static String getIpAddr(HttpServletRequest request) {
        InetAddress addr = null;
        try {
            addr = InetAddress.getLocalHost();
        } catch (UnknownHostException e) {
            return request.getRemoteAddr();
        }
        byte[] ipAddr = addr.getAddress();
        String ipAddrStr = "";
        for (int i = 0; i < ipAddr.length; i++) {
            if (i > 0) {
                ipAddrStr += ".";
            }
            ipAddrStr += ipAddr[i] & 0xFF;
        }
        return ipAddrStr;
    }

4、下单接口,因为自己第一次尝试写,其中有些没有用到方法,代码比较杂乱

//1、下单
    @RequestMapping("/createNative")
    public Object createNative(@RequestParam("outTradeNo") String outTradeNo, @RequestParam("totalFee") String totalFee,
                                                                        @RequestParam("body") String body,HttpServletRequest request)throws Exception {
        //解决中文乱码
        body  = new String(body.getBytes("iso-8859-1"), "utf-8");

        try {
            request.setCharacterEncoding("UTF-8");
            SortedMap req = new TreeMap();
            req.put("appid", ConfigUtil.APPID);
            req.put("mch_id", ConfigUtil.MCH_ID);

            req.put("out_trade_no", outTradeNo);
            totalFee= moneyUtil.changeY2F(Double.valueOf(totalFee));
            req.put("total_fee", totalFee);
            req.put("body",body);

            // 32位随机字符串
            String random = PayCommonUtil.CreateNoncestr();

            req.put("nonce_str", random);
            // 获取ip地址
            req.put("spbill_create_ip", PayCommonUtil.getIpAddr(request));

            String notify_url = "http://www.huiyouar.com/WeiXinSmpay/WeixinNotify";
            req.put("notify_url",notify_url );
            req.put("trade_type", "NATIVE");

            String sppend = "appid="+ConfigUtil.APPID+"&body="+body+"&mch_id="+ConfigUtil.MCH_ID+
                    "&nonce_str="+random+"¬ify_url="+notify_url+"&out_trade_no="+outTradeNo+
                    "&spbill_create_ip="+PayCommonUtil.getIpAddr(request)+
                    "&total_fee="+totalFee+"&trade_type=NATIVE&key="+ConfigUtil.API_KEY;


            String sign = PayCommonUtil.MD5Encode(sppend);
            req.put("sign", sign);


            //生成XML
            String xmlBody = WXPayUtil.generateSignedXml(req, ConfigUtil.API_KEY);

            String sendurl = "https://api.mch.weixin.qq.com/pay/unifiedorder";
            String result = PayCommonUtil.httpsRequest(sendurl, "POST", xmlBody);

            Map resultMap = WXPayUtil.xmlToMap(result);

            if(resultMap.get("result_code").equals("SUCCESS")){
                return resultMap.get("code_url");
            }else{
                return JSON.toJSONString(resultMap);
            }
        } catch (Exception e) {
            e.printStackTrace();
            return "请求异常";
        }
    }

以上代码可以就实现微信支付了,

接下来是微信支付查询接口

1、

//3、查询
@SneakyThrows
@RequestMapping("/queryOrder")
public String queryOrder(@RequestParam("out_trade_no") String out_trade_no){

    SortedMap parameters = new TreeMap();
    parameters.put("appid", ConfigUtil.APPID);
    parameters.put("mch_id", ConfigUtil.MCH_ID);
    // 随机字符串
    String randomString = PayCommonUtil.CreateNoncestr();
    parameters.put("nonce_str", randomString);
    parameters.put("out_trade_no", out_trade_no);

    //签名校验
    String append = "appid="+ConfigUtil.APPID+"&mch_id="+ConfigUtil.MCH_ID+"&nonce_str="+randomString+"&out_trade_no="+out_trade_no+"&key="+ConfigUtil.API_KEY;
    String sign = PayCommonUtil.MD5Encode(append);
    parameters.put("sign", sign);

    //生成XML
    String requestXML = WXPayUtil.generateSignedXml(parameters, ConfigUtil.API_KEY);


    String url = "https://api.mch.weixin.qq.com/pay/orderquery";
    String result = PayCommonUtil.httpsRequest(url, "POST", requestXML);

    //返回结果
    Map resultMap = WXPayUtil.xmlToMap(result);
    String return_code =resultMap.get("return_code");
    String result_code =resultMap.get("result_code");
    String trade_state =resultMap.get("trade_state");
    if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("SUCCESS")){
        return "支付成功";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("REFUND")){
        return "转入退款 ";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("NOTPAY")){
        return "订单未支付 ";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("CLOSED")){
        return "订单已关闭 ";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("REVOKED")){
        return "已撤销(刷卡支付)  ";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("USERPAYING")){
        return "用户支付中  ";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("PAYERROR")){
        return "支付失败(其他原因,如银行返回失败)";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("PAYERROR")){
        return "支付失败(其他原因,如银行返回失败)";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("SUCCESS")&&trade_state.equals("ACCEPT")){
        return "已接收,等待扣款";
    }else if(return_code.equals("SUCCESS")&&result_code.equals("FAIL")&&resultMap.get("err_code_des").equals("订单不存在")){
        return "订单不存在";
    }else {
        return String.valueOf(resultMap);
    }

}

2、关闭订单接口

//2、关闭订单
@RequestMapping("/closeOrder")
public String closeOrder(@RequestParam("out_trade_no") String out_trade_no) throws Exception {

    SortedMap parameters = new TreeMap();
    parameters.put("appid", ConfigUtil.APPID);
    parameters.put("mch_id", ConfigUtil.MCH_ID);
    // 随机字符串
    String randomString = PayCommonUtil.CreateNoncestr();
    parameters.put("nonce_str", randomString);
    parameters.put("out_trade_no", out_trade_no);

    String append = "appid="+ConfigUtil.APPID+"&mch_id="+ConfigUtil.MCH_ID+"&nonce_str="+randomString+"&out_trade_no="+out_trade_no+"&key="+ConfigUtil.API_KEY;

    String sign = PayCommonUtil.MD5Encode(append);
    parameters.put("sign", sign);

    //生成XML
    String requestXML = WXPayUtil.generateSignedXml(parameters, ConfigUtil.API_KEY);


    String url = "https://api.mch.weixin.qq.com/pay/closeorder";
    String result = PayCommonUtil.httpsRequest(url, "POST", requestXML);

    Map resultMap = WXPayUtil.xmlToMap(result);
    String  resultCode = resultMap.get("return_code");
    if(resultCode.equals("SUCCESS")){
        return "订单取消成功";
    }else{
        return "订单取消失败";
    }


}

 3、退款接口有些麻烦,他需要用到证书,不然会报错,百度查了告诉我是缺少证书,加载进来就可以实现功能了,

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyStore;
import javax.net.ssl.SSLContext;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;


public class CommonUtil {
    private static int socketTimeout = 10000;// 连接超时时间,默认10秒
    private static int connectTimeout = 30000;// 传输超时时间,默认30秒
    private static RequestConfig requestConfig;// 请求器的配置
    private static CloseableHttpClient httpClient;// HTTP请求器

    public static String postData(String url, String xmlObj, String path) {
        try {
            // 加载证书
            initCert(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = null;
        HttpPost httpPost = new HttpPost(url);
        // 得指明使用UTF-8编码,否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);
        // 根据默认超时限制初始化requestConfig
        requestConfig = RequestConfig.custom().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout).build();
        // 设置请求器的配置
        httpPost.setConfig(requestConfig);
        try {
            HttpResponse response = null;
            try {
                response =  httpClient.execute(httpPost);
            }  catch (IOException e) {
                e.printStackTrace();
            }
            HttpEntity entity = response.getEntity();
            try {
                result = EntityUtils.toString(entity, "UTF-8");
            }  catch (IOException e) {
                e.printStackTrace();
            }
        } finally {
            httpPost.abort();
        }
        return result;
    }

    
    @SuppressWarnings("deprecation")
    private static void initCert(String path) throws Exception {
        // 证书密码,默认为商户ID
        String key = ConfigUtil.MCH_ID;
        // 指定读取证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        // 读取本机存放的PKCS12证书文件
        FileInputStream instream = new FileInputStream(new File(path));
        try {
            // 指定PKCS12的密码(商户ID)
            keyStore.load(instream, key.toCharArray());
        } finally {
            instream.close();
        }
        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();
        // 指定TLS版本
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        // 设置httpclient的SSLSocketFactory
        httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }

}

退款接口

//4、退款-----证书
@SneakyThrows
@RequestMapping("/refundOrder")
public String refundOrder(@RequestParam("out_trade_no") String out_trade_no,@RequestParam("out_refund_no")  String out_refund_no,
                          @RequestParam("total_fee")  String total_fee,@RequestParam("refund_fee")String refund_fee){

    SortedMap parameters = new TreeMap();
    parameters.put("appid", ConfigUtil.APPID);
    parameters.put("mch_id", ConfigUtil.MCH_ID);
    // 随机字符串
    String randomString = PayCommonUtil.CreateNoncestr();
    parameters.put("nonce_str", randomString);

    parameters.put("out_trade_no", out_trade_no);
    //退款订单号
    parameters.put("out_refund_no", out_refund_no);
    //退款金额
    total_fee = chang2F.changeY2F(Double.valueOf(total_fee));
    parameters.put("total_fee", total_fee);
    refund_fee = moneyUtil.changeY2F(Double.valueOf(refund_fee));
    parameters.put("refund_fee", refund_fee);

    //签名校验
    String append = "appid="+ConfigUtil.APPID+"&mch_id="+ConfigUtil.MCH_ID+"&nonce_str="+randomString+"&out_refund_no="+out_refund_no +"&out_trade_no="+
                                                        out_trade_no+"&refund_fee="+refund_fee+"&total_fee="+total_fee+"&key="+ConfigUtil.API_KEY;

    String sign = PayCommonUtil.MD5Encode(append);
    parameters.put("sign", sign);

    //生成XML
    String requestXML = WXPayUtil.generateSignedXml(parameters, ConfigUtil.API_KEY);
    String imgPath = "证书目录"+"apiclient_cert.p12";

    String url = "https://api.mch.weixin.qq.com/secapi/pay/refund";

    String result =   CommonUtil.postData(url,requestXML,imgPath);

    Map resultMap = WXPayUtil.xmlToMap(result);
    String return_code = resultMap.get("return_code");
    if(return_code.equals("SUCCESS")){
        return "退款申请接收成功";
    }else{
        return JSON.toJSONString(resultMap);
    }

}

 退款查询接口

//5、退款查询
@SneakyThrows
@RequestMapping("/refundqueryOrder")
public String refundqueryOrder(@RequestParam("out_trade_no") String out_trade_no){

    SortedMap parameters = new TreeMap();
    parameters.put("appid", ConfigUtil.APPID);
    parameters.put("mch_id", ConfigUtil.MCH_ID);
    String ramdomString = PayCommonUtil.CreateNoncestr();
    parameters.put("nonce_str",ramdomString );// 随机字符串
    parameters.put("out_trade_no", out_trade_no);

    String append = "appid="+ConfigUtil.APPID+"&mch_id="+ConfigUtil.MCH_ID+"&nonce_str="+ramdomString+"&out_trade_no="+out_trade_no+"&key="+ConfigUtil.API_KEY;

    String sign = PayCommonUtil.MD5Encode(append);
    parameters.put("sign", sign);

    //生成XML
    String requestXML = WXPayUtil.generateSignedXml(parameters, ConfigUtil.API_KEY);

    String url = "https://api.mch.weixin.qq.com/pay/refundquery";
    String result = PayCommonUtil.httpsRequest(url, "POST", requestXML);

    Map resultMap = WXPayUtil.xmlToMap(result);
    return JSON.toJSONString(resultMap);

}

还有一些就是springmvc配置



	
	 
    
    
    
        
        
        
        
    

    
    
    
        
        
        
            
                
                    
                        text/html;charset=utf-8
                    
                
            
        
    

 web.xml配置





        dispatcherServlet
        org.springframework.web.servlet.DispatcherServlet
    
        contextConfigLocation
        classpath:springmvc.xml
    
    1


    dispatcherServlet
    /


    
    
        SpringEncodingFilter
        org.springframework.web.filter.CharacterEncodingFilter
        
            encoding
            UTF-8
        
        
            forceEncoding
            true
        
    
    
        SpringEncodingFilter
        /*
    

因为我下单接口返回的是链接,如果需要生成图片的话,以下是util

package com.saihui.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Hashtable;

public class ImageUtil {
    public static String image(String trl) {
        //二维码宽度
        int width=300;
        //二维码高度
        int height=300;
        //定义二维码图片格式
        String format="png";

        //定义二维码属性
        Hashtable his=new Hashtable();
        //二维码内容的编码格式
        his.put(EncodeHintType.CHARACTER_SET,"utf-8");
        //定义二维码边距
        his.put(EncodeHintType.MARGIN,"1");


        //创建位矩阵对象并且生成二维码对应的位矩阵对象
        //BarcodeFormat.QR_CODE  生成图片类型为QRCode
        BitMatrix bitMatrix= null;
        try {
            bitMatrix = new MultiFormatWriter().encode(trl, BarcodeFormat.QR_CODE,width,height);
        } catch (Exception e) {
            e.printStackTrace();
        }
        //二维码生成路径
        String path="D:\";
        //二维码生成名字
        String name="myBlog.png";

        Path path2= Paths.get(path,name);
        //生成二维码
        try {
            MatrixToImageWriter.writeToPath(bitMatrix, format, path2);
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("二维码生成成功");
        return format;
    }


}

 在controller里改成out.write(ImageUtil.image("微信支付返回的链接"));就可以了,把@RestController改成@Controller

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1031378.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号