微信授權以及微信支付所遇到的坑(完善)


 

一、最近又做了微信公眾號支付,前一次做支付沒有好好記錄,這次又浪費了不少時間,故完整的記錄下,下次就可以直接用了。

  • 1、准備工作(微信公眾號、微信商戶號申請)
  • 2、域名購買、域名備案(微信支付必須是備案的域名,測試環境支付測試不了)
  • 測試環境能測試授權等功能,掃描關注可獲得微信管方測試、app_id、app_secret 有了兩個就可以了

二、准備工作續

  第一步:開通微信公眾號支付功能后,就可以獲得app_id、app_secret,這個地方還需要設置一個ip白名單,代碼所放置的服務器ip地址

第二步:設置回調域名,必須是備案的域名,域名去掉 http

 

 

第三步:設置調起微信支付h5頁面的地址,在微信商戶平台設置

以上工作准備好了,接下來開始上代碼。

微信支付重點在簽名的生成,這塊錯一點就很麻煩。

主代碼:

package com.snp.app.controller;

import com.alibaba.fastjson.JSONObject;
import com.snp.app.domain.VO.PayVO;
import com.snp.common.controller.BaseController;
import com.snp.common.utils.ConfigUtil;
import com.snp.common.utils.StringUtil;
import com.snp.order.dao.FinancialClaimOrderDao;
import com.snp.order.domain.FinancialClaimOrderDO;
import com.snp.userManager.domain.UserWechatDO;
import com.snp.userManager.service.UserWechatService;
import com.snp.wechat.config.WechatConfig;
import com.snp.wechat.model.bean.*;
import com.snp.wechat.utils.AdvancedUtil;
import com.snp.wechat.utils.PayUtils;
import com.snp.wechat.utils.WeiXinOrderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * 支付控制器
 */
@RestController
@RequestMapping("/interface/pay")
public class PayController extends BaseController{
    private static Logger logger = LoggerFactory.getLogger(PayController.class);
    @Autowired
    private WeiXinOrderUtil weiXinOrderUtil;
    @Autowired
    private FinancialClaimOrderDao financialClaimOrderDao;
    @Autowired
    private WechatConfig wechatConfig;
    @Autowired
    private UserWechatService userWechatService;

    @ResponseBody
    @RequestMapping(value = "/createWechatOrder", method ={ RequestMethod.GET,RequestMethod.POST})
    public JSONObject createWechatOrder(PayVO payVO, HttpServletRequest request, HttpServletResponse response)
            throws Exception{
        payVO.setPayAmount("1");//1分錢
        payVO.setRobbingOrderNo(PayUtils.getTransferNo16());
        //ResultBody result = new ResultBody();
        logger.info("saveFinancialClaimOrder{}支付金額:"+payVO.getPayAmount());
        logger.info("saveFinancialClaimOrder{}訂單號:"+payVO.getRobbingOrderNo());
        UserWechatDO userWechatDO = userWechatService.getUserWechatByUserId(ConfigUtil.getUserId(request));
        WechatOrder wechatOrder = new WechatOrder();
        wechatOrder.setOpenid(userWechatDO.getWechatOpenid());
        wechatOrder.setOrderName("押金");
        //PayUtils.getTransferNo16()
        wechatOrder.setOut_trade_no(payVO.getRobbingOrderNo());
        wechatOrder.setNonce_str(PayUtils.getNonceStr());
        //wechatOrder.setTotal_fee(MoneyUtil.getOrderMoney(payVO.getPayAmount()));
        wechatOrder.setTotal_fee(Integer.parseInt(payVO.getPayAmount()));
        //請求微信下單 並返回參數
        String resultOrderStr =  weiXinOrderUtil.buildWechatOrderParam(wechatOrder,request);
        JSONObject returnJson=JSONObject.parseObject(resultOrderStr);
        //更新 openID prepay_id 到搶單表中
        FinancialClaimOrderDO finaClaimDO = new FinancialClaimOrderDO();
        finaClaimDO.setOpenId(userWechatDO.getWechatOpenid());
        finaClaimDO.setPrepayId(returnJson.get("pg").toString());
        //financialClaimOrderDao.update(finaClaimDO);
        logger.info("createWechatOrder{}支付結果:"+resultOrderStr);
        //result.setData(resultOrderStr);
        return returnJson;
    }

    //支付之前先去下單 獲取用戶openID
    @RequestMapping(value = "/getWechatOpenId", method = RequestMethod.GET)
    public void getWechatOpenId(PayVO payVO,HttpServletRequest request,HttpServletResponse response) throws IOException{
        //靜默授權 只能獲得openid
        //獲得微信公眾號的唯一標識
        String appID = wechatConfig.getWechatAppId();
        String appSecret = wechatConfig.getWechatAppSecret();

        // 用戶同意授權后,能獲取到code
        String code = request.getParameter("code");
        WeixinOauth2Token weixinOauth2Token = AdvancedUtil.getOauth2AccessToken(appID, appSecret, code);
        String openId = null;
        String accessToken = null;
        if(null!=weixinOauth2Token){
            openId = weixinOauth2Token.getOpenId();
            accessToken = weixinOauth2Token.getAccessToken();
        }
        UserWechatDO userWechatDO = new UserWechatDO();
        userWechatDO.setUserId(ConfigUtil.getUserId(request));
        userWechatDO.setWechatOpenid(openId);
        userWechatDO.setAccessToken(accessToken);
        userWechatService.save(userWechatDO);
        //獲取回調域名
        String url = wechatConfig.getRedirectUri();
        url=url+"/index.html";
        System.out.println(url);
        response.sendRedirect(url);
    }

    /**
     * 支付下單之前 先去判斷是否需要靜默授權獲取openID
     * @param request
     * @param response
     * @throws IOException
     */
    @RequestMapping(value = "/saveFinancialClaimOrder", method = {RequestMethod.GET,RequestMethod.POST})
    public void saveFinancialClaimOrder(PayVO payVO,HttpServletRequest request,HttpServletResponse response)
            throws Exception{
        //查詢數據庫 如果沒有記錄就是第一次登錄,如果有數據判斷token有沒有失效
        if(ConfigUtil.getUserId(request) == 0L){
            throw new Exception("用戶id為空");
        }
        UserWechatDO userWechatDO = userWechatService.getUserWechatByUserId(ConfigUtil.getUserId(request));
        int isLoginFirst = 0;
        if(StringUtil.isEmpty(userWechatDO)){//首次支付 靜默登錄
            isLoginFirst = 1;
        }else{
            //第二次登錄 支付這里不用檢查token失效 openid唯一的不會失效
            isLoginFirst = 0;
        }
        //獲取回調域名
        String url = wechatConfig.getRedirectUri();
        //獲得微信公眾號的唯一標識
        String appID = wechatConfig.getWechatAppId();
        //微信本地中轉站 去獲取token
        String reUrl = wechatConfig.getReUrl();
        reUrl = reUrl+"?userId="+ConfigUtil.getUserId(request);
        //微信靜默授權地址
        String accreditUrlBase = wechatConfig.getAccreditUrlBase();

        if(isLoginFirst == 1){
            accreditUrlBase=accreditUrlBase.replace("Redirect_UI", reUrl).replace("appId", appID);
            response.sendRedirect(accreditUrlBase);//未授權的用戶繼續授權
        }
        //token effective 支付頁面
        url=url+"/index.html";
        System.out.println(url);
        response.sendRedirect(url);
    }
    /**
     * 提交支付后的微信異步返回接口
     * @throws IOException
     */
    @RequestMapping(value="/weixinNotify")
    public void weixinNotify(HttpServletRequest request, HttpServletResponse response) throws IOException{
        String out_trade_no=null;
        String return_code =null;
        try {
            String resultNotify = weiXinOrderUtil.getOrderReturnStream(request);
            Map<String, String> resultMap = PayUtils.getH5PayMap(resultNotify,request);
            System.out.println("支付回調參數:"+resultMap);
            out_trade_no = resultMap.get("out_trade_no");
            return_code = resultMap.get("return_code");

            //通知微信.異步確認成功.必寫.不然微信會一直通知后台.八次之后就認為交易失敗了.
            response.getWriter().write(PayUtils.setXML("SUCCESS", ""));
        }  catch (Exception e) {
            logger.error("微信回調接口出現錯誤:",e);
            try {
                response.getWriter().write(PayUtils.setXML("FAIL", "error"));
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
        FinancialClaimOrderDO fClaimDO = financialClaimOrderDao.getFinanClaimByOrderNo(out_trade_no);
        if(return_code.equals("SUCCESS")){
            //支付成功的業務邏輯
            fClaimDO.setStatus(1);
        }else{
            //支付失敗的業務邏輯
            fClaimDO.setStatus(-1);
        }
        financialClaimOrderDao.update(fClaimDO);
    }
}

頁面:

<!DOCTYPE html>
<html>
<head>
<script src="/js/jquery-1.4.4.min.js"></script>
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
<meta charset="UTF-8">
<title>微信安全支付</title>
</head>
<body>
    <script type="text/javascript">
    window.onload=function() {
        var totalfees = window.location.search;
        totalfees=totalfees.substring(11,12);
            $.ajax({
                type : "POST",
                url : '/interface/pay/createWechatOrder?userId=4',
                success : function(data) {
                    var appId = data.appId;
                    var timeStamp = data.timeStamp;
                    var nonceStr = data.nonceStr;
                    var packages = "prepay_id=" + data.pg;
                    var signType = "MD5";
                    var paySign = data.paySign;
                    if (data.result == "success") {
                        pay();
                        function onBridgeReady(){    
                            WeixinJSBridge.invoke(    
                                'getBrandWCPayRequest', {    
                                    "appId" : appId,     //公眾號名稱,由商戶傳入         
                                    "timeStamp": timeStamp+"",         //時間戳,自1970年以來的秒數         
                                    "nonceStr" : nonceStr, //隨機串         
                                    "package" :  packages,         
                                    "signType" : signType,         //微信簽名方式:         
                                    "paySign" : paySign    //微信簽名     
                                },    
                                    
                                function(res){         
                                    if(res.err_msg == "get_brand_wcpay_request:ok" ) {    
                                        alert("支付成功");  // 使用以上方式判斷前端返回,微信團隊鄭重提示:res.err_msg將在用戶支付成功后返回    ok,但並不保證它絕對可靠。     
                                        //回到用戶訂單列表  
                                       // window.location.href="http://wx.ooklady.com/wechat/order/orderlist";  
                                    }else if (res.err_msg == "get_brand_wcpay_request:cancel")  {  
                                        alert("支付過程中用戶取消");  
                                    }else{  
                                       //支付失敗  
                                       alert(JSON.stringify(res))
                                    }       
                                }    
                            );     
                         }   
                        //喚起微信支付  
                        function pay(){    
                            if (typeof WeixinJSBridge == "undefined"){    
                               if( document.addEventListener ){    
                                   document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);    
                               }else if (document.attachEvent){    
                                   document.attachEvent('WeixinJSBridgeReady', onBridgeReady);     
                                   document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);    
                               }    
                            }else{    
                               onBridgeReady();    
                            }     
                                
                        }  
                    }
                        
                }        
            });        
        }
    </script>
</body>
</html>

工具類:

package com.snp.wechat.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.snp.wechat.config.WechatConfig;
import com.snp.wechat.model.bean.WechatOrder;
import com.snp.wechat.model.bean.WeixinOauth2Token;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * 微信公用工具類
 */
@Component
public class WeiXinOrderUtil {

    @Autowired
    private WechatConfig wechatConfig;

    /**
     * 組裝統一下單參數
     * @return
     */
    public String buildWechatOrderParam(WechatOrder wechatOrder,HttpServletRequest request)  throws Exception{
        String payKey = wechatConfig.getPaykey();
        String signType = wechatConfig.getSignType();
        SortedMap<String, String> signMap = new TreeMap<String, String>();
        long timeStamp = PayUtils.getUnixTime(new Date());
        wechatOrder.setAppid(wechatConfig.getWechatAppId());
        wechatOrder.setTrade_type(wechatConfig.getTradeType());
        //構建參數返回前台 請求支付接口
        String prepayId = createWechatOrder(wechatOrder,request);
        signMap.put("appId",wechatOrder.getAppid());
        signMap.put("timeStamp", timeStamp+"");
        signMap.put("nonceStr",  wechatOrder.getNonce_str());
        signMap.put("package", "prepay_id="+prepayId);
        signMap.put("signType", signType);
        String paySign = PayUtils.getSign(signMap, payKey);
        signMap.put("pg", prepayId);
        signMap.put("paySign", paySign);
        signMap.put("result", "success");
        String json = JSON.toJSONString(signMap);
        JSONObject returnJson=JSONObject.parseObject(json);
        return returnJson.toJSONString();
    }

    /**
     * 創建下單簽名 包含商品信息
     * @return
     */
    public String createWechatSign(WechatOrder wechatOrder){
        String mch_id = wechatConfig.getMchId();
        String notify_url = wechatConfig.getNotifyUrl();
        String device_info = wechatConfig.getDeviceInfo();
        String payKey = wechatConfig.getPaykey();

        //將商品信息打包
        SortedMap<String, String> parameters = new TreeMap<String, String>();
        parameters.put("appid", wechatOrder.getAppid());//公眾號id 這地方一定要小寫並跟下面xml文件對應都是小寫
        parameters.put("mch_id",mch_id);//商戶ID
        parameters.put("device_info", device_info);
        parameters.put("body", wechatOrder.getOrderName());//名稱
        parameters.put("trade_type", wechatOrder.getTrade_type());
        parameters.put("nonce_str", wechatOrder.getNonce_str());//隨機數
        parameters.put("notify_url", notify_url);
        parameters.put("out_trade_no", wechatOrder.getOut_trade_no());
        parameters.put("total_fee", wechatOrder.getTotal_fee()+"");
        //   parameters.put("spbill_create_ip", spbill_create_ip );
        parameters.put("openid", wechatOrder.getOpenid());
        //根據上述的數據生成預支付訂單號的前面sign
        return PayUtils.getSign(parameters, payKey);
    }

    /**
     * 創建微信訂單 請求微信接口下單
     * @return
     */
    public String createWechatOrder(WechatOrder wechatOrder,HttpServletRequest request) throws Exception{
         String mch_id = wechatConfig.getMchId();
         String notify_url = wechatConfig.getNotifyUrl();
         String device_info = wechatConfig.getDeviceInfo();
         String createOrderURL =  wechatConfig.getCreateOrderUrl();

        //生成統一支付接口數據
        String xml = "<xml>"+
                "<appid>"+wechatOrder.getAppid()+"</appid>"+
                "<body>"+wechatOrder.getOrderName()+"</body>"+
                "<device_info>"+device_info+"</device_info>"+
                "<mch_id>"+mch_id+"</mch_id>"+
                "<nonce_str>"+wechatOrder.getNonce_str()+"</nonce_str>"+
                "<notify_url>"+notify_url+"</notify_url>"+
                "<openid>"+wechatOrder.getOpenid()+"</openid>"+
                "<out_trade_no>"+wechatOrder.getOut_trade_no()+"</out_trade_no>"+
                "<total_fee>"+wechatOrder.getTotal_fee()+"</total_fee>"+
                "<trade_type>"+wechatOrder.getTrade_type()+"</trade_type>"+
                "<sign>"+createWechatSign(wechatOrder)+"</sign>"+
                "</xml>";
        //調用統一支付接口
        String result = PayUtils.httpsRequest(createOrderURL, "POST", xml);
        System.out.println("-----------------------------統一下單結果---------------------------");
        System.out.println(result);
        Map<String, String> resultMap = null;
        resultMap=PayUtils.getH5PayMap(result,request);
        return resultMap.get("prepay_id");  //預支付ID,保存到數據庫中
    }

    /**
     * 解析微信支付回調的結果
     * @return
     */
    public static String getOrderReturnStream(HttpServletRequest request) throws IOException {
        InputStream inStream = request.getInputStream();
        ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inStream.read(buffer)) != -1) {
            outSteam.write(buffer, 0, len);
        }
        outSteam.close();
        inStream.close();
        return new String(outSteam.toByteArray(),"utf-8");
    }

    /**
     * 獲取 WeixinOauth2Token
     * @return
     */
    public  WeixinOauth2Token getWeixinOauth2Token(String code){
        //獲得微信公眾號的唯一標識
        String appId = wechatConfig.getWechatAppId();
        String appSecret = wechatConfig.getWechatAppSecret();
        return AdvancedUtil.getOauth2AccessToken(appId, appSecret, code);
    }
}
package com.snp.wechat.utils;


import com.snp.common.utils.StringUtil;
import com.snp.userManager.domain.UserWechatDO;
import com.snp.wechat.model.bean.WeixinOauth2Token;
import org.apache.commons.lang3.StringUtils;

import com.alibaba.fastjson.JSONObject;

import java.util.Date;


/**
 * @author yuwei
 * 工具類
 * 2016年12月21日 下午1:58:38
 */
public class AdvancedUtil {

    public AdvancedUtil() {
        super();
        // TODO Auto-generated constructor stub
    }
 
    /**
     * 獲取網頁授權憑證
     * 
     * @param appId 公眾賬號的唯一標識
     * @param appSecret 公眾賬號的密鑰
     * @param code
     * @return 
     * @return WeixinAouth2Token
     */
    public static WeixinOauth2Token getOauth2AccessToken(String appId, String appSecret, String code) {
        WeixinOauth2Token wat = null;
        // 拼接請求地址
        String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code";
        requestUrl = requestUrl.replace("APPID", appId);
        requestUrl = requestUrl.replace("SECRET", appSecret);
        requestUrl = requestUrl.replace("CODE", code);
        // 獲取網頁授權憑證
        JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
        if (null != jsonObject) {
            try {
                wat = new WeixinOauth2Token();
                wat.setAccessToken(jsonObject.getString("access_token"));
                wat.setExpiresIn(jsonObject.getInteger("expires_in"));
                wat.setRefreshToken(jsonObject.getString("refresh_token"));
                wat.setOpenId(jsonObject.getString("openid"));
                wat.setScope(jsonObject.getString("scope"));
            } catch (Exception e) {
                wat = null;
                int errorCode = jsonObject.getInteger("errcode");
                String errorMsg = jsonObject.getString("errmsg");
                System.out.println(errorCode);
                System.out.println(errorMsg);
              //  log.error("獲取網頁授權憑證失敗 errcode:{} errmsg:{}", errorCode, errorMsg);
            }
        }
        return wat;
    }
    /**
     * 通過網頁授權獲取用戶信息
     * 
     * @param accessToken 網頁授權接口調用憑證
     * @param openId 用戶標識
     * @return SNSUserInfo
     */
    public static UserWechatDO getWechatInfo(String accessToken, String openId,String refreshToken) {
        UserWechatDO userWechatDO = null;
        // 拼接請求地址
        String requestUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
        // 通過網頁授權獲取用戶信息
        JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);

        if (!StringUtil.isEmpty(jsonObject)) {
            try {
                userWechatDO = new UserWechatDO();
                // 用戶的標識
                userWechatDO.setWechatOpenid(jsonObject.getString("openid"));
                // 昵稱
                String nickname = jsonObject.getString("nickname");
                nickname = filterEmoji(nickname);
                userWechatDO.setNickName(nickname);
                // 性別(1是男性,2是女性,0是未知)
                userWechatDO.setSex(jsonObject.getInteger("sex"));
                // 用戶所在國家
                userWechatDO.setCountry(jsonObject.getString("country"));
                // 用戶所在省份
                userWechatDO.setProvince(jsonObject.getString("province"));
                // 用戶所在城市
                userWechatDO.setCity(jsonObject.getString("city"));
                // 用戶頭像
                userWechatDO.setHeadImgUrl(jsonObject.getString("headimgurl"));
                //UnicodeID
                userWechatDO.setWechatUnionid(jsonObject.getString("unionid"));
                //userWechatDO.setWin(0);
                //userWechatDO.setLose(0);
                //查詢時間
          //      Date date = new Date();
               // player.setJoinTime(date);
                //首次授權時間
                userWechatDO.setCreateTime(new Date());
                //更新時間
                userWechatDO.setUpdateTime(new Date());
                userWechatDO.setLasttIme(new Date());
                //憑證保存
                userWechatDO.setAccessToken(accessToken);
                //刷新憑證
                userWechatDO.setRefreshToken(refreshToken);
                // 用戶特權信息
             //   snsUserInfo.setPrivilegeList(JSONArray.parseObject(jsonObject.getJSONArray("privilege"), List.class));
            } catch (Exception e) {
                userWechatDO = null;
                int errorCode = jsonObject.getInteger("errcode");
                String errorMsg = jsonObject.getString("errmsg");
                System.out.println(errorCode);
                System.out.println(errorMsg);
               // log.error("獲取用戶信息失敗 errcode:{} errmsg:{}", errorCode, errorMsg);
            }
        }
        return userWechatDO;
    }
    
    //檢驗憑證是否失效
    @SuppressWarnings("unused")
    public static boolean  judgeToken(String accessToken, String openId){
        // 拼接請求地址
        String requestUrl = "https://api.weixin.qq.com/sns/auth?access_token=ACCESS_TOKEN&openid=OPENID";
        requestUrl = requestUrl.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
        // 通過網頁授權獲取用戶信息
        JSONObject jsonObject = CommonUtil.httpsRequest(requestUrl, "GET", null);
        int errorCode = jsonObject.getInteger("errcode");
        String errorMsg = jsonObject.getString("errmsg");//正確返回OK
        errorMsg = errorMsg.toUpperCase();
        if(errorMsg.equals("OK")){
            return true;
        }
        return false;
    }

    
    
    //去掉ios特殊字符
    public static String filterEmoji(String source) {
        if (StringUtils.isBlank(source)) {
            return source;
        }
        StringBuilder buf = null;
        int len = source.length();
        for (int i = 0; i < len; i++) {
            char codePoint = source.charAt(i);
            if (isNotEmojiCharacter(codePoint)) {
                if (buf == null) {
                    buf = new StringBuilder(source.length());
                }
                buf.append(codePoint);
                }
        }
        if (buf == null) {
            return source;
        } else {
            if (buf.length() == len) {
                buf = null;
                return source;
            } else {
                return buf.toString();
            }
        }
    }
    //判斷特殊字符串
    private static boolean isNotEmojiCharacter(char codePoint) {
        return (codePoint == 0x0) ||
                (codePoint == 0x9) ||
                (codePoint == 0xA) ||
                (codePoint == 0xD) ||
                ((codePoint >= 0x20) && (codePoint <= 0xD7FF)) ||
                ((codePoint >= 0xE000) && (codePoint <= 0xFFFD)) ||
                ((codePoint >= 0x10000) && (codePoint <= 0x10FFFF));
    }
}

以上就是主要代碼。代碼寫的還不夠好,不喜勿噴

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM