SpringBoot整合Shiro后無法接收銀聯(lián)支付回調(diào)參數(shù)問題

快速導(dǎo)航

SpringBoot整合Shiro骨架采用的是FEBS-Shiro, FEBS-Shiro整合銀聯(lián)支付,支付骨架采用的是IJPay,感謝兩位作者的開源。

\*\* IJPay最新版本銀聯(lián)支付已修改為云閃付,這里采用的是V2.2.0版本,還是采用的網(wǎng)關(guān)支付方式。

\*\* 附上Gitee源碼地址,如果幫助到您,還請給個Star。代碼示例

異?,F(xiàn)象

代碼示例

直接使用IJPay中提供的代碼

/**
 * 后臺回調(diào)
 */
@RequestMapping(value = "/backRcvResponse", method = { RequestMethod.POST, RequestMethod.GET })
@ResponseBody
public String backRcvResponse(HttpServletRequest request) {
    logger.info("BackRcvResponse接收后臺通知開始,Content-Type:{}", request.getContentType());

    String encoding = "UTF-8";

    String notifyStr = readData(request);
    // 獲取銀聯(lián)通知服務(wù)器發(fā)送的后臺通知參數(shù)
    Map<String, String> reqParam = getAllRequestParamToMap(notifyStr);
    LogUtil.printRequestLog(reqParam);

    // 重要!驗證簽名前不要修改reqParam中的鍵值對的內(nèi)容,否則會驗簽不過
    if (!AcpService.validate(reqParam, encoding)) {
        logger.info("后臺驗證簽名結(jié)果[失敗].");
        // 驗簽失敗,需解決驗簽問題

    } else {
        logger.info("后臺驗證簽名結(jié)果[成功].");
        // 【注:為了安全驗簽成功才應(yīng)該寫商戶的成功處理邏輯】交易成功,更新商戶訂單狀態(tài)

        String orderId = reqParam.get("orderId"); // 獲取后臺通知的數(shù)據(jù),其他字段也可用類似方式獲取
        String respCode = reqParam.get("respCode");
        // 判斷respCode=00、A6后,對涉及資金類的交易,請再發(fā)起查詢接口查詢,確定交易成功后更新數(shù)據(jù)庫。
        logger.info("orderId>>>" + orderId + " respCode>>" + respCode);
    }
    logger.info("BackRcvResponse接收后臺通知結(jié)束");
    // 返回給銀聯(lián)服務(wù)器http 200 狀態(tài)碼
    return "ok";
}

控制臺日志

上述代碼執(zhí)行結(jié)果日志

2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController BackRcvResponse接收后臺通知開始,Content-Type:application/x-www-form-urlencoded; charset=UTF-8
2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController 收到通知報文:
2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 SDK_MSG_LOG ============================== SDK REQ MSG BEGIN ==============================
2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 SDK_MSG_LOG ==============================  SDK REQ MSG END  ==============================
2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 ACP_SDK_LOG 驗簽處理開始
2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController 后臺驗證簽名結(jié)果[失敗].
2020-06-13 16:52:46 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController BackRcvResponse接收后臺通知結(jié)束

異常原因

\*\* 因為Shiro會自動將原生request對象包裝成ShiroRequest,上面的String notifyStr = readData(request)獲取報文是從request.getReader()中獲取,這里獲取不到銀聯(lián)支付成功后返回的報文,所以導(dǎo)致驗簽失?。?。

查找資料,找到的解釋如下:

今天發(fā)現(xiàn)一個很奇怪的問題,我們系統(tǒng)里用REST方式做前后端的訪問,具體就是所有的請求都是POST,URL對應(yīng)處理的action,HTTP body里的json是請求參數(shù);后端程序里從Request.getReader拿到j(luò)son參數(shù),然后調(diào)用相應(yīng)的action來處理。有一個登陸接口,在頁面ajax和android里請求是正常的,但是在iphone里請求出錯。調(diào)試了下,發(fā)現(xiàn)request.getReader拿不到數(shù)據(jù)。

通過tcpmon代理查看HTTP請求報文,對比下正確和錯誤的REST請求,感覺最大的問題可能是出現(xiàn)在Content-type上,進(jìn)而發(fā)現(xiàn)application/x-www-form-urlencoded時,會出現(xiàn)這個問題,但是text/html,text/xml等格式都沒有問題。這就能確定是Content-Type引起的了。

為什么Content-Type會引起這個問題呢?

我們知道request.getInputStream\getReader,都只能調(diào)用一次,調(diào)用過了,buffer里的數(shù)據(jù)就沒有了。而request.getParameterXX方法也可能會解析buffer,如果這個調(diào)用過了,再調(diào)用getReader也會沒有數(shù)據(jù)了。難道Content-Type不同的時候?qū)е抡{(diào)用了這個?

調(diào)試下,追了追shiro和tomcat的代碼,發(fā)現(xiàn)果然如此。

請求進(jìn)來先進(jìn)過shiro的filter,filter里試圖拿到當(dāng)前subject,先從cookie試著拿sessionId,不行就從URL中試著拿sessionId,還沒有的話就從request.getParameter里獲取sessionId,這里調(diào)用到了tomcat的request.getParameter實現(xiàn):如果Content-Type是multipart/form-data或者application/x-www-form-urlencoded,則直接解析http body……問題就出現(xiàn)了。

簡單的說就是,如果請求是application/x-www-form-urlencoded格式的話,shiro的filter在我們的servlet或action處理之前,就可能直接把request的body給讀取并清空了。

通過這個實現(xiàn)我們也可以看到:除了這兩個Content-Type之外的格式都不會有問題,登陸后sessionId放到cookie里了也不會有問題。

按理講,我們用json應(yīng)該手動設(shè)置Content-Type:application/json;因為application/x-www-form-urlencoded就是為了在body里使用類似QueryString的key-value格式。所以寫代碼的時候要注意了,如果某些HTTP庫的實現(xiàn)里,默認(rèn)POST是form格式的,如果你要自己處理HTTP body就需要手工的設(shè)置自己想要的Content-Type了。

知道怎么回事了,就很好處理了。在xcode里,將Content-Type改成text/html或application/json即可。

進(jìn)一步的來看,shiro處理考慮到sessionId在cookie和url里,還考慮到一種情況:session藏在頁面form的hidden里,通過form的post方式,把key-value作為http body來post到服務(wù)器端,shiro可能通過解析httpbody拿到sessionId,這個對session來說用處不大,因為我們一般都放到cookie或url的jsessionId里,但是對于某些需要自己處理http body的場景,shiro的filter顯然破壞掉了后續(xù)對body的request.getReader讀取。

版權(quán)聲明:本文為CSDN博主「kimmking」的原創(chuàng)文章,遵循CC 4.0 BY-SA版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。原文鏈接:https://blog.csdn.net/kimmking/article/details/17505637

解決方法

上述文章已經(jīng)很明確的告訴我們問題出現(xiàn)的原因了,那我們該如何處理呢?這里我們更改接收參數(shù)的方式。

代碼示例

\*\* 這里采用@RequestParam來接收銀聯(lián)支付成功返回的參數(shù)是因為我們通過獲取Content-Type發(fā)現(xiàn),銀聯(lián)返回參數(shù)的Content-Type為:application/x-www-form-urlencoded; charset=UTF-8。

/**
 * 后臺回調(diào)
 * @param request
 * @param respParam 獲取銀聯(lián)通知服務(wù)器發(fā)送的后臺通知參數(shù)
 * @return
 */
@RequestMapping(value = "/backRcvResponse", method = { RequestMethod.POST, RequestMethod.GET })
@ResponseBody
public String backRcvResponse(@RequestParam Map<String, String> respParam) {
    logger.info("BackRcvResponse接收后臺通知開始");

    String encoding = "UTF-8";

    LogUtil.printRequestLog(respParam);

    // 重要!驗證簽名前不要修改reqParam中的鍵值對的內(nèi)容,否則會驗簽不過
    if (!AcpService.validate(respParam, encoding)) {
        logger.info("后臺驗證簽名結(jié)果[失敗].");
        // 驗簽失敗,需解決驗簽問題

    } else {
        logger.info("后臺驗證簽名結(jié)果[成功].");
        // 【注:為了安全驗簽成功才應(yīng)該寫商戶的成功處理邏輯】交易成功,更新商戶訂單狀態(tài)

        String orderId = respParam.get("orderId"); // 獲取后臺通知的數(shù)據(jù),其他字段也可用類似方式獲取
        String respCode = respParam.get("respCode");
        // 判斷respCode=00、A6后,對涉及資金類的交易,請再發(fā)起查詢接口查詢,確定交易成功后更新數(shù)據(jù)庫。
        logger.info("orderId>>>" + orderId + " respCode>>" + respCode);
    }
    logger.info("BackRcvResponse接收后臺通知結(jié)束");
    // 返回給銀聯(lián)服務(wù)器http 200 狀態(tài)碼
    return "ok";
}

控制臺日志

修改后我們來看下上述代碼執(zhí)行結(jié)果日志

2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController BackRcvResponse接收后臺通知開始
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG ============================== SDK REQ MSG BEGIN ==============================
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [accNo] = [6226********0048]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [accessType] = [0]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [bizType] = [000201]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [currencyCode] = [156]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [encoding] = [UTF-8]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [merId] = [777290058110048]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [orderId] = [1592039725990]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [payCardType] = [01]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [payType] = [0001]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [queryId] = [512006131715250536508]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [reqReserved] = [reqReserved]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [respCode] = [00]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [respMsg] = [成功[0000000]]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [settleAmt] = [6666]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [settleCurrencyCode] = [156]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [settleDate] = [0613]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [signMethod] = [01]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [signPubKeyCert] = [-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIFEBJJZVgwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC
Q04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMTcxMTAxMDcyNDA4WhcN
MjAxMTAxMDcyNDA4WjB3MQswCQYDVQQGEwJjbjESMBAGA1UEChMJQ0ZDQSBPQ0Ex
MQ4wDAYDVQQLEwVDVVBSQTEUMBIGA1UECxMLRW50ZXJwcmlzZXMxLjAsBgNVBAMU
JTA0MUBaMjAxNy0xMS0xQDAwMDQwMDAwOlNJR05AMDAwMDAwMDEwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDIWO6AESrg+34HgbU9mSpgef0sl6avr1d
bD/IjjZYM63SoQi3CZHZUyoyzBKodRzowJrwXmd+hCmdcIfavdvfwi6x+ptJNp9d
EtpfEAnJk+4quriQFj1dNiv6uP8ARgn07UMhgdYB7D8aA1j77Yk1ROx7+LFeo7rZ
Ddde2U1opPxjIqOPqiPno78JMXpFn7LiGPXu75bwY2rYIGEEImnypgiYuW1vo9UO
G47NMWTnsIdy68FquPSw5FKp5foL825GNX3oJSZui8d2UDkMLBasf06Jz0JKz5AV
blaI+s24/iCfo8r+6WaCs8e6BDkaijJkR/bvRCQeQpbX3V8WoTLVAgMBAAGjgfQw
gfEwHwYDVR0jBBgwFoAUz3CdYeudfC6498sCQPcJnf4zdIAwSAYDVR0gBEEwPzA9
BghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNu
L3VzL3VzLTE0Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vdWNybC5jZmNh
LmNvbS5jbi9SU0EvY3JsMjQ4NzIuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU
mQQLyuqYjES7qKO+zOkzEbvdFwgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAujhBuOcuxA+VzoUH84uoFt5aaBM3vGlpW
KVMz6BUsLbIpp1ho5h+LaMnxMs6jdXXDh/du8X5SKMaIddiLw7ujZy1LibKy2jYi
YYfs3tbZ0ffCKQtv78vCgC+IxUUurALY4w58fRLLdu8u8p9jyRFHsQEwSq+W5+bP
MTh2w7cDd9h+6KoCN6AMI1Ly7MxRIhCbNBL9bzaxF9B5GK86ARY7ixkuDCEl4XCF
JGxeoye9R46NqZ6AA/k97mJun//gmUjStmb9PUXA59fR5suAB5o/5lBySZ8UXkrI
pp/iLT8vIl1hNgLh0Ghs7DBSx99I+S3VuUzjHNxL6fGRhlix7Rb8
-----END CERTIFICATE-----]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [traceNo] = [053650]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [traceTime] = [0613171525]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [txnAmt] = [6666]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [txnSubType] = [01]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [txnTime] = [20200613171525]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [txnType] = [01]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [version] = [5.1.0]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG [signature] = [fMAWGyurRRKCk31AsG/J/0yKpk92ViOKmQ83O0OOgoN/iIy/cxUhGNgA6RqbScGZqLG5UVyQI/BUWCQgeuTX9MtA4sd4kmm3F9BgCR3s4kIcJqKM/0/x6ZdPeBU7nd8F/Aev07P3YA3wmzz0bbk/htrhFuH8rWQRArzCv8cLy78ZxKbetzI+BU8pKzghK7YPY7yTQmimYXkuIQpq38IJvWSzybvAwXzXre5m/DgXZLdFvLhuvsb0H2POwz+qN90FMpl7VlJAe+FhNi6yOIfKyvKZJUErG0uGQt5hSYoCzCcu3IUhYSwSzP8gfhKOrk3yWExefY90FKQOcyFTBfjZxg==]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 SDK_MSG_LOG ==============================  SDK REQ MSG END  ==============================
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 ACP_SDK_LOG 驗簽處理開始
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 ACP_SDK_LOG verify certificate chain succeed.
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 ACP_SDK_LOG 簽名原文:[fMAWGyurRRKCk31AsG/J/0yKpk92ViOKmQ83O0OOgoN/iIy/cxUhGNgA6RqbScGZqLG5UVyQI/BUWCQgeuTX9MtA4sd4kmm3F9BgCR3s4kIcJqKM/0/x6ZdPeBU7nd8F/Aev07P3YA3wmzz0bbk/htrhFuH8rWQRArzCv8cLy78ZxKbetzI+BU8pKzghK7YPY7yTQmimYXkuIQpq38IJvWSzybvAwXzXre5m/DgXZLdFvLhuvsb0H2POwz+qN90FMpl7VlJAe+FhNi6yOIfKyvKZJUErG0uGQt5hSYoCzCcu3IUhYSwSzP8gfhKOrk3yWExefY90FKQOcyFTBfjZxg==]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 ACP_SDK_LOG 待驗簽返回報文串:[accNo=6226********0048&accessType=0&bizType=000201&currencyCode=156&encoding=UTF-8&merId=777290058110048&orderId=1592039725990&payCardType=01&payType=0001&queryId=512006131715250536508&reqReserved=reqReserved&respCode=00&respMsg=成功[0000000]&settleAmt=6666&settleCurrencyCode=156&settleDate=0613&signMethod=01&signPubKeyCert=-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIFEBJJZVgwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UEBhMC
Q04xMDAuBgNVBAoTJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEXMBUGA1UEAxMOQ0ZDQSBURVNUIE9DQTEwHhcNMTcxMTAxMDcyNDA4WhcN
MjAxMTAxMDcyNDA4WjB3MQswCQYDVQQGEwJjbjESMBAGA1UEChMJQ0ZDQSBPQ0Ex
MQ4wDAYDVQQLEwVDVVBSQTEUMBIGA1UECxMLRW50ZXJwcmlzZXMxLjAsBgNVBAMU
JTA0MUBaMjAxNy0xMS0xQDAwMDQwMDAwOlNJR05AMDAwMDAwMDEwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDIWO6AESrg+34HgbU9mSpgef0sl6avr1d
bD/IjjZYM63SoQi3CZHZUyoyzBKodRzowJrwXmd+hCmdcIfavdvfwi6x+ptJNp9d
EtpfEAnJk+4quriQFj1dNiv6uP8ARgn07UMhgdYB7D8aA1j77Yk1ROx7+LFeo7rZ
Ddde2U1opPxjIqOPqiPno78JMXpFn7LiGPXu75bwY2rYIGEEImnypgiYuW1vo9UO
G47NMWTnsIdy68FquPSw5FKp5foL825GNX3oJSZui8d2UDkMLBasf06Jz0JKz5AV
blaI+s24/iCfo8r+6WaCs8e6BDkaijJkR/bvRCQeQpbX3V8WoTLVAgMBAAGjgfQw
gfEwHwYDVR0jBBgwFoAUz3CdYeudfC6498sCQPcJnf4zdIAwSAYDVR0gBEEwPzA9
BghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNu
L3VzL3VzLTE0Lmh0bTA5BgNVHR8EMjAwMC6gLKAqhihodHRwOi8vdWNybC5jZmNh
LmNvbS5jbi9SU0EvY3JsMjQ4NzIuY3JsMAsGA1UdDwQEAwID6DAdBgNVHQ4EFgQU
mQQLyuqYjES7qKO+zOkzEbvdFwgwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUF
BwMEMA0GCSqGSIb3DQEBBQUAA4IBAQAujhBuOcuxA+VzoUH84uoFt5aaBM3vGlpW
KVMz6BUsLbIpp1ho5h+LaMnxMs6jdXXDh/du8X5SKMaIddiLw7ujZy1LibKy2jYi
YYfs3tbZ0ffCKQtv78vCgC+IxUUurALY4w58fRLLdu8u8p9jyRFHsQEwSq+W5+bP
MTh2w7cDd9h+6KoCN6AMI1Ly7MxRIhCbNBL9bzaxF9B5GK86ARY7ixkuDCEl4XCF
JGxeoye9R46NqZ6AA/k97mJun//gmUjStmb9PUXA59fR5suAB5o/5lBySZ8UXkrI
pp/iLT8vIl1hNgLh0Ghs7DBSx99I+S3VuUzjHNxL6fGRhlix7Rb8
-----END CERTIFICATE-----&traceNo=053650&traceTime=0613171525&txnAmt=6666&txnSubType=01&txnTime=20200613171525&txnType=01&version=5.1.0]
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 ACP_SDK_LOG 驗證簽名成功
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController 后臺驗證簽名結(jié)果[成功].
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController orderId>>>1592039725990 respCode>>00
2020-06-13 17:15:51 INFO  http-nio-8080-exec-8 cc.mrbird.febs.pay.unionpay.controller.UnionPayController BackRcvResponse接收后臺通知結(jié)束

通過日志我們可以看出已經(jīng)成功接收銀聯(lián)支付成功返回的報文,并且已經(jīng)驗證簽名成功

\*\* 注意:代碼示例中支付控制器包路徑:cc.mrbird.febs.pay.unionpay.controller,這里只修改了后臺回調(diào)(/backRcvResponse)和前臺回調(diào)(/frontRcvResponse),其余如果使用到請參照修改。

參考資料

Shiro導(dǎo)致Request.getReader無法獲取數(shù)據(jù)

Shiro導(dǎo)致request.getInputStream()無法獲取數(shù)據(jù)

request.getReader()的作用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容