JAVA生成二维码扫码进入h5微信支付宝支付_调皮小帅的博客-程序员宅基地_java 支付宝h5支付

技术标签: spring boot  java  web  微信支付宝支付  redis  二维码  

第一步准备

(1)微信需要的公众服务号和商户号;沙箱有很多问题,所以本人以正式的配置实现,其中公众号需要配置授权路径

其中公众号需配置

商户号需到产品中心 -> 开发配置 -> 支付配置 ->添加JSAPI支付

(2)支付宝需要的商户号

(3)WEB项目:本人的项目基于SpringBoot+SSM框架的网站项目

(4)demo:github链接


第二步生成二维码

(1)在pom.xml引入依赖:

        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>core</artifactId>
            <version>3.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.google.zxing</groupId>
            <artifactId>javase</artifactId>
            <version>3.3.0</version>
        </dependency>

(2)编写工具类QrCodeUtils:  

package com.meal.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import javax.imageio.ImageIO;

import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
import java.util.Random;

/**
 * 工程名:meal
 * 包名:com.meal.util
 * 文件名:QrCodeUtils.java
 * @author lcwen
 * @version $Id: QrCodeUtils.java 2020年3月10日 上午11:53:55 $
 */
public class QrCodeUtils {

    private static final String CHARSET = "utf-8";
    public static final String FORMAT = "JPG";
    
    // 二维码尺寸
    private static final int QRCODE_SIZE = 180;
    // LOGO宽度
    private static final int LOGO_WIDTH = 60;
    // LOGO高度
    private static final int LOGO_HEIGHT = 60;

    /**
     * 生成二维码
     *
     * @param content      二维码内容
     * @param logoPath     logo地址
     * @param needCompress 是否压缩logo
     * @return 图片
     * @throws Exception
     */
    public static BufferedImage createImage(String content, String logoPath, boolean needCompress) throws Exception {
        Hashtable<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
        hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
        hints.put(EncodeHintType.MARGIN, 1);
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, QRCODE_SIZE, QRCODE_SIZE,
                hints);
        int width = bitMatrix.getWidth();
        int height = bitMatrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        if (logoPath == null || "".equals(logoPath)) {
            return image;
        }
        // 插入图片
        QrCodeUtils.insertImage(image, logoPath, needCompress);
        return image;
    }

    /**
     * 插入LOGO
     *
     * @param source       二维码图片
     * @param logoPath     LOGO图片地址
     * @param needCompress 是否压缩
     * @throws IOException
     */
    private static void insertImage(BufferedImage source, String logoPath, boolean needCompress) throws IOException {
        InputStream inputStream = null;
        try {
            inputStream = FileUtils.getResourceAsStream(logoPath);
            Image src = ImageIO.read(inputStream);
            int width = src.getWidth(null);
            int height = src.getHeight(null);
            if (needCompress) { // 压缩LOGO
                if (width > LOGO_WIDTH) {
                    width = LOGO_WIDTH;
                }
                if (height > LOGO_HEIGHT) {
                    height = LOGO_HEIGHT;
                }
                Image image = src.getScaledInstance(width, height, Image.SCALE_SMOOTH);
                BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
                Graphics g = tag.getGraphics();
                g.drawImage(image, 0, 0, null); // 绘制缩小后的图
                g.dispose();
                src = image;
            }
            // 插入LOGO
            Graphics2D graph = source.createGraphics();
            int x = (QRCODE_SIZE - width) / 2;
            int y = (QRCODE_SIZE - height) / 2;
            graph.drawImage(src, x, y, width, height, null);
            Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
            graph.setStroke(new BasicStroke(3f));
            graph.draw(shape);
            graph.dispose();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        } finally {
            if (inputStream != null) {
                inputStream.close();
            }
        }
    }

    /**
     * 生成二维码(内嵌LOGO)
     * 二维码文件名随机,文件名可能会有重复
     *
     * @param content      内容
     * @param logoPath     LOGO地址
     * @param destPath     存放目录
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static String encode(String content, String logoPath, String destPath, boolean needCompress) throws Exception {
        BufferedImage image = QrCodeUtils.createImage(content, logoPath, needCompress);
        mkdirs(destPath);
        String fileName = new Random().nextInt(99999999) + "." + FORMAT.toLowerCase();
        ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));
        return fileName;
    }

    /**
     * 生成二维码(内嵌LOGO)
     * 调用者指定二维码文件名
     *
     * @param content      内容
     * @param logoPath     LOGO地址
     * @param destPath     存放目录
     * @param fileName     二维码文件名
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static String encode(String content, String logoPath, String destPath, String fileName, boolean needCompress) throws Exception {
        BufferedImage image = QrCodeUtils.createImage(content, logoPath, needCompress);
        mkdirs(destPath);
        fileName = fileName.substring(0, fileName.indexOf(".") > 0 ? fileName.indexOf(".") : fileName.length())
                + "." + FORMAT.toLowerCase();
        ImageIO.write(image, FORMAT, new File(destPath + "/" + fileName));
        return fileName;
    }

    /**
     * 当文件夹不存在时,mkdirs会自动创建多层目录,区别于mkdir.
     * (mkdir如果父目录不存在则会抛出异常)
     *
     * @param destPath 存放目录
     */
    public static void mkdirs(String destPath) {
        File file = new File(destPath);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        }
    }

    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content  内容
     * @param logoPath LOGO地址
     * @param destPath 存储地址
     * @throws Exception
     */
    public static String encode(String content, String logoPath, String destPath) throws Exception {
        return QrCodeUtils.encode(content, logoPath, destPath, false);
    }

    /**
     * 生成二维码
     *
     * @param content      内容
     * @param destPath     存储地址
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static String encode(String content, String destPath, boolean needCompress) throws Exception {
        return QrCodeUtils.encode(content, null, destPath, needCompress);
    }

    /**
     * 生成二维码
     *
     * @param content  内容
     * @param destPath 存储地址
     * @throws Exception
     */
    public static String encode(String content, String destPath) throws Exception {
        return QrCodeUtils.encode(content, null, destPath, false);
    }

    /**
     * 生成二维码(内嵌LOGO)
     *
     * @param content      内容
     * @param logoPath     LOGO地址
     * @param output       输出流
     * @param needCompress 是否压缩LOGO
     * @throws Exception
     */
    public static void encode(String content, String logoPath, OutputStream output, boolean needCompress)
            throws Exception {
        BufferedImage image = QrCodeUtils.createImage(content, logoPath, needCompress);
        ImageIO.write(image, FORMAT, output);
    }

    /**
     * 生成二维码
     *
     * @param content 内容
     * @param output  输出流
     * @throws Exception
     */
    public static void encode(String content, OutputStream output) throws Exception {
        QrCodeUtils.encode(content, null, output, false);
    }

}

(3)调用工具类生产二维码(根据各自业务生成对应的二维码,其中二维码路径可用redis缓存并设置过期时间减少二维码频繁生成,过期可重新生成)


第三步:在微信和支付宝开发文档下载对应的SDK  DEMO

(1)微信支付宝引入依赖

<!-- 支付宝SDK -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.9.5.ALL</version>
        </dependency>
        
        <!-- 微信支付SDK -->
        <dependency>
            <groupId>com.github.wxpay</groupId>
            <artifactId>wxpay-sdk</artifactId>
            <version>0.0.3</version>
        </dependency>
      
        <!-- XML转bean对象 -->
        <dependency>
            <groupId>com.thoughtworks.xstream</groupId>
            <artifactId>xstream</artifactId>
            <version>1.4.10</version>
        </dependency>

(2)对应的包目录

  

(3)对应的代码:链接


第四步:扫描进入二维码对应的URL

(1)控制层处理

   /**
     * 扫描二维码进入控制器处理具体业务逻辑
     */

  @GetMapping(value = "****")
    public String payh5(@PathVariable String ***) throws Exception{
        String userAgent = request.getHeader("user-agent");
        if (userAgent == null
                || !(userAgent.contains("AlipayClient") || userAgent
                        .contains("MicroMessenger"))) {
            log.info("未知来源扫码进入付费模块,返回无页面...");
            return "****";
        }       
        if (userAgent.contains("AlipayClient")) {   //支付宝
            Map<String, Object> pay = vipChargeService.findParamForPay(***);//对应需要的参数
            request.setAttribute("info", pay.get("info")); //前端H5页面需要的参数
            request.setAttribute("payParam", pay.get("payParam"));//支付宝支付需要的参数
            return "school/vip/alipay_h5";
        }else{
            Map<String, Object> pay = vipChargeService.findParamForPay(****);//对应需要的参数
            request.setAttribute("appId", pay.get("appId"));//APPID - 公众号APPID
            request.setAttribute("url", pay.get("url")); //微信静默授权成功后  跳转到微信支付页面的URL
            request.setAttribute("state", pay.get("state"));//微信附加参数
            return "**/wx_auth"; //微信授权页面
        }
    }

 /**
     * 跳转到微信支付页 ,该处为微信授权成功后回调路径
     * @param state     微信返回附加参数
     * @param code      授权code
     * @return
     */
    @GetMapping(value = "/wxpayh5/")
    public String getWxpayParam(String state ,String code){
        if (StringUtils.isEmpty(state) || StringUtils.isEmpty(code)) {
            return "***/expire_h5";//过期页面
        }
        try {          
            vipChargeService.findWxPayMwebUrl(request,***, code);
            return "***/wxpay_h5";//支付页面
        } catch (Exception e) {
            log.error("微信获取支付参数出错,错误信息:", e.getMessage(), e);
            e.printStackTrace();
        }
        return "***/expire_h5";//过期页面
    }

(2)业务层处理vipChargeService

  @Override
    public Map<String, Object> findParamForPay(***,  int payType) throws Exception {     
        long time = redisGetService.getOrderExpireTime(***); //获取剩余过期时间单位秒
        Date expireTime = new Date(new Date().getTime() + 1000 * time);//获取过期的具体时间
        String backParams = ****;//附加参数       
        Map<String, Object> result = new HashMap<String, Object>();       
        if (payType == 1) {   //微信
            WXPayConfig config = new WxpayConfig();
            result.put("appId", config.getAppID());
            result.put("url", ****);
            result.put("state", backParams);
        }else {  //支付宝
            String payParam = AlipayUtil.getPayParam(****);
            payParam = payParam.replace("<script>document.forms[0].submit();</script>", "");
            result.put("payParam", payParam);      

    
            Map<String, Object> info = new HashMap<String, Object>();
            //TODO   添加页面需要的参数
            result.put("info", info);
        }
        return result;
    }

  @Override
    public void findWxPayMwebUrl(HttpServletRequest request, ***, String code)
            throws Exception {
        String openid = WxSignUtil.accessWithOpenid(code);//获取微信用户openid

       //TODO 获取相关的参数
        long time = redisGetService.getOrderExpireTime(***);
        Date expireTime = new Date(new Date().getTime() + 1000 * time);
        
        String ip = *****;//获取客户端IP地址 -> 自己百度
        String notify_url = UrlConstants.VIP_NOTIFY_URL;
        String attach = "****";//附带参数
        Map<String, Object> result = WxPayUtil.getH5PayParam(***, openid);
        if (result == null) {
            throw new Exception("获取微信订单参数失败");
        }
        Map<String, Object> info = new HashMap<String, Object>();
        //TODO 返回至支付页面需要的参数
        request.setAttribute("info", info);
        request.setAttribute("result", result);
    }

(3)微信的授权页面、微信的支付页面、支付宝的支付页面:链接


第五步:异步通知

(1)支付宝异步通知/同步通知

package com.meal.module.school.api;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.alipay.api.internal.util.AlipaySignature;
import com.meal.constant.UrlRoot;
import com.meal.module.admin.order.service.PcOrderService;
import com.meal.pay.alipay.config.AlipayConfig;

/**
 * 文件名:AlipayController.java
 * @author lcwen
 * @version $Id: AlipayController.java 2020年3月11日 上午11:34:45 $
 */
@Controller
@RequestMapping(value = UrlRoot.ALIPAY_NOTIFY_URL)
public class AlipayController {
    
    private static final Logger log = LoggerFactory.getLogger(AlipayController.class);
    
    @Autowired
    private HttpServletRequest request;
    
    @RequestMapping(value = "/notify_url")
    public void notify_url(){
        try {
            boolean signVerified = signVerify(request);
            if (!signVerified) {// 是否验证不成功
                log.error("支付宝异步通知验证签名失败");
                return;
            }    
            
            String trade_status = new String(request.getParameter(
                    "trade_status").getBytes("ISO-8859-1"), "UTF-8");
            if (!trade_status.equals("TRADE_FINISHED") && !trade_status.equals("TRADE_SUCCESS")) {
                log.info("支付宝异步通知回调结果:失败");
                return;
            }
            
            String out_trade_no = request.getParameter("out_trade_no");
            String trade_no = request.getParameter("trade_no");
            //TODO处理订单      
            //**********************
        } catch (Exception e) {
            log.error("支付宝异步通知出错,错误信息:",e.getMessage(),e);
            e.printStackTrace();
        }
    }
    
    /**
     * 简要说明:同步路径 <br>
     * 创建者:lcwen
     * 创建时间:2020年3月12日 下午5:47:17
     * @return
     */
    @RequestMapping(value = "/return_url")
    public String return_url(){
        try {
            boolean signVerified = signVerify(request);
            if (!signVerified) {
                request.setAttribute("msg", "支付失败,签名验证错误!");
                return "******"; //支付失败页面
            }           
            return "*****";//支付成功页面       
        } catch (Exception e) {
            request.setAttribute("msg", "支付失败,同步通知出错!");
            log.error("支付宝同步通知出错,错误信息:",e.getMessage(),e);
            e.printStackTrace();
        }
        return "*****";    //支付失败页面   
    }
    
    /**
     * 简要说明:支付宝签名验证 <br>
     *************************页面功能说明*************************
     * 创建该页面文件时,请留心该页面文件中无任何HTML代码及空格。
     * 该页面不能在本机电脑测试,请到服务器上做测试。请确保外部可以访问该页面。
     * 如果没有收到该页面返回的 success
     * 建议该页面只做支付成功的业务逻辑处理,退款的处理请以调用退款查询接口的结果为准。
     * 创建者:lcwen
     * 创建时间:2020年3月12日 下午5:00:28
     * @param request
     * @return
     * @throws Exception
     */
    private boolean signVerify(HttpServletRequest request) throws Exception{
        boolean signVerified = false;
        // 获取支付宝POST过来反馈信息
        Map<String, String> params = new HashMap<String, String>();
        Map<String, String[]> requestParams = request.getParameterMap();
        for (Iterator<String> iter = requestParams.keySet().iterator(); iter
                .hasNext();) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            // 乱码解决,这段代码在出现乱码时使用
            valueStr = new String(valueStr.getBytes("utf-8"), "utf-8");
            params.put(name, valueStr);
        }
        signVerified = AlipaySignature.rsaCheckV1(params,
                AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET,
                AlipayConfig.SIGNTYPE); // 调用SDK验证签名
        return signVerified;
    }

}

(2)微信异步通知

package com.meal.module.school.api;

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.math.BigDecimal;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.github.wxpay.sdk.WXPayConfig;
import com.github.wxpay.sdk.WXPayUtil;
import com.meal.constant.UrlRoot;
import com.meal.module.admin.order.service.PcOrderService;
import com.meal.pay.wxpay.config.WxpayConfig;
import com.meal.pay.wxpay.pojo.NotifyInfo;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.XmlFriendlyNameCoder;
import com.thoughtworks.xstream.io.xml.XppDriver;

/**
 * 文件名:WxpayController.java
 * @author lcwen
 * @version $Id: WxpayController.java 2020年3月11日 上午11:35:02 $
 */
@Controller
@RequestMapping(value = ****)
public class WxpayController {
    
    private static final Logger log = LoggerFactory.getLogger(WxpayController.class);
    
    @Autowired
    private HttpServletRequest request;
    
    @Autowired
    private HttpServletResponse response;
    
    /**
     * 简要说明:异步通知 <br>
     * 详细说明:TODO
     * 创建者:lcwen
     * 创建时间:2020年3月13日 上午10:39:26
     * 更新者:
     * 更新时间:
     */
    @RequestMapping(value = "/notify_url")
    public void notify_url() throws Exception{
        String notityXml = "";
        String inputLine = "";
        while ((inputLine = request.getReader().readLine()) != null) {
            notityXml += inputLine;
        }
        request.getReader().close();
        
        WXPayConfig config = new WxpayConfig();
        XStream xs = new XStream(new XppDriver(new XmlFriendlyNameCoder("_-",
                "_")));
        xs.alias("xml", NotifyInfo.class);
        NotifyInfo ntfInfo = (NotifyInfo)xs.fromXML(notityXml.toString());
        
        // 验证签名是否正确
        boolean isSign = WXPayUtil.isSignatureValid(notityXml, config.getKey());
        if(!isSign){
            signFail(response);
            return;
        }
        if (!"SUCCESS".equals(ntfInfo.getReturn_code())
                || !"SUCCESS".equals(ntfInfo.getResult_code())) {
            payFail(response,ntfInfo.getErr_code());
            return;
        }
        
        //订单号、微信交易号、
        String out_trade_no = ntfInfo.getOut_trade_no();
        String trade_no = ntfInfo.getTransaction_id();
        
        //TODO 订单处理
        //**************************
        payOk(response);
    }
    
    /**
     * 支付成功
     */
    private static void payOk(HttpServletResponse response){
        log.info("================  微信支付异步回调支付成功返回  =================");
        String resXml = "<xml><return_code><![CDATA[SUCCESS]]></return_code>"
                + "<return_msg><![CDATA[OK]]></return_msg></xml> ";
        flushResponse(response, resXml);
    }
    
    
    /**
     * 支付失败
     */
    private static void payFail(HttpServletResponse response ,String errCode){
        log.info("================  微信支付异步回调支付失败返回  =================");
        String resXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"
                + "<return_msg><![CDATA[" + errCode + "]]></return_msg></xml>";
        flushResponse(response, resXml);
    }
    
    /**
     * 签名失败
     */
    private static void signFail(HttpServletResponse response){
        log.info("================  微信支付异步回调签名失败  =================");
        String resXml = "<xml><return_code><![CDATA[FAIL]]></return_code>"  
                + "<return_msg><![CDATA[签名有误]]></return_msg></xml> ";
        flushResponse(response, resXml);
    }
    
    private static void flushResponse(HttpServletResponse response ,String resXml){
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(response.getOutputStream());      
            out.write(resXml.getBytes("utf-8"));
            out.flush();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}


第六部:效果(实际项目)

                                                    

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_37162179/article/details/104938548

智能推荐

Activity跳转到 TabActivity的子页面_Fans_Mo的博客-程序员宅基地

。。。。。。随手记下,这个东西用到的并不是太多还用上次写的TabActivity那个demo来说吧点击打开链接在TabActivity 中的oncreate() 中添加 广播,代码如下://注册广播 IntentFilter filter = new IntentFilter(); filter.addAction("com.ex

c语言将0.0001转换成double型,C语言 日期型转double型_恒银信金融的博客-程序员宅基地

在C语言中没有直接将日期转换为double型的函数,但是在将日期类型保存到文件时往往需要日期的转换。/* ************************************************************************************************************* conversion between double type and da...

【Numpy】学习笔记1___盛夏光年__的博客-程序员宅基地

文章目录一、概述二、基础1、创建数组(1)通过 list 创建数组(2)特殊数组2、数组运算(1)基础运算(一维)(2)基础运算(二维)3、数学函数4、数组切片和索引5、数组形状操作(1)形变(2)数组的拼合6、数组排序7、数组统计三、进阶1、创建数组55https://www.shiyanlou.com/courses/running一、概述numpy 支持大量高维度数组与矩阵运算,此外也针...

js实现本地文件的加载与读取_超频化石鱼的博客-程序员宅基地_js加载本地文件

加载本地文件要加载本地文件,需要使用&lt;input&gt;标签:&lt;input type="file" id="file" multiple&gt;如上:type: 必须为file。multiple: 用于同时加载多个文件。这样就会生成一个选择文件按钮,其右侧显示未选择任何文件。点击选择文件,即可弹出一个文件选择窗口。同时该元素还接收拖放,拖动多个文件到选择文件即可...

gradle修改AndroidManifest.xml中的meta-data元素值_Cookie-kimi的博客-程序员宅基地

Jenkins+gradle自动打包 场景:想用gradle修改AndroidManifest.xml中的meta-data元素值 JPUSH_APPKEY的value想替换成88888888AndroidManifest.xml:<meta-data android:name="JPUSH_APPKEY" android:value="${JPU

SMS4(中国商用加密算法)_wuyingzhiyi的博客-程序员宅基地

/*******************************************************************************密码学实验-----SMS4算法演示 Wuhan University   Computer School   HonYi YanChao    *****************

随便推点

王道考研 计算机网络笔记 第五章:传输层_Baret-H的博客-程序员宅基地

本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络个人笔记总结第一章:王道考研 计算机网络笔记 第一章:概述&amp;计算机网络体系结构第二章:王道考研 计算机网络笔记 第二章:物理层第三章:王道考研 计算机网络笔记 第三章:数据链路层第四章:王道考研 计算机网络笔记 第四章:网络层后续章节将陆续更新…第三章一、传输层概述1. 功能2. 传输层两个协议3. 传输层的寻址与端口二、UDP协议1. 概述2. UDP首部格式3. UDP校验三、TCP协议1. 特点2. TC.

【目录】计算几何_ZhgDgE的博客-程序员宅基地

Acwing 算法进阶课1.1 二维计算几何基础1.2 二维凸包1.3 半平面交1.4 最小圆覆盖1.5 三维计算几何基础1.6 三维凸包1.7 旋转卡壳1.8 三角剖分1.9 扫描线1.10 自适应辛普森积分OI-Wiki2.1 距离2.2 Pick 定理2.3 欧拉公式2.4 最优三角剖分2.5 平面最近点对2.6 反演变换杂知识点3.1 圆的一些定理...

Java NIO学习教程(六)_stepMoreForever的博客-程序员宅基地

原文地址: link.12.Java NIO DatagramChannelJava NIO DatagramChannel是可以发送和接收UDP数据包的通道。由于UDP是一种无连接的网络协议,因此你不能像从其他通道读写数据报通道一样,在默认情况下读写数据报通道。相反,您发送和接收数据包。Opening a DatagramChannel以下是打开DatagramChannel方法:Da...

python学习笔记_day0_外壳_Don't back的博客-程序员宅基地

python用缩进来区分代码段。目的:了解python中的代码结构,[判断if, 循环while, 迭代(for, zip)],4种推导式,3种参数,*,**收集参数(收集位置参数,关键字参数),生成器,装饰器,闭包,异常等概念。

【Java 8】FutureTask、CompletableFuture实践案例_Lambo Chen的博客-程序员宅基地

文章目录1. 前言2. demo 代码2.1. 定义耗时操作2.2. 同步代码2.2.1. 运行日志2.3. 同步代码另一种写法2.3.1. 运行日志3. FutureTask版本3.1. 异步分析3.2. FutureTask 版本3.2.1. 日志分析3.2.2. 异步分析4. CompletableFuture4.1. 日志分析4.2. FutureTask VS CompletableFu...

PowerDesigner使用手册1--下载安装篇_lby0608的博客-程序员宅基地

PowerDesigner简述    Power Designer 是Sybase公司的CASE工具集,使用它可以方便地对管理信息系统进行分析设计,他几乎包括了数据库模型设计的全过程。利用Power Designer可以制作数据流程图、概念数据模型、物理数据模型,还可以为数据仓库制作结构模型,也能对团队设计模型进行控制。他可以与许多流行的软件开发工具,例如PowerBuilder、Delphi、V...

推荐文章

热门文章

相关标签