好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

java实现微信企业付款到个人功能

微信官方提供了微信企业账户付款到微信个人零钱接口,提供企业向用户付款的功能,支持企业通过api接口付款,或通过微信支付商户平台网页功能操作付款。该接口并不是直接所有的商户都拥有,企业要开启必须满足以下两个条件:

 1、商户号已入驻90日
 2、商户号有30天连续正常交易

满足以上条件就可登录微信支付商户平台-产品中心,开通企业付款。
调用的链接地址:接口链接: https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers
微信官方接口文档提供的调用微信企业付款的参数:

参数中最重要是获取用户openid和调用接口ip,获取openid可以通过公众号获取,app端可以直接获取。具体的代码实现如下:

封装请求微信企业付款的实体类transfers:

?

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

public class transfers implements serializable{

   private static final long serialversionuid = 1l;

   /** 商户账号appid*/

   public string mch_appid;

   /** 微信支付商户号*/

   public string mchid;

   /** 随机串*/

   public string nonce_str;

   /** 签名*/

   public string sign;

   /** 商户订单号*/

   public string partner_trade_no;

   /** 用户id*/

   public string openid;

   /** 是否校验用户姓名 no_check:不校验真实姓名 force_check:强校验真实姓名*/

   public string check_name;

   /** 金额 单位:分*/

   public integer amount;

   /** 企业付款描述信息*/

   public string desc;

   /** ip地址*/

   public string spbill_create_ip;

   public string getmch_appid() {

     return mch_appid;

   }

   public void setmch_appid(string mch_appid) {

     this .mch_appid = mch_appid;

   }

   public string getmchid() {

     return mchid;

   }

   public void setmchid(string mchid) {

     this .mchid = mchid;

   }

   public string getnonce_str() {

     return nonce_str;

   }

   public void setnonce_str(string nonce_str) {

     this .nonce_str = nonce_str;

   }

   public string getsign() {

     return sign;

   }

   public void setsign(string sign) {

     this .sign = sign;

   }

   public string getpartner_trade_no() {

     return partner_trade_no;

   }

   public void setpartner_trade_no(string partner_trade_no) {

     this .partner_trade_no = partner_trade_no;

   }

   public string getopenid() {

     return openid;

   }

   public void setopenid(string openid) {

     this .openid = openid;

   }

   public string getcheck_name() {

     return check_name;

   }

   public void setcheck_name(string check_name) {

     this .check_name = check_name;

   }

   public integer getamount() {

     return amount;

   }

   public void setamount(integer amount) {

     this .amount = amount;

   }

   public string getdesc() {

     return desc;

   }

   public void setdesc(string desc) {

     this .desc = desc;

   }

   public string getspbill_create_ip() {

     return spbill_create_ip;

   }

   public void setspbill_create_ip(string spbill_create_ip) {

     this .spbill_create_ip = spbill_create_ip;

   }

 

}

接口部分代码:

?

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

private transfers transfers = new transfers();

// 构造签名的map

   private sortedmap<object, object> parameters = new treemap<object, object>();

// 微信的参数

   private weixinconfigutils config = new weixinconfigutils();

  /**

   * 微信提现(企业付款)

   */

   @action ( "weixinwithdraw" )

   public string weixinwithdraw(){

     string openid = request.getparameter( "openid" );

     string ip = request.getparameter( "ip" );

     string money = request.getparameter( "money" );

     string doctorid = request.getparameter( "doctorid" );

     if (stringutils.isnotblank(money) && stringutils.isnotblank(ip) && stringutils.isnotblank(openid) && stringutils.isnotblank(doctorid)) {

     // 参数组

     string appid = config.appid;

     string mch_id = config.mch_id;

     string nonce_str = randcharsutils.getrandomstring( 16 );

     //是否校验用户姓名 no_check:不校验真实姓名 force_check:强校验真实姓名

     string checkname = "no_check" ;

     //等待确认转账金额,ip,openid的来源

     integer amount = integer.valueof(money);

     string spbill_create_ip = ip;

     string partner_trade_no = uuidutils.getuuid();

     //描述

     string desc = "健康由我医师助手提现" +amount/ 100 + "元" ;

     // 参数:开始生成第一次签名

     parameters.put( "appid" , appid);

     parameters.put( "mch_id" , mch_id);

     parameters.put( "partner_trade_no" , partner_trade_no);

     parameters.put( "nonce_str" , nonce_str);

     parameters.put( "openid" , openid);

     parameters.put( "checkname" , checkname);

     parameters.put( "amount" , amount);

     parameters.put( "spbill_create_ip" , spbill_create_ip);

     parameters.put( "desc" , desc);

     string sign = wxsignutils.createsign( "utf-8" , parameters);

     transfers.setamount(amount);

     transfers.setcheck_name(checkname);

     transfers.setdesc(desc);

     transfers.setmch_appid(appid);

     transfers.setmchid(mch_id);

     transfers.setnonce_str(nonce_str);

     transfers.setopenid(openid);

     transfers.setpartner_trade_no(partner_trade_no);

     transfers.setsign(sign);

     transfers.setspbill_create_ip(spbill_create_ip);

     string xmlinfo = httpxmlutils.transferxml(transfers);

     try {

       closeablehttpresponse response = httputil.post(weixinconstant.withdraw_url, xmlinfo, true );

       string transfersxml = entityutils.tostring(response.getentity(), "utf-8" );

       map<string, string> transfermap = httpxmlutils.parserefundxml(transfersxml);

       if (transfermap.size()> 0 ) {

         if (transfermap.get( "result_code" ).equals( "success" ) && transfermap.get( "return_code" ).equals( "success" )) {

           //成功需要进行的逻辑操作,

 

           }

         }

       system.out.println( "成功" );

     } catch (exception e) {

       log.error(e.getmessage());

       throw new basicruntimeexception( this , "企业付款异常" + e.getmessage());

     }

     } else {

       system.out.println( "失败" );

     }

     return none;

   }

产生随机串部分代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

public class randcharsutils {

   private static simpledateformat df = new simpledateformat( "yyyymmddhhmmss" );

 

   public static string getrandomstring( int length) { //length表示生成字符串的长度

     string base = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz" ; 

     random random = new random(); 

     stringbuffer sb = new stringbuffer();

     int number = 0 ;

     for ( int i = 0 ; i < length; i++) { 

       number = random.nextint(base.length()); 

       sb.append(base.charat(number)); 

     } 

     return sb.tostring(); 

   } 

   }

生成签名:

?

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

public class wxsignutils {

   /**

    * 微信支付签名算法sign

    * @param characterencoding

    * @param parameters

    * @return

    */

   @suppresswarnings ( "rawtypes" )

   public static string createsign(string characterencoding,sortedmap<object,object> parameters){

     stringbuffer sb = new stringbuffer();

     set es = parameters.entryset(); //所有参与传参的参数按照accsii排序(升序)

     iterator it = es.iterator();

     while (it.hasnext()) {

       map.entry entry = (map.entry)it.next();

       string k = (string)entry.getkey();

       object v = entry.getvalue();

       if ( null != v && ! "" .equals(v)

           && ! "sign" .equals(k) && ! "key" .equals(k)) {

         sb.append(k + "=" + v + "&" );

       }

     }

     sb.append( "key=" + weixinconstant.key);

     string sign = md5util.md5encode(sb.tostring(), characterencoding).touppercase();

     return sign;

   }

}

md5部分代码:

?

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

import java.security.messagedigest;

 

public class md5util {

 

   private static string bytearraytohexstring( byte b[]) {

     stringbuffer resultsb = new stringbuffer();

     for ( int i = 0 ; i < b.length; i++)

       resultsb.append(bytetohexstring(b[i]));

 

     return resultsb.tostring();

   }

 

   private static string bytetohexstring( byte b) {

     int n = b;

     if (n < 0 )

       n += 256 ;

     int d1 = n / 16 ;

     int d2 = n % 16 ;

     return hexdigits[d1] + hexdigits[d2];

   }

 

   public static string md5encode(string origin, string charsetname) {

     string resultstring = null ;

     try {

       resultstring = new string(origin);

       messagedigest md = messagedigest.getinstance( "md5" );

       if (charsetname == null || "" .equals(charsetname))

         resultstring = bytearraytohexstring(md.digest(resultstring

             .getbytes()));

       else

         resultstring = bytearraytohexstring(md.digest(resultstring

             .getbytes(charsetname)));

     } catch (exception exception) {

     }

     return resultstring;

   }

 

   private static final string hexdigits[] = { "0" , "1" , "2" , "3" , "4" , "5" ,

     "6" , "7" , "8" , "9" , "a" , "b" , "c" , "d" , "e" , "f" };

 

}

构造xml:

?

1

2

3

4

5

6

7

8

9

10

/**

    * 构造企业付款xml参数

    * @param xml

    * @return

    */

   public static string transferxml(transfers transfers){

       xstream.autodetectannotations( true );

       xstream.alias( "xml" , transfers. class );

       return xstream.toxml(transfers);

   }

向微信发送xml请求(验证证书)部分代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public class httputil {

   /**

    * 发送post请求

    *

    * @param url

    *      请求地址

    * @param outputentity

    *      发送内容

    * @param isloadcert

    *      是否加载证书

    */

   public static closeablehttpresponse post(string url, string outputentity, boolean isloadcert) throws exception {

     httppost httppost = new httppost(url);

     // 得指明使用utf-8编码,否则到api服务器xml的中文不能被成功识别

     httppost.addheader( "content-type" , "text/xml" );

     httppost.setentity( new stringentity(outputentity, "utf-8" ));

     if (isloadcert) {

       // 加载含有证书的http请求

       return httpclients.custom().setsslsocketfactory(certutil.initcert()).build().execute(httppost);

     } else {

       return httpclients.custom().build().execute(httppost);

     }

   }

}

加载证书部分代码:(加载证书需要注意证书放置位置在项目下的webapp中建文件夹,linux单独防止只要地址配置正确即可。)

?

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

import java.io.file;

import java.io.fileinputstream;

import java.security.keystore;

 

import javax.net.ssl.sslcontext;

 

import org.apache.http.conn.ssl.sslconnectionsocketfactory;

import org.apache.http.ssl.sslcontexts;

 

/**

  * 加载证书的类

  * @author

  * @since 2017/08/16

  */

 

@suppresswarnings ( "deprecation" )

public class certutil {

   private static weixinconfigutils config = new weixinconfigutils();

   /**

    * 加载证书

    */

   public static sslconnectionsocketfactory initcert() throws exception {

     fileinputstream instream = null ;

     keystore keystore = keystore.getinstance( "pkcs12" );

     instream = new fileinputstream( new file(weixinconstant.path));

     keystore.load(instream, config.mch_id.tochararray());

 

     if ( null != instream) {

       instream.close();

     }

 

     sslcontext sslcontext = sslcontexts.custom().loadkeymaterial(keystore,config.mch_id.tochararray()).build();

     sslconnectionsocketfactory sslsf = new sslconnectionsocketfactory(sslcontext, new string[]{ "tlsv1" }, null , sslconnectionsocketfactory.browser_compatible_hostname_verifier);

 

     return sslsf;

   }

}

加载配置文件部分代码:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

@suppresswarnings ( "unused" )

public class weixinconfigutils {

   private static final log log = logfactory.getlog(weixinconfigutils. class );

   public static string appid;

   public static string mch_id;

   public static string notify_url;

   public static string order_notify_url;

   public static string doctor_notify_url;

   static {

     try {

       inputstream is = weixinconfigutils. class .getresourceasstream( "/weixin.properties" );

       properties properties = new properties();

       properties.load(is);

       appid = properties.getproperty( "weixin.appid" );

       mch_id = properties.getproperty( "weixin.mch_id" );

       notify_url = properties.getproperty( "weixin.notify_url" );

       order_notify_url = properties.getproperty( "weixin.order_notify_url" );

       doctor_notify_url = properties.getproperty( "weixin.doctor_notify_url" );

     } catch (exception ex){

       log.debug( "加载配置文件:" +ex.getmessage());

     }

   }

}

获取返回的xml参数并解析为map:

?

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

/**

    * 解析申请退款之后微信返回的值并进行存库操作

    * @throws ioexception

    * @throws jdomexception

    */

   public static map<string, string> parserefundxml(string refundxml) throws jdomexception, ioexception{

     parsexmlutils.jdomparsexml(refundxml);

     stringreader read = new stringreader(refundxml);

     // 创建新的输入源sax 解析器将使用 inputsource 对象来确定如何读取 xml 输入

     inputsource source = new inputsource(read);

     // 创建一个新的saxbuilder

     saxbuilder sb = new saxbuilder();

     // 通过输入源构造一个document

     org.jdom.document doc;

     doc = (org.jdom.document) sb.build(source);

     org.jdom.element root = doc.getrootelement(); // 指向根节点

     list<org.jdom.element> list = root.getchildren();

     map<string, string> refundordermap = new hashmap<string, string>();

     if (list!= null &&list.size()> 0 ){

       for (org.jdom.element element : list) {

         refundordermap.put(element.getname(), element.gettext());

       }

       return refundordermap;

       }

     return null ;

   }

调用时候主要是获取openid和调起接口的ip(ip十分重要,微信在收到xml后会校验传过去的ip和微信获取的调起接口ip是否一致)
在调用时候当返回错误码为[systemerror]时,一定要使用原单号重试,否则可能造成重复支付等资金风险。
微信官方文档提供有相关的  参数错误码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

原文链接:https://blog.csdn.net/github_38924695/article/details/78850704

查看更多关于java实现微信企业付款到个人功能的详细内容...

  阅读:17次