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


    一、最近又做了微信公众号支付,前一次做支付没有好好记录,这次又浪费了不少时间,故完整的记录下,下次就可以直接用了。

    • 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));
        }
    }

    以上就是主要代码。代码写的还不够好,不喜勿喷

  • 相关阅读:
    mysqldump 备份导出数据排除某张表
    PHP中cookies跨目录无法调用解决办法
    数据库之mac上mysql root密码忘记或权限错误的解决办法
    mac攻略(4) -- 使用brew配置php7开发环境(mac+php+apache+mysql+redis)
    js中event.keyCode用法及keyCode对照表
    BigDecimal用法详解
    Java开发中的23种设计模式详解(转)
    常用正则表达式大全 (转)
    sql查询重复记录、删除重复记录方法大全
    使用连接来代替in和not in(使用外连接技巧)
  • 原文地址:https://www.cnblogs.com/yw-ah/p/6245196.html
Copyright © 2020-2023  润新知