• 微信小程序基于java实现v2支付,提现,退款


    v2支付

    v2微信官方文档

    封装支付请求实体

    import io.swagger.annotations.ApiModelProperty;
    import lombok.Getter;
    import lombok.Setter;
    
    import java.math.BigDecimal;
    
    @Getter
    @Setter
    public class WeixinPayForm{
    
    	@ApiModelProperty("支付信息")
    	private String body;
    
    	@ApiModelProperty("请求ip")
    	private String ip;
    
    	@ApiModelProperty("交易订单号")
    	private String outTradeNo;
    
    	@ApiModelProperty("总金额")
    	private BigDecimal totalAmount;
    
    	@ApiModelProperty("小程序openid")
    	private String openId;
    
    	@ApiModelProperty("支付回调地址")
    	private String notifyUrl;
    	
    	//app,xcx,gzh
    	@ApiModelProperty("xcx")
    	private String wxType;
    
    	@ApiModelProperty("支付信息")
    	private String authCode;
    	
    	//门店编号
    	@ApiModelProperty("设备信息")
    	private String deviceInfo;
    
    	@ApiModelProperty("商户id")
    	private String subMchId;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    controller接口暴露层

    	@ApiOperation(value = "支付下单")
    	@ResponseBody
    	@RequestMapping(value={"/buy"}, method=RequestMethod.POST)
            
    		String message = payService.payFoodOrder( orderNo, new PayBaseForm(payMethod, this.getApplicationType(), this.getRequestIp()));
    		return CommonResult.success(message);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    payFoodOrder 支付接口实现类

     public String payFoodOrder(UmsMember member, String orderNo, PayBaseForm baseForm)  {
            //查询订单 可以根据实际业务来 目前写死是为了方便理解 实际业务可以换成对应实体参数
            WeixinPayForm wxform = new WeixinPayForm();
            wxform.setBody("订单支付");
            wxform.setIp(getRequestIp());
         	//商户订单号
            wxform.setOutTradeNo("0010001");
         	//总金额
            wxform.setTotalAmount(new BigDecimal(100));
            wxform.setWxType("xcx");
            wxform.setDeviceInfo("cccc");
            wxform.setOpenId("xccxxx*********");
            //支付回调地址
            wxform.setNotifyUrl(WechatUtil.getPayNotifyUrl() + WXPAY_NOTIFY_URL_FOOD_ORDER);
            wxform.setSubMchId("商户号id");
            return new WeixinPay().pay(wxform);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    获取请求ip

    	
    	public String getRequestIp(){
    		HttpServletRequest request = this.getRequest();
    		String ip = request.getHeader("x-forwarded-for");
    		if(ip == null) {
    			ip = request.getRemoteAddr();
    		} else {
    			String[] ips = ip.split(",");
    			ip = ips[0];
    		}
    		
    		return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    wxform.setNotifyUrl(WechatUtil.getPayNotifyUrl() + WXPAY_NOTIFY_URL_FOOD_ORDER);

    这个回调地址是你自己代码里面定义的回调接口,例如你定义的controller回调接口url是 feedback/wx/notifurl ,
    即是 wxform.setNotifyUrl(“feedback/wx/notifurl”),微信终端会去调用这个回调方法的,可以通过日志确认。

    WeixinPay().pay(wxform)方法

    public String pay(WeixinPayForm form) throws Exception{
        	//微信服务商APPID,一般情况为认证的服务号appid
    		String appId = "wxd******";
            //子商户号
    		String mchId = "160*****";
        	//小程序appid
    		String subAppid = "111111******";
    		tradeType = "JSAPI";
    		Map<String,String> paramMap = new LinkedHashMap<>();
    		paramMap.put("appid", appId);
    		paramMap.put("body", form.getBody());
    		paramMap.put("device_info", StringUtils.isNotBlank(form.getDeviceInfo()) ? form.getDeviceInfo() : "WEB");
    		paramMap.put("fee_type", "CNY");
    		paramMap.put("limit_pay", "no_credit");
    		paramMap.put("mch_id", mchId);
    		paramMap.put("nonce_str", StringUtils.genenrateUniqueInd());
    		paramMap.put("notify_url", form.getNotifyUrl());
    //		if(!isApp){
    //			paramMap.put("openid", form.getOpenId());
    //		}
    		paramMap.put("out_trade_no", form.getOutTradeNo());
    		paramMap.put("sign_type", "MD5");
    		paramMap.put("spbill_create_ip", form.getIp());
    		paramMap.put("spbill_create_ip", form.getIp());
    		paramMap.put("sub_appid", subAppid);
    		paramMap.put("sub_mch_id", form.getSubMchId());
    		if(!isApp){
    			paramMap.put("sub_openid", form.getOpenId());
    		}
    		paramMap.put("total_fee", String.valueOf(form.getTotalAmount().multiply(new BigDecimal(100)).intValue()));
    		paramMap.put("trade_type", tradeType);
    		System.out.println("=======签名参数开始==========");
    		System.out.println(paramMap.toString());
    		System.out.println("=======签名参数结束==========");
    		paramMap.put("sign", WechatUtil.MD5(paramMap, IspConstant.WX_ISP_MCH_KEY));
    		//签名
    		String xmlParams = getPayXmlString(paramMap, isApp);
    		System.out.println("=======签名XML开始==========");
    		System.out.println(xmlParams);
    		System.out.println("=======签名XML结束==========");
    		String message = HttpUtil.doPostByXml(WechatUtil.GEN_ORDER_URL, xmlParams);
    	    WeixinResponse response = WechatUtil.xmlToBean(message, WeixinResponse.class); 
    	    System.out.println("=======返回信息开始==========");
    		System.out.println(message);
    		 System.out.println("=======返回结束开始==========");
    		
    		if("SUCCESS".equals(response.getReturn_code())){
    			if(StringUtils.isNotBlank(response.getResult_code()) && "SUCCESS".equals(response.getResult_code())){
    				//返回公众号,小程序前端所需参数
    				Map<String,String> result = new LinkedHashMap<>();
                    result.put("appId", subAppid);
                    result.put("nonceStr", StringUtils.genenrateUniqueInd());
                    result.put("package", "prepay_id="+response.getPrepay_id());
                    result.put("signType", "MD5");
                    result.put("timeStamp", String.valueOf(System.currentTimeMillis()));
                    result.put("paySign", WechatUtil.MD5(result, IspConstant.WX_ISP_MCH_KEY));
    				return JsonUtils.object2JsonString(result);
    			}else{
    				throw new ServiceException("支付失败,失败原因:"+response.getErr_code_des());
    			}
    		}else{
    			throw new ServiceException("支付失败,失败原因:"+response.getReturn_msg());
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    StringUtils.genenrateUniqueInd() 生成订单号

    import java.io.UnsupportedEncodingException;
    import java.util.Random;
    import java.util.UUID;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    import org.apache.commons.lang.math.RandomUtils;
    
    public class StringUtils extends org.apache.commons.lang.StringUtils {
    	private static final Pattern URL = Pattern.compile(
    		"^((https|http|ftp|rtsp|mms)?://)" 
    	     + "+(([0-9a-z_!~*'().&=+$%-]+: )?[0-9a-z_!~*'().&=+$%-]+@)?" 
    	     + "(([0-9]{1,3}\\.){3}[0-9]{1,3}" 
    	     + "|" 
    	     + "([0-9a-z_!~*'()-]+\\.)*" 
    	     + "([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\\." 
    	     + "[a-z]{2,6})" 
    	     + "(:[0-9]{1,4})?" 
    	     + "((/?)|" 
    	     + "(/[0-9a-z_!~*'().;?:@&=+$,%#-]+)+/?)$", Pattern.CASE_INSENSITIVE
    	);
    	
    	private static final Pattern PHONE = Pattern.compile("^1[3|4|5|6|7|8|9]([0-9])\\d{8}$");
    	
    	private static final Pattern MONEY = Pattern.compile("^[0-9]+$|^[0-9]+\\.[0-9]{1,6}$");
    	
    	private static final Pattern TELPHONE = Pattern.compile("^(0[0-9]{2,4}-?[0-9]{7,8})|(1[3|4|5|7|8][0-9]{9})$");
    	
    	private static final Pattern IP = Pattern.compile("^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])\\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5]|[*])$");
    	
    	private static final Pattern EMAIL = Pattern.compile("^([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)*@([a-zA-Z0-9]*[-_]?[a-zA-Z0-9]+)+[\\.][A-Za-z]{2,3}([\\.][A-Za-z]{2})?$");
    
    	private static final Pattern SUZI = Pattern.compile("^[0-9]*$");
    	
    	 public static boolean isContainChinese(String str) {
    	        Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
    	        Matcher m = p.matcher(str);
    	        if (m.find()) {
    	            return true;
    	        }
    	        return false;
    	    }
    	
    	public static boolean isEqual(Object obj1, Object obj2) {
    		if(obj1 == null && obj2 == null) return true;
    		if(obj1 == null || obj2 == null) return false;
    		
    		return obj1.equals(obj2);
    	}
    	
    	public static boolean isNotEqual(Object obj1, Object obj2) {
    		return !isEqual(obj1, obj2);
    	}
    	
    	/**
    	 * 六位数字验证码
    	 * @return
    	 */
    	public static String getSixCode() {
    		String result = "";
    		for (int i = 0; i < 6; i++) {
    			result += new Random().nextInt(10);
    		}
    		return result;
    	}
    	
    	public static String getFourCode() {
    		String result = "";
    		for (int i = 0; i < 4; i++) {
    			result += new Random().nextInt(10);
    		}
    		return result;
    	}
    	
    	/**
    	 * 数字字母验证码
    	 */
        public static String getStringRandom(int length) {  
            String val = "";  
            Random random = new Random();  
              
            //参数length,表示生成几位随机数  
            for(int i = 0; i < length; i++) {  
                  
                String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";  
                //输出字母还是数字  
                if( "char".equalsIgnoreCase(charOrNum) ) {  
                    //输出是大写字母还是小写字母  
                    int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;  
                    val += (char)(random.nextInt(26) + temp);  
                } else if( "num".equalsIgnoreCase(charOrNum) ) {  
                    val += String.valueOf(random.nextInt(10));  
                }  
            }  
            return val;  
        }
        
      
    	
    	/**
    	 * 生成20位订单号
    	 */
    	public static String genenrateInd(){
    		Random random = new Random();
    		Integer x = random.nextInt(899999);
    		Integer y = x + 100000;
    		return DateUtil.getShortCurrentTimeStr() + y.toString();
    	}
    	
    	public static String[] chars = new String[] { "a", "b", "c", "d", "e", "f",  
                "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s",  
                "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5",  
                "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I",  
                "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",  
                "W", "X", "Y", "Z" };  
      
      
    	public static String generateShortUuid(int length) {  
    	    StringBuffer shortBuffer = new StringBuffer();  
    	    String uuid = UUID.randomUUID().toString().replace("-", "");  
    	    for (int i = 0; i < length; i++) {  
    	        String str = uuid.substring(i * 4, i * 4 + 4);  
    	        int x = Integer.parseInt(str, 16);  
    	        shortBuffer.append(chars[x % 0x3E]);  
    	    }  
    	    return shortBuffer.toString();  
    	}
    	
    	/**
    	 * 生成32位的唯一序列号
    	 * @return
    	 */
    	public static String genenrateUniqueInd() {
    		return MD5Util.MD5Encode(UUID.randomUUID().toString(), "utf-8");
    	}
    	
    	public static String genOrderNo(Integer memberId) {
    		return (System.currentTimeMillis() + (memberId==null?0L:memberId)) + StringUtils.leftPad("" + RandomUtils.nextInt(1000), 3, "0");
    	}
    	
    	public static void main(String[] args) {
    		System.out.println(genenrateInd());
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144

    生成xml字符串 getPayXmlString();

    private String getPayXmlString(Map<String,String> paramMap, boolean isApp){
    		StringBuilder sb = new StringBuilder(); 
    		sb.append(""); 
    		sb.append("+MapUtil.getStr(paramMap, "appid")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "body")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "device_info")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "fee_type")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "limit_pay")+"]]>");
    		sb.append("+MapUtil.getStr(paramMap, "mch_id")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "nonce_str")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "notify_url")+"]]>"); 
    		/*if(!isApp){
    			sb.append("");
    		}*/
    		sb.append("+MapUtil.getStr(paramMap, "out_trade_no")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sign_type")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "spbill_create_ip")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sub_appid")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sub_mch_id")+"]]>"); 
    		if(!isApp){
    			sb.append("+MapUtil.getStr(paramMap, "sub_openid")+"]]>");
    		}
    		sb.append("+MapUtil.getStr(paramMap, "total_fee")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "trade_type")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sign")+"]]>"); 
    		sb.append(""); 
    		return sb.toString();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    生成秘钥签名

    WechatUtil.MD5(paramMap, IspConstant.WX_ISP_MCH_KEY)

    import java.io.Writer;
    import java.util.Map;
    import java.util.concurrent.TimeUnit;
    
    import javax.annotation.PostConstruct;
    import javax.servlet.http.HttpServletRequest;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import com.alibaba.fastjson.JSONObject;
    import com.thoughtworks.xstream.XStream;
    import com.thoughtworks.xstream.core.util.QuickWriter;
    import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
    import com.thoughtworks.xstream.io.xml.DomDriver;
    import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
    import com.thoughtworks.xstream.io.xml.XppDriver;
    
    import cn.hutool.http.HttpUtil;
    
    @Component
    public class WechatUtil {
    	
    	private static final String key1 = "key1";
    	private static final String key2 = "key2";
    	public static final String JS_CODE_URL="https://api.weixin.qq.com/sns/jscode2session?appid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code";
    	public static final String AUTH2_URL="https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
    	public static final String USERINFO_URL="https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
    	public static final String GEN_ORDER_URL="https://api.mch.weixin.qq.com/pay/unifiedorder";
    	public static final String WECHAT_TRANSFERS_URL="https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
    	public static final String REFUND_ORDER_URL="https://api.mch.weixin.qq.com/secapi/pay/refund";
    	public static final String ACCESS_TOKEN_URL="https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET";
    	public static final String WXACODE="https://api.weixin.qq.com/wxa/getwxacode?access_token=ACCESS_TOKEN";
    	public static final String TEMPLATE_URL="https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=ACCESS_TOKEN";
    	public static final String DOWNLOADBILL_URL="https://api.mch.weixin.qq.com/pay/downloadbill";
    
    	@Autowired 
    	private WeixinConfigService weixinService;
    	@Autowired
    	private RedisUtil redisUtil;
    	
    	private static SysWeixinConfig config;
    	
    	@PostConstruct
        public void init() throws ServiceException {
    		config = weixinService.getAllWeixinConfigs().get(0);
    	}
    	
    	public static String getPayNotifyUrl() {
    		return config.getPayNotifyUrl();
    	}
    	
    	public static String getKfAppId() {
    		return config.getKfAppId();
    	}
    	
    	public static String getKfSecret() {
    		return config.getKfSecret();
    	}
    	
    	public static String getMchId() {
    		return config.getMchId();
    	}
    	
    	public static String getMchKey() {
    		return config.getMchKey();
    	}
    	
    	public static String getGzhAppId(){
    		return config.getGzhAppId();
    	}
    	
    	public static String getGzhSecret(){
    		return config.getGzhSecret();
    	}
    	
    	public static String getXcxAppId(){
    		return config.getXcxAppId();
    	}
    	
    	public static String getXcxSecret(){
    		return config.getXcxSecret();
    	}
    	
    	public static String getFiveXcxAppId(){
    		return config.getFiveXcxAppId();
    	}
    	
    	public static String getFiveXcxSecret(){
    		return config.getFiveXcxSecret();
    	}
    	
    	public static String getCertPath(){
    		return config.getCertPath();
    	}
    	
    	public static String MD5(Map<String,String> paramMap){
    		return MD5(paramMap, WechatUtil.getMchKey());
    	}
    
    	/**
    	 * 返回加密签名
    	 * @param paramMap xml字符串
    	 * @param mchKey  微信服务商商户号
    	 * @return
    	 */
    	public static String MD5(Map<String,String> paramMap, String mchKey){
    		StringBuffer signA = new StringBuffer();
    		for(String key : paramMap.keySet()){
    			signA.append(key+"="+paramMap.get(key)+"&");
    		}
    		String signTemp = signA.toString()+"key="+mchKey;
    		return MD5Util.MD5Encode(signTemp,"utf-8").toUpperCase();
    	}
    	
    	/**
         * bean转成微信的xml消息格式
         * @param object
         * @return
         */
        public static String beanToXml( Object object) {
            XStream xStream = getMyXStream();
            xStream.alias("xml", object.getClass());
            xStream.processAnnotations(object.getClass());
            String xml = xStream.toXML(object);
            if (!StringUtils.isEmpty(xml)){
                return xml;
            }else{
                return null;
            }
        }
    
    	/**
         * xml转成bean泛型方法
         * @param resultXml
         * @param clazz
         * @param 
         * @return
         */
        @SuppressWarnings({ "unchecked", "rawtypes" })
    	public static <T> T xmlToBean(String resultXml, Class clazz) {
            // XStream对象设置默认安全防护,同时设置允许的类
            XStream stream = new XStream(new DomDriver());
    //        XStream.setupDefaultSecurity(stream);
    //        stream.allowTypes(new Class[]{clazz});
            stream.processAnnotations(new Class[]{clazz});
    //        stream.setMode(XStream.NO_REFERENCES);
            stream.alias("xml", clazz);
            return (T) stream.fromXML(resultXml);
        }
    
    	public static String getIp2(HttpServletRequest request) {
    		String ip = request.getHeader("X-Forwarded-For");
    		if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
    			// 多次反向代理后会有多个ip值,第一个ip才是真实ip
    			int index = ip.indexOf(",");
    			if (index != -1) {
    				return ip.substring(0, index);
    			} else {
    				return ip;
    			}
    		}
    		ip = request.getHeader("X-Real-IP");
    		if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
    			return ip;
    		}
    		return request.getRemoteAddr();
    	}
    
      //xstream扩展,bean转xml自动加上![CDATA[]]
        public static XStream getMyXStream() {
            return new XStream(new XppDriver() {
                @Override
                public HierarchicalStreamWriter createWriter(Writer out) {
                    return new PrettyPrintWriter(out) {
                        // 对所有xml节点都增加CDATA标记
                        boolean cdata = true;
     
                        @SuppressWarnings("rawtypes")
    					@Override
                        public void startNode(String name, Class clazz) {
                            super.startNode(name, clazz);
                        }
     
                        @Override
                        protected void writeText(QuickWriter writer, String text) {
                            if (cdata) {
                                writer.write(");
                                writer.write(text);
                                writer.write("]]>");
                            } else {
                                writer.write(text);
                            }
                        }
                    };
                }
            });
        }
        
        
        public void sendWxMessage(JSONObject paramsMap, Integer type) throws ServiceException {
    		String acctenToken = getAccessToken(type);
    		String message;
    		try {
    			message = HttpUtil.post(TEMPLATE_URL.replace("ACCESS_TOKEN", acctenToken), paramsMap.toString());
    			System.out.println(message);
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
        
        public String getAccessToken(Integer type) throws ServiceException {
        	String key = ACCESS_TOKEN_KEY_7;
        	if(type == 5) key = ACCESS_TOKEN_KEY_5;
    		String access_token = (String) redisUtil.getRedisValue(key);
    		if(StringUtils.isEmpty(access_token)){
    			JSONObject jsonObject = HttpUtil.doGet(
    					ACCESS_TOKEN_URL
    					.replace("APPID", type == 5 ? getFiveXcxAppId() : getXcxAppId())
    					.replace("SECRET", type == 5 ? getFiveXcxSecret() : getXcxSecret()));
    			access_token = jsonObject.getString("access_token");
    			if(!StringUtils.isEmpty(access_token)){
    				redisUtil.delete(key);
    				redisUtil.setRedisValue(key, access_token, jsonObject.getLong("expires_in"), TimeUnit.SECONDS);
    			}
    		}
    		return access_token;
    	}
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230

    WeixinResponse转换实体

    
    import com.thoughtworks.xstream.annotations.XStreamAlias;
    import lombok.Getter;
    import lombok.Setter;
    
    @Getter
    @Setter
    public class WeixinResponse {
    	
    	@XStreamAlias("appid")
    	private String appid;
    	
    	@XStreamAlias("sub_appid")
    	private String sub_appid;
    	
    	@XStreamAlias("sub_mch_id")
    	private String sub_mch_id;
    	
    	@XStreamAlias("sub_is_subscribe")
    	private String sub_is_subscribe;
    	
    	@XStreamAlias("device_info")
    	private String device_info;
    	
    	@XStreamAlias("nonce_str")
    	private String nonce_str;
    	
    	@XStreamAlias("sign")
    	private String sign;
    	
    	@XStreamAlias("sign_type")
    	private String sign_type;
    	
    	@XStreamAlias("settlement_total_fee")
    	private String settlement_total_fee;
    	
    	@XStreamAlias("coupon_fee")
    	private String coupon_fee;
    
    	@XStreamAlias("coupon_fee_1")
    	private String coupon_fee_1;
    
    	@XStreamAlias("coupon_count")
    	private String coupon_count;
    	
    	@XStreamAlias("coupon_type_0")
    	private String coupon_type_0;
    	
    	@XStreamAlias("coupon_id_0")
    	private String coupon_id_0;
    	
    	@XStreamAlias("coupon_fee_0")
    	private String coupon_fee_0;
    	
    	@XStreamAlias("attach")
    	private String attach;
    	
    	@XStreamAlias("code_url")
    	private String code_url;
    	
    	@XStreamAlias("return_code")
    	private String return_code;
    	
    	@XStreamAlias("return_msg")
    	private String return_msg;
    	
    	@XStreamAlias("result_code")
    	private String result_code;
    	
    	@XStreamAlias("err_code")
    	private String err_code;
    	
    	@XStreamAlias("err_code_des")
    	private String err_code_des;
    	
    	@XStreamAlias("mch_billno")
    	private String mch_billno;
    	
    	@XStreamAlias("mch_id")
    	private String mch_id;
    	
    	@XStreamAlias("wxappid")
    	private String wxappid;
    	
    	@XStreamAlias("re_openid")
    	private String re_openid;
    	
    	@XStreamAlias("total_amount")
    	private String total_amount;
    	
    	@XStreamAlias("send_listid")
    	private String send_listid;
    	
    	@XStreamAlias("prepay_id")
    	private String prepay_id;
    	
    	@XStreamAlias("trade_type")
    	private String trade_type;
    	
    	@XStreamAlias("openid")
    	private String openid;
    	
    	@XStreamAlias("sub_openid")
    	private String sub_openid;
    	
    	@XStreamAlias("is_subscribe")
    	private String is_subscribe;
    	
    	@XStreamAlias("bank_type")
    	private String bank_type;
    	
    	@XStreamAlias("total_fee")
    	private String total_fee;
    	
    	@XStreamAlias("cash_fee")
    	private String cash_fee;
    	
    	@XStreamAlias("transaction_id")
    	private String transaction_id;
    	
    	@XStreamAlias("out_trade_no")
    	private String out_trade_no;
    	
    	@XStreamAlias("time_end")
    	private String time_end;
    	
    	@XStreamAlias("fee_type")
    	private String fee_type;
    	
    	@XStreamAlias("cash_fee_type")
    	private String cash_fee_type;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133

    JsonUtils.object2JsonString()

    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    
    
    public class JsonUtils {
    	public static final Gson gson = new Gson();
    	
    	public static final GsonBuilder gsonBuilder = new GsonBuilder();
    
    	public static <T> T json2Object(Object data, Class<T> clazz) {
    		return gson.fromJson(gson.toJson(data), clazz);
    	}
    
    	public static String object2JsonString(Object obj) {
    		if(obj == null) {
    			return null;
    		}
    		return gson.toJson(obj).toString();
    	}
    
    	public static <T> T fromJson(String data, Class<T> clazz) {
    		return gson.fromJson(data, clazz);
    	}
    	
    	/**
    	 * 转化成Json,不转化hmtl字符及不忽略空值
    	 * @param obj
    	 * @return
    	 */
    	public static String object2JsonNoEscaping(Object obj){
    		gsonBuilder.disableHtmlEscaping();
    		gsonBuilder.serializeNulls();
    		return gsonBuilder.create().toJson(obj);
    	}
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    v2提现

    controller接口暴露层

        @ApiOperation(value = "提现")
        @OperationLog
        @ApiImplicitParams({
                @ApiImplicitParam(paramType="query",name = "id", value = "提现订单id",dataType="Long",required=true)
        })
        @ResponseBody
        @RequestMapping(value="/member/ith_draw", method=RequestMethod.GET)
        public CommonResult<Boolean> findWithdrawLog(HttpServletRequest request, @RequestParam("id") Long id) throws ServiceException {
            return CommonResult.success(this.iUmsMemberRechargeConfigService.doExtract(request,id));
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    接口实现逻辑

    import lombok.Getter;
    import lombok.Setter;
    
    import java.math.BigDecimal;
    
    @Getter
    @Setter
    public class WeixinEntPayForm {
    
    	/**
    	 * 提现单号
    	 */
    	private String partnerTradeNo;
    	/**
    	 * 用户openId
    	 */
    	private String openId;
    
    	/**
    	 * 退款金额
    	 */
    	private BigDecimal totalAmount;
    
    	/**
    	 * 用户名
    	 */
    	private String userName;
    
    	//app,xcx,gzh
    	private String wxType;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    提现

      /**
         * 提现
         *
         * @param request
         * @param id      操作id
         * @return
         */
        @Override
        @Transactional(rollbackFor = Exception.class)
        public boolean doExtract(HttpServletRequest request, Long id) throws ServiceException {
            WeixinEntPayForm form = new WeixinEntPayForm();
            form.setOpenId("scx");
            form.setTotalAmount(new BigDecimal(111));
            form.setUserName("ssss");
            form.setPartnerTradeNo("11281932218");
            Map<String, String> map = new WeixinPay().entPay(request, form);
            if (ObjectUtils.isEmpty(map)) {
                return true;
            }
            Date now = new Date();
            if ("200".equals(map.get("code"))) {
                //修改提现订单
                update();
                //生成提现记录  看自己的个人实际业务
                insert();
                //修改用户余额 积分  冻结金额
                update();
            } else {
                throw new BusinessException(map.get("message"));
            }
            return false;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    WeixinPay.entPay()

    import cn.hutool.core.date.DateUtil;
    import cn.hutool.core.io.FileUtil;
    import cn.hutool.core.io.file.FileWriter;
    import cn.hutool.core.map.MapUtil;
    import cn.hutool.core.util.NumberUtil;
    import com.github.wxpay.sdk.WXPay;
    import com.github.wxpay.sdk.WXPayUtil;
    import lombok.extern.log4j.Log4j2;
    import org.dom4j.Document;
    import org.dom4j.DocumentHelper;
    import org.dom4j.Element;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.servlet.http.HttpServletRequest;
    import java.math.BigDecimal;
    import java.util.*;
    
    @Log4j2
    public class WeixinPay {
        public Map<String, String> entPay(HttpServletRequest request, WeixinEntPayForm form) {
    		String appId = "appid";
    		String mchId = "商户号";
    		boolean isApp = false;
    		Map<String, String> paramMap = new LinkedHashMap<>();
    		// 商户账号appid
    		paramMap.put("mch_appid", appId);
    		// 商户
    		paramMap.put("mchid", mchId);
    		// 随机字符串
    		paramMap.put("nonce_str", WXPayUtil.generateNonceStr());
    		// 交易订单号
    		paramMap.put("partner_trade_no", form.getPartnerTradeNo());
    		// 用户openid
    		paramMap.put("openid", form.getOpenId());
    		// 校验用户姓名选项
    		paramMap.put("check_name", "NO_CHECK");
    		// 金额 分
    		paramMap.put("amount", String.valueOf(form.getTotalAmount().multiply(new BigDecimal(100)).intValue()));
    		//备注
    		paramMap.put("desc", "提现");
    		paramMap.put("spbill_create_ip", WechatUtil.getIp2(request));
    		paramMap.put("sign", WechatUtil.MD5(paramMap, IspConstant.WX_ISP_MCH_KEY));
    		log.info("=======签名参数开始weixin-entpay==========");
    		log.info(paramMap.toString());
    		String requestXml = getRequestXml(paramMap);
    		log.info("=======签名参数结束weixin-entpay==========");
    		String xmlResult = CertHttpUtil.postData(WechatUtil.WECHAT_TRANSFERS_URL, requestXml, IspConstant.WX_ISP_MCH_ID, IspConstant.WX_CERT_PATH);
    		log.info("=======返回信息开始weixin-entpay==========");
    		log.info(xmlResult);
    		log.info("=======返回信息结束weixin-entpay==========");
    		Map<String, String> mapResult = null;
    		try {
    			mapResult = WXPayUtil.xmlToMap(xmlResult);
    		} catch (Exception e) {
    			log.info("xml转换错误======================" + e.getMessage());
    		}
    		Map<String, String> result = new HashMap<>();
    		// 转账成功
    		if ("SUCCESS".equalsIgnoreCase(mapResult.get("result_code"))) {
    			//todo 记录提现日志 生成消费单
    			result.put("code", "200");
    			result.put("message", "支付成功");
    		}
    		// 转帐失败
    		else if ("FAIL".equalsIgnoreCase(mapResult.get("result_code"))) {
    			result.put("code", "500");
    			// 系统错误需要重试[请先调用查询接口,查看此次付款结果,如结果为不明确状态(如订单号不存在),请务必使用原商户订单号进行重试。
    			if ("SYSTEMERROR".equalsIgnoreCase(mapResult.get("err_code"))) {
    //                result.put("message", "支付成功");]
    			}
    			// 金额超限
    			else if ("AMOUNT_LIMIT".equalsIgnoreCase(mapResult.get("err_code"))) {
    
    				result.put("message", "金额超限");
    			}
    			// 余额不足
    			else if ("NOTENOUGH".equalsIgnoreCase(mapResult.get("err_code"))) {
    //                result.put("message", "支付成功");
    			}
    			// 超过频率限制,请稍后再试。
    			else if ("FREQ_LIMIT".equalsIgnoreCase(mapResult.get("err_code"))) {
    				result.put("message", "超过频率限制,请稍后再试。");
    			}
    			// 已经达到今日付款总额上限/已达到付款给此用户额度上限
    			else if ("MONEY_LIMIT".equalsIgnoreCase(mapResult.get("err_code"))) {
    				result.put("message", "已经达到今日付款总额上限");
    			}
    			// 无法给非实名用户付款
    			else if ("V2_ACCOUNT_SIMPLE_BAN".equalsIgnoreCase(mapResult.get("err_code"))) {
    				result.put("message", "无法给非实名用户付款");
    			}
    			// 该用户今日付款次数超过限制,如有需要请登录微信支付商户平台更改API安全配置
    			else if ("SENDNUM_LIMIT".equalsIgnoreCase(mapResult.get("err_code"))) {
    				result.put("message", "今日付款次数超过限制");
    			}
    		} else {
    			// 系统错误
    			log.info("------------------具体报错信息------------------" + mapResult.get("err_code_des"));
    			result.put("code", "500");
    			result.put("message", "系统错误");
    		}
    		return result;
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106

    WechatUtil.getIp2(request)

    	public static String getIp2(HttpServletRequest request) {
    		String ip = request.getHeader("X-Forwarded-For");
    		if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
    			// 多次反向代理后会有多个ip值,第一个ip才是真实ip
    			int index = ip.indexOf(",");
    			if (index != -1) {
    				return ip.substring(0, index);
    			} else {
    				return ip;
    			}
    		}
    		ip = request.getHeader("X-Real-IP");
    		if (!StringUtils.isEmpty(ip) && !"unKnown".equalsIgnoreCase(ip)) {
    			return ip;
    		}
    		return request.getRemoteAddr();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    WechatUtil.generateNonceStr()

       public static String generateNonceStr() {
            return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
        }
    
    • 1
    • 2
    • 3

    CertHttpUtil.postData

    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.entity.StringEntity;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.ssl.SSLContexts;
    import org.apache.http.util.EntityUtils;
    
    public class CertHttpUtil {
    	 
        private static int socketTimeout = 10000;// 连接超时时间,默认10秒
        private static int connectTimeout = 30000;// 传输超时时间,默认30秒
        private static RequestConfig requestConfig;// 请求器的配置
        private static CloseableHttpClient httpClient;// HTTP请求器
     
        /**
         * 通过Https往API post xml数据
         *
         * @param url API地址
         * @param xmlObj 要提交的XML数据对象
        * @param mchId 商户ID
        * @param certPath 证书位置
         * @return
         */
        public static String postData(String url, String xmlObj, String mchId, String certPath) {
            // 加载证书
            try {
                initCert(mchId, certPath);
            } 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;
        }
     
        /**
         * 加载证书
         *
         * @param mchId 商户ID
         * @param certPath 证书位置
         * @throws Exception
         */
        @SuppressWarnings("deprecation")
    	private static void initCert(String mchId, String certPath) throws Exception {
            // 证书密码,默认为商户ID
            String key = mchId;
            // 证书的路径
            String path = certPath;
            // 指定读取证书格式为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();
            SSLConnectionSocketFactory sslsf =
                    new SSLConnectionSocketFactory(sslcontext, new String[] {"TLSv1"}, null,
                            SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
            httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101

    生成xml字符串

    	@SuppressWarnings("rawtypes")
    	public static String getRequestXml(Map<String, String> parameters) {
    		StringBuffer sb = new StringBuffer();
    		sb.append("");
    		Set es = parameters.entrySet();
    		Iterator it = es.iterator();
    		while (it.hasNext()) {
    			Map.Entry entry = (Map.Entry) it.next();
    			String k = (String) entry.getKey();
    			String v = (String) entry.getValue();
    			if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
    				sb.append("<" + k + ">" + " + v + "]]> + k + ">");
    			} else {
    				sb.append("<" + k + ">" + v + " + k + ">");
    			}
    		}
    		sb.append("");
    		return sb.toString();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    v2退款

    ![](https://img-blog.csdnimg.cn/img_convert/f8c5c0e718095cfa50079c781e3b9101.png#clientId=u89e85d45-da94-4&crop=0&crop=0&crop=1&crop=1&from=paste&id=u363733d3&margin=[object Object]&originHeight=486&originWidth=437&originalType=url&ratio=1&rotation=0&showTitle=false&status=done&style=none&taskId=u56a22731-966e-4215-bec6-b7e14ecd38c&title=)
    cancelAndRefundOrder 退款接口

        @Override
    	public void cancelAndRefundOrder() {
            BigDecimal refundAmount = new BigDecimal(111);
            refundAmount = refundAmount == null ? BigDecimal.ZERO : refundAmount;
          
            //获取支付订单
            WeixinRefundForm wxform = new WeixinRefundForm();
            wxform.setWxType("xcx");
            wxform.setOutRefundNo("110001111");
            wxform.setOutTradeNo("110001111");
            wxform.setRefundFee("退款金额");
            wxform.setTotalAmount("订单金额");
            wxform.setNotifyUrl("退款回调地址");
            String subMchId = "商户号id";
            wxform.setSubMchId(subMchId);
            new WeixinPay().refund(wxform);
          
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    refund 退款封装

    public void refund(WeixinRefundForm form) throws ServiceException{
    		String appId = "微信服务商APPID";
    		String mchId = "微信服务商商户号";
    		String subAppid = "小程序appid";
    		boolean isApp = false;
    		Map<String,String> paramMap = new LinkedHashMap<>();
    		paramMap.put("appid", appId);
    		paramMap.put("mch_id", mchId);
    		paramMap.put("nonce_str", StringUtils.genenrateUniqueInd());
    		paramMap.put("notify_url", form.getNotifyUrl());
    		paramMap.put("out_refund_no", form.getOutRefundNo());
    		paramMap.put("out_trade_no", form.getOutTradeNo());
    		paramMap.put("refund_fee", String.valueOf(form.getRefundFee().multiply(new BigDecimal(100)).intValue()));
    		paramMap.put("sign_type", "MD5");
    		paramMap.put("sub_appid", subAppid);
    		paramMap.put("sub_mch_id", form.getSubMchId());
    		paramMap.put("total_fee", String.valueOf(form.getTotalAmount().multiply(new BigDecimal(100)).intValue()));
    		System.out.println("=======签名参数开始==========");
    		System.out.println(paramMap.toString());
    		System.out.println("=======签名参数结束==========");
    		paramMap.put("sign", WechatUtil.MD5(paramMap, IspConstant.WX_ISP_MCH_KEY));
    		//签名
    		String xmlParams = getRefundXmlString(paramMap, isApp);
    		System.out.println("=======签名XML开始==========");
    		System.out.println(xmlParams);
    		System.out.println("=======签名XML结束==========");
    		String message = CertHttpUtil.postData(WechatUtil.REFUND_ORDER_URL, xmlParams, IspConstant.WX_ISP_MCH_ID, IspConstant.WX_CERT_PATH);
    	    WeixinRefundResponse response = WechatUtil.xmlToBean(message, WeixinRefundResponse.class); 
    	    System.out.println("=======返回信息开始==========");
    		System.out.println(message);
    		 System.out.println("=======返回结束开始==========");
    		
    		if("SUCCESS".equals(response.getReturn_code())){
    			if(StringUtils.isNotBlank(response.getResult_code()) && "SUCCESS".equals(response.getResult_code())){
    				//退款申请成功,结果通过退款查询接口查询 
    			}else{
    				throw new ServiceException("退款申请失败,失败原因:"+response.getErr_code_des());
    			}
    		}else{
    			throw new ServiceException("退款申请失败,失败原因:"+response.getReturn_msg());
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    生成退款xml字符串

    private String getRefundXmlString(Map<String,String> paramMap, boolean isApp){
    		StringBuilder sb = new StringBuilder(); 
    		sb.append(""); 
    		sb.append("+MapUtil.getStr(paramMap, "appid")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "mch_id")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "nonce_str")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "notify_url")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "out_refund_no")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "out_trade_no")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "refund_fee")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sign_type")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sub_appid")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sub_mch_id")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "total_fee")+"]]>"); 
    		sb.append("+MapUtil.getStr(paramMap, "sign")+"]]>"); 
    		sb.append(""); 
    		return sb.toString();
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    支付回调

    微信支付成功回调----> 这边用到了设计模式,工厂模式

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    
    @Api(tags = "订单支付回调", description = "FoodOrderPayCallbackController")
    @Controller
    public class FoodOrderPayCallbackController extends PayCallbackController {
    	
    
    	@ApiOperation(value = "微信支付回调")
        @ResponseBody
        @RequestMapping(value="/pay/callbak", method=RequestMethod.POST)
        public String paySusForWx(HttpServletRequest request) throws Exception{
    		return this.paySusForWx(request, CallbackManager.CALLBACK_FOOD_ORDER);
        }
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    PayCallbackController 支付回调controller

    import java.io.BufferedOutputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.util.HashMap;
    import java.util.Iterator;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import lombok.extern.log4j.Log4j2;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    
    
    @Log4j2
    @Controller
    public class PayCallbackController {
    	
    	@Autowired
    	private CallbackManager paySusManager;
    	
        public String paySusForWx(HttpServletRequest request, String type) throws Exception{
    		InputStream inStream = request.getInputStream(); 
    		int _buffer_size = 1024; 
    		if (inStream != null) { 
    			ByteArrayOutputStream outStream = new ByteArrayOutputStream(); 
    			byte[] tempBytes = new byte[_buffer_size]; 
    			int count = -1; 
    			while ((count = inStream.read(tempBytes, 0, _buffer_size)) != -1) {
    				outStream.write(tempBytes, 0, count); 
    			} 
    			tempBytes = null; outStream.flush(); 
    			//将流转换成字符串 
    			String result = new String(outStream.toByteArray(), "UTF-8"); 
    			log.info("微信支付回调:"+result);
    			WeixinResponse response = WechatUtil.xmlToBean(result, WeixinResponse.class);
    			
    			//通知成功
    			if(StringUtils.isNotBlank(response.getReturn_code()) && "SUCCESS".equals(response.getReturn_code())){
    				if(StringUtils.isNotBlank(response.getResult_code()) && "SUCCESS".equals(response.getResult_code())){
    					//支付成功
    					paySusManager.getPaySusFactory(type).paySus(response.getOut_trade_no());
    				}
    			}
    			
    		}
    		
    		return "";
        }
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    CallbackManager 定义回调工厂管理类

    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    @Component
    public class CallbackManager {
    
    
        public static final String CALLBACK_RECHARGE = "recharge";
        public static final String CALLBACK_FOOD_ORDER = "foodOrder";
        /**
         * 退款
         */
        public static final String CALLBACK_REFUND_HANDLE = "refundHandle";
        /**
         * 申请退款
         */
        public static final String CALLBACK_REFUND_APPLY = "refundApply";
    
        @Autowired
        private FoodOrderLogic foodOrderLogic;
        @Autowired
        private RefundLogic refundLogic;
        @Autowired
        private RechargeLogic rechargeLogic;
    
        public CallbackFactory getPaySusFactory(String mode) {
            switch (mode) {
                case CALLBACK_REFUND_APPLY:
                    return refundLogic;
                case CALLBACK_FOOD_ORDER:
                    return foodOrderLogic;
                case CALLBACK_RECHARGE:
                    return rechargeLogic;
                default:
                    return null;
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    CallbackFactory回调工厂

    import org.springframework.stereotype.Component;
    
    
    import java.util.concurrent.ExecutionException;
    
    @Component
    public abstract class CallbackFactory{
    	
    	public abstract void paySus(String orderNo) ;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    FoodOrderLogic 回调处理逻辑方法

    import cn.hutool.core.collection.CollectionUtil;
    import cn.hutool.core.date.DateUnit;
    import cn.hutool.core.date.DateUtil;
    import com.dtp.core.DtpExecutor;
    import com.dtp.core.DtpRegistry;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.Date;
    import java.util.List;
    import java.util.concurrent.CompletableFuture;
    import java.util.concurrent.ExecutionException;
    import java.util.function.Function;
    
    @Slf4j
    @Service("paySusFoodOrder")
    public class FoodOrderLogic extends CallbackFactory {
    
      
    
        @Override
        public void paySus(String orderNo) throws ServiceException, ExecutionException, InterruptedException {
    
            //处理回调逻辑       
        }
    
    
        public void refundSus(String refundNo, String type) throws ServiceException {
            switch (type) {
                case CallbackManager.CALLBACK_REFUND_APPLY:
                    refundService.refundSusCallback(refundNo, null);
                    break;
    
                case CallbackManager.CALLBACK_REFUND_HANDLE:
                    OmsFoodOrder order = foodOrderService.getOrderByOrderNo(refundNo);
                    foodOrderService.cancelAndRefundOrderSus(order);
                    break;
                default:
                    break;
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    微信退款回调

    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.ResponseBody;
    
    
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    
    @Api(tags = "申请售后退款回调", description = "RefundApplyCallbackController")
    @Controller
    public class RefundApplyCallbackController extends RefundCallbackController {
    
    	
    	@ApiOperation(value = "微信退款回调")
    	@RequestMapping(value="/weixin/pay/refund/callback", method=RequestMethod.POST)
        @ResponseBody
        public String paySusJoinPinkaForWx(HttpServletRequest request) throws Exception{
    		return this.refundSusForWx(request, CallbackManager.CALLBACK_REFUND_APPLY);
        }
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    WeixinRefundResponse 微信退款实体

    import com.thoughtworks.xstream.annotations.XStreamAlias;
    
    import lombok.Getter;
    import lombok.Setter;
    
    @Getter
    @Setter
    public class WeixinRefundResponse {
    	
    	@XStreamAlias("appid")
    	private String appid;
    	
    	@XStreamAlias("sub_appid")
    	private String sub_appid;
    	
    	@XStreamAlias("nonce_str")
    	private String nonce_str;
    	
    	@XStreamAlias("sign")
    	private String sign;
    	
    	@XStreamAlias("out_refund_no")
    	private String out_refund_no;
    	
    	@XStreamAlias("refund_id")
    	private String refund_id;
    	
    	@XStreamAlias("refund_fee")
    	private String refund_fee;
    	
    	@XStreamAlias("settlement_refund_fee")
    	private String settlement_refund_fee;
    	
    	@XStreamAlias("settlement_total_fee")
    	private String settlement_total_fee;
    	
    	@XStreamAlias("return_code")
    	private String return_code;
    	
    	@XStreamAlias("return_msg")
    	private String return_msg;
    	
    	@XStreamAlias("result_code")
    	private String result_code;
    	
    	@XStreamAlias("refund_account")
    	private String refund_account;
    	
    	@XStreamAlias("err_code")
    	private String err_code;
    	
    	@XStreamAlias("err_code_des")
    	private String err_code_des;
    	
    	@XStreamAlias("cash_refund_fee")
    	private String cash_refund_fee;
    	
    	@XStreamAlias("mch_id")
    	private String mch_id;
    	
    	@XStreamAlias("sub_mch_id")
    	private String sub_mch_id;
    	
    	@XStreamAlias("coupon_type_$n")
    	private String coupon_type_$n;
    	
    	@XStreamAlias("coupon_refund_fee")
    	private String coupon_refund_fee;
    	
    	@XStreamAlias("coupon_refund_fee_$n")
    	private String coupon_refund_fee_$n;
    	
    	@XStreamAlias("coupon_refund_count")
    	private String coupon_refund_count;
    	
    	@XStreamAlias("coupon_refund_id_$n")
    	private String coupon_refund_id_$n;
    	
    	@XStreamAlias("total_fee")
    	private String total_fee;
    	
    	@XStreamAlias("cash_fee")
    	private String cash_fee;
    	
    	@XStreamAlias("transaction_id")
    	private String transaction_id;
    	
    	@XStreamAlias("out_trade_no")
    	private String out_trade_no;
    	
    	@XStreamAlias("fee_type")
    	private String fee_type;
    	
    	@XStreamAlias("cash_fee_type")
    	private String cash_fee_type;
    	
    	@XStreamAlias("req_info")
    	private String req_info;
    	
    	@XStreamAlias("refund_channel")
    	private String refund_channel;
    	
    	@XStreamAlias("refund_recv_accout")
    	private String refund_recv_accout;
    	
    	@XStreamAlias("refund_request_source")
    	private String refund_request_source;
    	
    	@XStreamAlias("refund_status")
    	private String refund_status;
    	
    	@XStreamAlias("success_time")
    	private String success_time;
    	
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116

    RefundCallbackController 微信退款回调实现逻辑

    import java.io.ByteArrayOutputStream;
    import java.io.InputStream;
    import java.security.InvalidKeyException;
    import java.security.NoSuchAlgorithmException;
    import java.security.Security;
    import java.util.Base64;
    
    import javax.crypto.Cipher;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.SecretKeySpec;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    import lombok.extern.log4j.Log4j2;
    import org.bouncycastle.jce.provider.BouncyCastleProvider;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    
    @Log4j2
    @Controller
    public class RefundCallbackController  {
    	
        private static Cipher cipher = null;  //解码器
    
    	
        public String refundSusForWx(HttpServletRequest request, String type) throws Exception{
    		InputStream inStream = request.getInputStream();
    		int _buffer_size = 1024;
    		if (inStream != null) {
    			ByteArrayOutputStream outStream = new ByteArrayOutputStream();
    			byte[] tempBytes = new byte[_buffer_size];
    			int count = -1;
    			while ((count = inStream.read(tempBytes, 0, _buffer_size)) != -1) {
    				outStream.write(tempBytes, 0, count);
    			}
    			tempBytes = null; outStream.flush();
    			//将流转换成字符串
    			String result = new String(outStream.toByteArray(), "UTF-8");
    			log.info("微信退款回调:{}", result);
    			WeixinRefundResponse response = WechatUtil.xmlToBean(result, WeixinRefundResponse.class);
    
    			String reqInfo = response.getReq_info();
    
    			init(IspConstant.WX_ISP_MCH_KEY);
    			Base64.Decoder decoder = Base64.getDecoder();
    	        byte[] base64ByteArr = decoder.decode(reqInfo);
    
    	        String jmResult = new String(cipher.doFinal(base64ByteArr));
    	        log.info("解密结果:{}", jmResult);
    	        String jmr = jmResult.replaceAll("", "").replaceAll("", "");
    	        if(jmr.contains("]>") && !jmr.contains("]]>")){
    	    		jmr = jmr.replaceAll("]>", "]]>");
    	    	}
    	        WeixinRefundResponse notifyResponse = WechatUtil.xmlToBean(jmr, WeixinRefundResponse.class);
    
    			//通知成功
    			if(StringUtils.isNotBlank(notifyResponse.getRefund_status()) && "SUCCESS".equals(notifyResponse.getRefund_status())){
    					log.info("退款单号:{}, type:{}", notifyResponse.getOut_refund_no(), type);
                    	//具体个人实现逻辑 可以去调用不同自己的实现逻辑代码
    					refundSus(notifyResponse.getOut_refund_no(), type);
    				}
    		}
    
    		return "";
        }
    	
        public static void init(String mchKey) {
    //        String key = MD5Util.MD5Encode(WechatUtil.getMchKey(), "");
        	String key = MD5Util.MD5Encode(mchKey, "");
            SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "AES");
            Security.addProvider(new BouncyCastleProvider());
            try {
                cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
                cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                e.printStackTrace();
            } catch (InvalidKeyException e) {
                e.printStackTrace();
            }
        }
        
        
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
  • 相关阅读:
    10.10c++作业
    2023年7月京东奶粉行业品牌销售排行榜(京东数据产品)
    【优化选址】基于matlab遗传算法求解物流配送中心选址【含Matlab源码 1917期】
    使用JMeter测试Go WebSocket服务的并发
    Nature子刊|“二代+三代”宏基因组学揭示肠道微生物群的个性化结构变异
    从月薪3千到月薪3万,网络运维工程师是怎么逆袭的?
    tomcat 把webappp设置在其他目录
    SuperMap iServer11i新功能----图例的发布和使用
    基于SpringBoot的校园闲置物品交易管理系统
    如何设计元宇宙展厅,元宇宙展厅的展示和交互形式有哪些?
  • 原文地址:https://blog.csdn.net/sha1024/article/details/127771970