【SpringBoot2 微信支付实例】

1、 POM添加微信开发支持

<parent>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-parent</artifactId>
	<version>2.0.5.RELEASE</version>
	<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
	<groupId>com.github.wxpay</groupId>
	<artifactId>wxpay-sdk</artifactId>
	<version>0.0.3</version>
</dependency>

2、yml配置

weixin:
  #正式环境
  wxpay:
    useSandbox: true
    app_id: adfasfasdfsdf //公众账号ID
    mch_id: 134dddddd4901// 商户号
    key: 13579246800987654321abcdefssssghijkl// 商户密钥
    certPath: src/weixin/apiclient_cert.p12//从微信商户平台下载的安全证书存放的路径
    spbill_create_ip: 114.55.200.128 //APP和网页支付提交用户端ip, Native支付填调用微信支付API的机器IP, 即:服务器ip地址
    notify_url: // 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。(需要配置)
    trade_type: NATIVE
    placeanorder_url: https://api.mch.weixin.qq.com/pay/unifiedorder
    return_url_html: // 微信支付 - 统一下单地址
    sandboxSignKeyurl: https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey
    attach: 教育

3、wechatConfig配置文件获取yml配置

@Data
@Configuration
public class WeChatConfig {

    @Value("${weixin.wxpay.useSandbox}")
    private boolean useSandbox;//是否沙箱环境
    @Value("${weixin.wxpay.app_id}")
    public  String app_id;		// 公众账号ID
    @Value("${weixin.wxpay.mch_id}")
    public  String mch_id ;		// 商户号
    @Value("${weixin.wxpay.key}")
    public  String key;		// 商户密钥
    @Value("${weixin.wxpay.certPath}")
    public  String certPath =
            ClassUtils.getDefaultClassLoader().getResource("").getPath()+"/weixin/apiclient_cert.p12";
    //从微信商户平台下载的安全证书存放的路径
    // APP和网页支付提交用户端ip, Native支付填调用微信支付API的机器IP, 即:服务器ip地址
    @Value("${weixin.wxpay.spbill_create_ip}")
    public  String spbill_create_ip;
    // 接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。(需要配置)
    @Value("${weixin.wxpay.notify_url}")
    public  String notify_url;
    // 支付方式,取值如下:JSAPI,NATIVE,APP
    @Value("${weixin.wxpay.trade_type}")
    public  String trade_type;
    @Value("${weixin.wxpay.placeanorder_url}")
    // 微信支付 - 统一下单地址
    public  String placeanorder_url;
    @Value("${weixin.wxpay.attach}")
    public String attach;
}

4、支付代码处理文件

controller层

/**
 * 正式使用环境
 * @param id
 * @param req
 * @param response
 * @return
 * @throws Exception
 */
@RequestMapping(value = "/pay", method = {RequestMethod.GET, RequestMethod.POST})
public BaseResponse orderPay(@RequestParam Integer id,@RequestParam(required = false) Integer acuId,
							 HttpServletRequest req, HttpServletResponse response) throws Exception {
	log.info("进入微信支付申请");
	DlOrder dlOrder = idlOrderService.get(id);
	String out_trade_no=dlOrder.getOdUuid();  // 需要前端给的参数

	//获取金额,根据业务逻辑获取
	String total_fee = idlOrderService.useOrNotCoupon(dlOrder,acuId); //微信支付钱的单位为分
	log.info("支付金额:",total_fee);
	//String user_id= dlOrder.getCreateUser();               //

	String attach=weChatConfig.getAttach();
	String spbill_create_ip= weChatConfig.getSpbill_create_ip();//IP地址
	log.info(spbill_create_ip);
	//生成订单
	Map<String,String> result = wxOrderService.dounifiedOrder(id,attach,out_trade_no,total_fee,spbill_create_ip,1);

	if (null != result)
	{
		String code_url = result.get("code_url");
		log.info("返回图片地址:{}",code_url);
		BufferedImage image = PayUtil.getQRCodeImge(code_url);
		response.setContentType("image/jpeg");
		response.setHeader("Pragma","no-cache");
		response.setHeader("Cache-Control","no-cache");
		response.setIntHeader("Expires",-1);
		ImageIO.write(image, "JPEG", response.getOutputStream());
		return successToJson(result,"获取微信支付订单成功");
	}else {
	   return fail("获取微信支付订单失败");
	}
	//return resultString;    //给前端app返回此字符串,再调用前端的微信sdk引起微信支付
}
service层:
//生成订单
@Override
public Map<String, String> dounifiedOrder(Integer id,String attach, String out_trade_no,
										  String total_fee, String spbill_create_ip, int type) throws Exception {
	//第一步、查询微信服务器是否有订单
	//第二步、有,则关闭先前的订单
	//第三步、生成新订单
	WXPay wxpay = new WXPay(config, WXPayConstants.SignType.HMACSHA256,false);
	//微信生成订单参数
	Map<String, String> data = convertToWXData(attach,out_trade_no,total_fee,spbill_create_ip,type);
	StringBuffer url= new StringBuffer();
	Map<String,String> existsresp = getExistOrder(wxpay,out_trade_no);
	String existsresp_return_code = existsresp.get("return_code");
	String existsresp_trade_state= existsresp.get("trade_state");
	String existsresp_result_code= existsresp.get("result_code");
	log.info("查询订单:{}",JSON.toJSONString(existsresp));
	log.info("更新前out_trade_no:{}",out_trade_no);
	if ("SUCCESS".equals(existsresp_return_code))
	{
		log.info("关闭已有订单,订单existsresp_return_code:{},existsresp_result_code:{},existsresp_trade_state:{}",
				existsresp_return_code,existsresp_result_code,existsresp_trade_state);
		if ("SUCCESS".equals(existsresp_result_code)
				&& ("NOTPAY".equals(existsresp_trade_state)||"CLOSED".equals(existsresp_trade_state)))
		{
			log.info("关闭已有订单,订单existsresp_result_code:{}",existsresp_result_code);
			closeOrder(wxpay,out_trade_no);
			//更改订单UUID
			out_trade_no = StringUtil.getOrderID();
			data.put("out_trade_no",out_trade_no);
			DlOrder dlOrder = new DlOrder();
			dlOrder.setId(id);
			dlOrder.setOdUuid(out_trade_no);
			int i = dlOrderMapper.updateByID(dlOrder);
			log.info("更新后out_trade_no:{}",out_trade_no);
		}
	}
	try {
		Map<String, String> resp = wxpay.unifiedOrder(data);
		String returnCode = resp.get("return_code");    //获取返回码
		String returnMsg = resp.get("return_msg");
		//String  nonce_str = resp.get("nonce_str");//微信返回的随机字符串
		log.info("生成订单的结果:{}",JSON.toJSONString(resp));
		if("SUCCESS".equals(returnCode)){       //若返回码为SUCCESS,则会返回一个result_code,再对该result_code进行判断
			String resultCode = resp.get("result_code");
			String errCodeDes = resp.get("err_code_des");
			log.info(resultCode);
			if("SUCCESS".equals(resultCode)){
				//获取预支付交易回话标志
				return convertToWXRst(resp,data);
			}else {
				//订单已经生成的情况下,直接查询订单返回
				Map<String,String> existsresp2 = getExistOrder(wxpay,out_trade_no);
				log.info("已经存在的订单1:{}",JSON.toJSONString(existsresp2));
				log.info("订单号:{},错误信息:{}",out_trade_no,errCodeDes);
				return convertToWXRst(existsresp2,data);
			}
		}else {
			//订单已经生成的情况下,直接查询订单返回
			Map<String,String> existsresp2 = getExistOrder(wxpay,out_trade_no);
			log.info("已经存在的订单2:{}",JSON.toJSONString(existsresp2));
			log.info("订单号:{},错误信息:{}",out_trade_no,returnMsg);
		}
	} catch (Exception e) {
		log.info(e.getMessage());
	}
	return null;
}
/**
 * 微信生成订单参数
 * @param attach
 * @param out_trade_no
 * @param total_fee
 * @param spbill_create_ip
 * @param type
 * @return
 * @throws Exception
 */
private Map<String, String> convertToWXData(String attach, String out_trade_no,
											String total_fee, String spbill_create_ip, int type) throws Exception {
	Map<String, String> data = new HashMap<String, String>();
	String body="订单支付";
	data.put("appid",weChatConfig.getApp_id());
	data.put("mch_id",weChatConfig.getMch_id());
	data.put("nonce_str",WXPayUtil.generateNonceStr());
	data.put("body", body);
	data.put("out_trade_no", out_trade_no);
	data.put("total_fee", total_fee);
	data.put("spbill_create_ip",spbill_create_ip);
	//异步通知地址(请注意必须是外网)
	data.put("notify_url", weChatConfig.getNotify_url());
	data.put("trade_type", weChatConfig.getTrade_type());
	data.put("attach", attach);
	String signtmp = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.HMACSHA256);
	data.put("sign", signtmp);
	log.info("微信环境类型:{}",config.isUseSandbox());

	return data;
}
/**
 * 查询已有订单
 * @param wxpay
 * @param out_trade_no
 * @return
 * @throws Exception
 */
@Override
public Map<String,String> getExistOrder(WXPay wxpay, String out_trade_no) throws Exception {
	Map<String,String> data = new HashMap<>();
	data.put("out_trade_no",out_trade_no);
	data.put("mch_id",weChatConfig.getMch_id());
	Map<String, String> existsresp = wxpay.orderQuery(data);
	log.info("查看是否有存在的订单:{}",JSON.toJSONString(existsresp));
	return existsresp;
}
/**
* 获取订单返回值
* @param resp
* @param data
* @return
* @throws Exception
*/
private Map<String,String> convertToWXRst(Map<String, String> resp,Map<String, String> data) throws Exception {
Map<String,String> map = new HashMap<>();
String prepay_id = resp.get("prepay_id");
map.put("appid",weChatConfig.getApp_id());
map.put("mch_id",weChatConfig.getMch_id());
map.put("prepayid",prepay_id);
map.put("package","Sign=WXPay");
map.put("noncestr",resp.get("nonce_str"));
map.put("timestamp",String.valueOf(System.currentTimeMillis()/1000));
String sign = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.HMACSHA256);
map.put("sign",sign);
map.put("timestamp",resp.get("timestamp"));
map.put("package","WXPay");
map.put("code_url",resp.get("code_url"));
map.put("return_code",resp.get("return_code"));
map.put("result_code",resp.get("result_code"));

if (null != resp.get("trade_state") && "SUCCESS".equals(resp.get("trade_state"))) {
//对于已经支付成功的订单,直接修改订单的状态
		//需要判断是否已经支付,只有未支付才需要修改
		String out_trade_no = resp.get("out_trade_no");
		DlOrder order = dlOrderMapper.getOrderByUUID(out_trade_no);
		if(null !=order.getOdStatusCode()
		&& "O2".equals(order.getOdStatusCode())) {
			DlOrder dlOrder = new DlOrder();
			dlOrder.setOdUuid(resp.get("out_trade_no"));
			dlOrder.setOdStatusCode("O3");
			dlOrder.setOdStatusName("已支付");
			dlOrder.setModifyTime(new Date());
			dlOrder.setModifyUser("admin@qq.com");
			BigDecimal total_fee = new BigDecimal(resp.get("total_fee"));
			dlOrder.setOdOutOfPocket(total_fee.multiply(new BigDecimal("100")));

			int update = dlOrderMapper.update(dlOrder);
			//插入一条支付成功的记录
			this.insertPaymentLog(resp,out_trade_no,resp.get("nonce_str"));
		}
	}
	return map;
}

 5、微信服务同步通知页面

/**
     * 订单支付异步通知
     */
    @ApiOperation(value = "手机订单支付完成后回调")
    @RequestMapping(value = "/notify",method = {RequestMethod.GET, RequestMethod.POST})
    public String WXPayBack(HttpServletRequest request,HttpServletResponse response){
        String resXml="";
        log.info("======================>>>微信支付回调<<======================");
        try{
            //
            InputStream is = request.getInputStream();
            //将InputStream转换成String
            BufferedReader reader = new BufferedReader(new InputStreamReader(is));
            StringBuilder sb = new StringBuilder();
            String line = null;
            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line + "
");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            resXml=sb.toString();
            //实例测试代码
/*            resXml = "<xml><appid><![CDATA[wx7a5088333e7a7234]]></appid>
" +
                    "<attach><![CDATA[82569575@qq.com,7]]></attach>
" +
                    "<bank_type><![CDATA[CFT]]></bank_type>
" +
                    "<cash_fee><![CDATA[1]]></cash_fee>
" +
                    "<fee_type><![CDATA[CNY]]></fee_type>
" +
                    "<is_subscribe><![CDATA[N]]></is_subscribe>
" +
                    "<mch_id><![CDATA[1348674901]]></mch_id>
" +
                    "<nonce_str><![CDATA[51eec4509f68473da0a660baabaab8a9]]></nonce_str>
" +
                    "<openid><![CDATA[owyu2v00-fp62nZa-fRvEl2doR1w]]></openid>
" +
                    "<out_trade_no><![CDATA[2019081211264961401245689]]></out_trade_no>
" +
                    "<result_code><![CDATA[SUCCESS]]></result_code>
" +
                    "<return_code><![CDATA[SUCCESS]]></return_code>
" +
                    "<sign><![CDATA[BDA7CBAA80954C531F5E100559A34992]]></sign>
" +
                    "<time_end><![CDATA[20190813100643]]></time_end>
" +
                    "<total_fee>1</total_fee>
" +
                    "<trade_type><![CDATA[NATIVE]]></trade_type>
" +
                    "<transaction_id><![CDATA[4200000398201908134997424507]]></transaction_id>
" +
                    "</xml>";*/
            //log.info("回调返回的xml结果值:{}",resXml);
            String out_trade_no = wxOrderService.payBack(resXml);
            if (null != out_trade_no) {
                Thread t = new Thread(new Runnable() {
                    @Override
                    public void run() {
                        //发送邮件
                        log.info("启动一个线程,微信发送下单邮件。线程编号:{}",Thread.currentThread().getName());
                        sendPlaceOrderMail(out_trade_no);
                    }
                });
                t.start();
            }
            log.info("支付成功,回调结果:{}",out_trade_no);
            return toPaySuccess(out_trade_no);
            //return result;
        }catch (Exception e){
            log.error("手机支付回调通知失败",e);
            String result = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>" + "<return_msg><![CDATA[报文为空]]></return_msg>" + "</xml> ";
            return result;
        }
    }

    /***
     * 查看支付状态
     * @param id
     * @param req
     * @param response
     * @return
     */
    @ApiOperation(value = "微信手机订单支付状态")
    @RequestMapping(value = "/getWXPayStatus",method = {RequestMethod.GET, RequestMethod.POST})
    public BaseResponse getWXPayStatus(@RequestParam Integer id,
                                       HttpServletRequest req, HttpServletResponse response){
        try {
            DlOrder dlOrder = idlOrderService.get(id);
            Map<String, String> wxPayStatus = wxOrderService.getWXPayStatus(dlOrder.getOdUuid());
            if (null != wxPayStatus)
            {
                /*{"transaction_id":"4200000376201908143196470846","nonce_str":"GNAGvXoqGWHocktm","trade_state":"SUCCESS",
                        "bank_type":"CFT","openid":"owyu2v00-fp62nZa-fRvEl2doR1w",
                        "sign":"06334CB9CFB0C65C5D09488AEA20A0E32BB323A3D095FAD46EAC843AD430C6B8",
                        "return_msg":"OK","fee_type":"CNY","mch_id":"1348674901",
                        "cash_fee":"1","out_trade_no":"2019081411420931412345679",
                        "appid":"wx7a5088333e7a7234","total_fee":"1",
                        "trade_state_desc":"支付成功","trade_type":"NATIVE","result_code":"SUCCESS",
                        "attach":"点教点育","time_end":"20190814114313","is_subscribe":"N","return_code":"SUCCESS"}*/
                if ("SUCCESS".equals(wxPayStatus.get("return_code"))
                    &&"SUCCESS".equals(wxPayStatus.get("result_code"))
                    &&"SUCCESS".equals(wxPayStatus.get("trade_state")))
                {
                    return successToJson("支付成功");
                }
            }
        } catch (Exception e) {
            log.info("---------------获取微信支付状态失败------------------");
            e.printStackTrace();
        }
        return fail("支付中");
    }
    /**
     * 成功业务处理
     * @param out_trade_no  订单ID,本地业务订
     * @return
     */
    private String toPaySuccess(String out_trade_no){
        String return_url_html = alipayConfig.getReturn_url_html();
        //前后分离形式  直接返回页面 记得加上注解@Response  http://login.calidray.com你要返回的网址,再页面初始化时候让前端调用你其他接口,返回信息
        StringBuilder sbd = new StringBuilder();
        sbd.append("<form action="");
        sbd.append(return_url_html);
        sbd.append("#/payForSuccess?odUuid=");
        sbd.append(out_trade_no);
        sbd.append("" method="get" name="form1">
");
        sbd.append("</form>
");
        sbd.append("<script>document.forms[0].submit();</script>");

        // 如果使用优惠券,更新优惠券已经使用
        DlOrder order = idlOrderService.getByUUID(out_trade_no);
        dlActiveCouponUserService.setAcuIsUsed(order);

        log.info("跳转页面:{}",sbd.toString());
        return sbd.toString();
    }

集成成功,请测试!