Java 对接百度网盘

news2024/9/20 6:28:01

文章目录

  • 前言
  • 一、创建百度网盘账号
  • 二、代码实现
    • 1. 常量类
    • 2. 工具类
    • 3. 授权码模式授权
    • 4. 文件分片上传(可获取进度)--方法一
    • 5. 文件下载(可获取进度)--方法一
    • 6. 获取文件列表
    • 7. 文件分片上传(不可获取进度)--方法二
    • 7. 文件下载(不可获取进度)--方法二


前言

百度网盘官方文档中的介绍的很清楚明了,在此不做赘述,直接上代码!!!

提示:以下是案例是基于企业认证的账号

一、创建百度网盘账号

百度网盘官方文档

  1. 进行百度帐号的实名认证;
  2. 认证成功后,创建应用; 在【控制台】中点击「+创建应用」创建一个应用
  3. 完成应用创建后,你的应用可以获取到关键凭证:Appid、Appkey、Secretkeyk和Signkey。
    在这里插入图片描述
  4. 设置授权的回调地址,如果不设置回调地址那么使用默认的回调地址oob 【应用详情】页,右上角【安全设置】,设置授权回调地址
  • 授权回调地址支持配置多个,多个地址之间,通过英文逗号进行分隔。
  • 授权回调地址修改后在 1 小时后生效。
  • 授权回调地址中如果包含特殊符号,请求接口时,回调地址需要进行url编码。

二、代码实现

1. 常量类

package boot.test.constant;


/**
 * 百度网盘常量信息
 */
public interface BaiduNetDiskConstant {
    /**
     * 百度网盘 秘钥字段
     */
    String APPKEY = "AppKey";
    String SECRETKEY = "SecretKey";
    String ACCESSTOKEN = "AccessToken";
    /**
     * 文件上传到百度网盘的路径地址
     * - 每个第三方应用在网盘只能拥有一个文件夹用于存储上传文件,该文件夹必须位于/apps目录下,apps下的文件夹名称为申请接入时填写的申请接入的产品名称。
     * - 如申请接入的产品名称为云存储,那么该文件夹为/apps/云存储,用户看到的文件夹为/我的应用数据/云存储。
     */
    String BAIDUNETDISK_APP_PATH = "/apps/XXX/";
    /**
     * 分片上传 单片大小 单位:MB
     * - 上传的文件大于4MB,需要将上传的文件按照4MB大小在本地切分成分片,不足4MB的分片自动成为最后一个分片
     */
    Integer BAIDUNETDISK_SLICE_SIZE = 4;
    /**
     * 百度网盘 回调地址 URL
     */
    String BAIDUNETDISK_CALLBACK_URL = "https://internal.beausoft.cn";
    /**
     * 百度网盘用户授权码的 URL
     */
    String BAIDUNETDISK_ACCREDITCODE_URL = "https://openapi.baidu.com/oauth/2.0/authorize?";
    /**
     * 1. 获取 Access Token的 URL
     * 2. 刷新Access Token的 URL
     */
    String BAIDUNETDISK_ACCESSTOKEN_URL = "https://openapi.baidu.com/oauth/2.0/token?";
    /**
     * 百度网盘用户信息 URL
     */
    String BAIDUNETDISK_USERINFO_URL = "https://pan.baidu.com/rest/2.0/xpan/nas?";
    /**
     * 百度网盘容量信息 URL
     */
    String BAIDUNETDISK_QUOTA_URL = "https://pan.baidu.com/api/quota?";
    /**
     * 1. 百度网盘 文件 列表 URL
     * 2. 百度网盘 文档 列表 URL
     */
    String BAIDUNETDISK_FILE_LIST_URL = "https://pan.baidu.com/rest/2.0/xpan/file?";
    /**
     * 分片上传 - 预上传 URL
     */
    String BAIDUNETDISK_PREUPLOAD_URL = "https://pan.baidu.com/rest/2.0/xpan/file?";
    /**
     * 分片上传 - 分片上传 URL
     */
    String BAIDUNETDISK_FILE_UPLOAD_URL = "https://d.pcs.baidu.com/rest/2.0/pcs/superfile2?";
    /**
     * 分片上传 - 合并文件 URL
     */
    String BAIDUNETDISK_MERGE_FILE_URL = "https://pan.baidu.com/rest/2.0/xpan/file?";
    /**
     * 单步上传 URL
     */
    String BAIDUNETDISK_SINGLE_UPLOAD_URL = "https://d.pcs.baidu.com/rest/2.0/pcs/file?";
    /**
     * 百度网盘 查询文件信息 URL
     */
    String BAIDUNETDISK_MULTIMEDIA_URL = "http://pan.baidu.com/rest/2.0/xpan/multimedia?";
    /**
     * 百度网盘 创建文件夹 URL
     */
    String BAIDUNETDISK_CREATE_FOLDER_URL = "https://pan.baidu.com/rest/2.0/xpan/file?";
}

2. 工具类

package boot.test.utils;

import java.net.URLEncoder;

public class BaiduNetDiskUtil {
    /**
     * 对中文字符进行URL编码
     *
     * @param encodeStr
     * @return
     */
    public static String urlEncoder(String encodeStr) {
        try {
            String encodedString = URLEncoder.encode(encodeStr, "UTF-8");
            return encodedString;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 字节转GB
     *
     * @param len
     * @return
     */
    public static String byteConvertToGib(Long len) {
        if (len == null || len <= 0) {
            return "0GB";
        }
        try {
            double val = len.doubleValue() / (1024 * 1024 * 1024);
            return val < 0.1 ? "0.1GB" : String.format("%.1f", val) + "GB";
        } catch (Exception e) {
            e.printStackTrace();
            return "0GB";
        }
    }
}

MD5工具类

package boot.test.utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;


@Slf4j
public class BigFileMD5Util {

    private static MessageDigest MD5 = null;

    static {
        try {
            MD5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException ne) {
            log.error("init md5 utils failed", ne);
        }
    }

    public static String getMD5(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[8192];   // each read bytes to buff
        int length;
        while ((length = inputStream.read(buffer)) != -1) {
            MD5.update(buffer, 0, length);
        }
        return new String(Hex.encodeHex(MD5.digest()));
    }


    /**
     * 对一个文件获取md5值
     *
     * @return md5串
     */
    public static String getMD5(File file) throws IOException {
        try (FileInputStream fileInputStream = new FileInputStream(file)) {
            return getMD5(fileInputStream);
        } catch (IOException e) {
            throw e;
        }
    }


    /**
     * 求一个字符串的md5值
     *
     * @param target 字符串
     * @return md5 value
     */
    public static String getStringMD5(String target) {
        return DigestUtils.md5Hex(target);
    }
}
package boot.test.baidu;

import java.io.*;

public class RandomAccessFileInputStream extends InputStream {

    private final RandomAccessFile raf;
    private final long offset;
    private final int size;

    private volatile int pos;

    public RandomAccessFileInputStream(RandomAccessFile raf, long offset, int size) {
        this.raf = raf;
        this.offset = offset;
        this.size = size;
    }

    @Override
    public int read() throws IOException {
        synchronized (raf) {
            raf.seek(offset + pos);
            pos += 1;
            return raf.read();
        }
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        synchronized (raf) {
            raf.seek(offset + pos);
            if (offset + pos >= offset + size) {
                return -1;
            } else if (offset + pos + len - off >= offset + size) {
                byte[] buff = new byte[(int) ((offset + size) - (offset + pos))];
                int r = raf.read(buff, 0, buff.length);
                System.arraycopy(buff, 0, b, off, buff.length);
                pos += r;
                return r;
            } else {
                int r = raf.read(b, off, len);
                pos += r;
                return r;
            }
        }
    }
}

3. 授权码模式授权

package boot.test.baidu;

import boot.test.constant.BaiduNetDiskConstant;
import boot.test.dto.BaiduNetDiskAccessToken;
import boot.test.utils.BaiduNetDiskUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;

/**
 * 百度网盘 授权
 * - 授权码模式:授权码模式适用于有 Server 端的应用。
 */
@Slf4j
@Component
public class BaiduNetDiskAccredit {

    /**
     * 获取百度用户授权码的url
     *
     * @param appKey
     * @return
     */
    public static String userAccreditCodeUrl(String appKey) {
        String url = BaiduNetDiskConstant.BAIDUNETDISK_ACCREDITCODE_URL +
                "&response_type=code" +    // 固定值,值必须为code。表示为授权码模式。
                "&client_id=" + appKey +// 应用的AppKey
                "&redirect_uri=" + BaiduNetDiskUtil.urlEncoder(BaiduNetDiskConstant.BAIDUNETDISK_CALLBACK_URL) +   // 应用的授权回调地址
                "&scope=basic,netdisk";// 固定值,值必须为basic,netdisk。
//                "&device_id=APPID"; // 应用的AppID, device_id为硬件应用下的必选参数
//                "&qrcode=1" //让用户通过扫二维码的方式登录百度账号时,可传递 “qrcode=1”
        log.info("百度用户授权码 url:{} " + url);
        return url;
    }

    /**
     * 根据用户授权码 Code 换取 Access Token 凭证
     * - Access Token 有效期30天,过期后支持刷新
     *
     * @param code      用户授权后拿到的code, 获取到的授权码 code 有效期 10 分钟,且仅一次有效。
     * @param appKey    应用的AppKey。
     * @param secretKey 应用的SecretKey
     * @return
     */
    public static BaiduNetDiskAccessToken getAccessToken(String code, String appKey, String secretKey) {
        BufferedReader in = null;
        BaiduNetDiskAccessToken accessTokenDto = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_ACCESSTOKEN_URL +
                    "grant_type=authorization_code" + // 固定值,值必须为authorization_code。
                    "&code=" + code + // 获取用户授权后拿到的code。注意code 作为换取Access Token的票据,每次用户授权带上的 code 将不一样,code 只能使用一次,10分钟未被使用自动过期。
                    "&client_id=" + appKey + //应用的AppKey。
                    "&client_secret=" + secretKey + // 应用的SecretKey。
                    "&redirect_uri=" + URLEncoder.encode(BaiduNetDiskConstant.BAIDUNETDISK_CALLBACK_URL, "UTF-8") //授权回调地址。注意必须与获取授权code传递的保持一致。
            );
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("获取Access Token响应结果:{} " + response.toString());
            accessTokenDto = JSON.parseObject(response.toString(), BaiduNetDiskAccessToken.class);
            return accessTokenDto;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取百度 Access Token 凭证失败");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 刷新Access Token
     * - 授权码模式下,刷新后Access Token 的有效期仍为 30 天
     * - 刷新请求,如果API返回失败,旧的refresh_token会失效,此时需要重新发起授权请求,获取新的 Access Token、refresh_token,而不是使用旧的 refresh_token 循环再发起刷新请求。
     *
     * @param refreshToken refresh_token 只支持使用一次,refresh_token 使用后失效,下次刷新 Access Token 时需要使用上一次刷新请求响应中的 refresh_token
     * @param appKey       应用的AppKey。
     * @param secretKey    应用的SecretKey
     * @return
     */
    public BaiduNetDiskAccessToken refreshAccessToken(String refreshToken, String appKey, String secretKey) {
        BufferedReader in = null;
        BaiduNetDiskAccessToken accessTokenDto = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_ACCESSTOKEN_URL +
                    "grant_type=refresh_token" + //固定值,值必须为 refresh_token。
                    "&refresh_token=" + refreshToken +//固定值,值必须为换取 Access Token时候返回的 refresh_token 值。
                    "&client_id=" + appKey + //应用的AppKey
                    "&client_secret=" + secretKey //应用的SecretKey
            );
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("刷新Access Token响应结果:{} " + response.toString());
            accessTokenDto = JSON.parseObject(response.toString(), BaiduNetDiskAccessToken.class);
            return accessTokenDto;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("刷新百度 Access Token 凭证失败");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }
            }
        }
        return null;
    }

}

package boot.test.dto;

import lombok.Data;


/**
 * 百度网盘请求响应
 */
@Data
public class BaiduRespondBase {
    /**
     * 错误信息
     */
    private String errmsg;
    /**
     * 错误码
     */
    private Integer errno;

    /**
     * 发起请求的请求 Id
     */
    private String requestId;
}

package boot.test.dto;

import lombok.Data;

/**
 * 百度网盘 Access Token
 */
@Data
public class BaiduNetDiskAccessToken {
    /**
     * 获取到的Access Token,Access Token是调用网盘开放API访问用户授权资源的凭证。
     * Access Token 有效期30天
     */
    private String accessToken;
    /**
     * Access Token的有效期,单位为秒。
     */
    private Integer expiresIn;
    /**
     * 用于刷新 Access Token, 有效期为10年。
     */
    private String refreshToken;
    /**
     * Access Token 最终的访问权限,即用户的实际授权列表。
     */
    private String scope;
}

测试


    public static void main(String[] args) {
        String AppKey = BaiduNetDiskConstant.APPKEY;
        String SecretKey = BaiduNetDiskConstant.SECRETKEY;
        String accessToken = BaiduNetDiskConstant.ACCESSTOKEN;
        /**
         * 获取用户授权码URL
         */
        String s = BaiduNetDiskAccredit.userAccreditCodeUrl(AppKey);
        System.out.println(s);

        /**
         * 获取 accessToken
         * "9683f31834108e1bcd1821ef7d4c30a5" 👆👆👆👆👆👆👆👆👆来源于用户授权码的 code 👆👆👆👆👆👆👆👆👆👆👆👆
         */
        BaiduNetDiskAccessToken accessToken1 = BaiduNetDiskAccredit.getAccessToken("9683f31834108e1bcd1821ef7d4c30a5", AppKey, SecretKey);
        System.out.println(accessToken1.getAccessToken());
	}

4. 文件分片上传(可获取进度)–方法一

package boot.test.baidu;

import boot.test.constant.BaiduNetDiskConstant;
import boot.test.dto.BaiduNetDiskMergeFile;
import boot.test.dto.BaiduNetDiskPrecreate;
import boot.test.utils.BaiduNetDiskUtil;
import boot.test.vo.BaiduUploadFileVo;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.http.Header;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;


/**
 * 百度网盘文件上传类
 */
@Slf4j
public class BaiduNetDiskUpload {

    /**
     * 分片上传
     * -预上传
     *
     * @param accessToken
     * @param baiduUploadFileVo
     * @return
     */
    public static BaiduNetDiskPrecreate precreate(String accessToken, BaiduUploadFileVo baiduUploadFileVo) {
        BaiduNetDiskPrecreate precreateDto = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_PREUPLOAD_URL +
                    "method=precreate" + // 本接口固定为precreate
                    "&access_token=" + accessToken  //接口鉴权认证参数,标识用户
            );
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setRequestMethod("POST");
            httpConn.setRequestProperty("User-Agent", "pan.baidu.com");
            httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            httpConn.setDoOutput(true);

            OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
            writer.write("path=" + BaiduNetDiskUtil.urlEncoder(baiduUploadFileVo.getPath()) + //上传后使用的文件绝对路径,需要urlencode
                    "&size=" + baiduUploadFileVo.getSize() + //文件和目录两种情况:上传文件时,表示文件的大小,单位B;上传目录时,表示目录的大小,目录的话大小默认为0
                    "&isdir=" + baiduUploadFileVo.getIsdir() + //是否为目录,0 文件,1 目录
                    "&block_list=[\"" + baiduUploadFileVo.getBlockList() + "\"]" + //文件各分片MD5数组的json串
                    "&autoinit=1" + //固定值1
                    "&rtype=3" //文件命名策略。1 表示当path冲突时,进行重命名 2 表示当path冲突且block_list不同时,进行重命名 3 当云端存在同名文件时,对该文件进行覆盖
            );
            writer.flush();
            writer.close();
            httpConn.getOutputStream().close();

            BufferedReader in = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("预上传响应结果:{} " + response.toString());
            precreateDto = JSON.parseObject(response.toString(), BaiduNetDiskPrecreate.class);
            if (precreateDto == null || precreateDto.getErrno() != 0) {
                System.out.println("预上传文件失败");
            }
            return precreateDto;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("预上传文件失败");
        }
        return null;
    }

    /**
     * 分片上传
     * -分片文件
     *
     * @param accessToken
     * @param uploadid    上一个阶段预上传precreate接口下发的uploadid
     * @param path        上传后使用的文件绝对路径
     * @param file        分片索引
     * @return
     */
    public static boolean shardUpload(String accessToken, String uploadid, String path, File file) {
        try {
            RandomAccessFile raf = new RandomAccessFile(file, "r");
            long fileSize = file.length();
            long splitSize = BaiduNetDiskConstant.BAIDUNETDISK_SLICE_SIZE * 1024 * 1024;//单片文件大小
            int count = (int) (fileSize % splitSize != 0 ? fileSize / splitSize + 1 : fileSize / splitSize);
            AtomicLong size = new AtomicLong();
            for (int i = 0; i < count; i++) {
                String url = BaiduNetDiskConstant.BAIDUNETDISK_FILE_UPLOAD_URL +
                        "method=upload" + //本接口固定为upload
                        "&access_token=" + accessToken +
                        "&type=tmpfile" + //固定值 tmpfile
                        "&path=" + BaiduNetDiskUtil.urlEncoder(path) +//上传后使用的文件绝对路径,需要urlencode,需要与上一个阶段预上传precreate接口中的path保持一致
                        "&uploadid=" + uploadid +//上一个阶段预上传precreate接口下发的uploadid
                        "&partseq=" + i; //文件分片的位置序号,从0开始,参考上一个阶段预上传precreate接口返回的block_list

                int iTmp = i;

                AtomicLong inc = new AtomicLong();
                RandomAccessFileInputStream stream = new RandomAccessFileInputStream(raf, (int) (i * splitSize), (int) splitSize);

                Map<String, Object> map = new HashMap<>();
                map.put("file", new Resource() {
                    @Override
                    public String getName() {
                        return "ly_" + iTmp;
                    }

                    @Override
                    public URL getUrl() {
                        return null;
                    }

                    @Override
                    public InputStream getStream() {
                        return new InputStream() {
                            @Override
                            public int read() throws IOException {
                                int ret = stream.read();
                                size.addAndGet(1);
                                inc.addAndGet(1);
                                return ret;
                            }

                            @Override
                            public int read(byte[] b, int off, int len) throws IOException {
                                int ret = stream.read(b, off, len);
                                size.addAndGet(ret);
                                inc.addAndGet(ret);
                                return ret;
                            }
                        };
                    }
                });

                Thread t = new Thread(() -> {
                    while (!Thread.interrupted()) {
                        try {
                            System.out.println("当前传输的大小为:" + size.get() + ",每秒传输大小:" + inc.getAndSet(0));
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
//                        e.printStackTrace();
                            break;
                        }
                    }
                    System.out.println("读取大小线程结束");
                });
                t.start();
                /**
                 * 进行文件上传
                 */
                HttpUtil.post(url, map);
                t.interrupt();
                t.join();
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件分片上传失败");
        }
        return false;
    }

    /**
     * 分片上传
     * -合并文件
     *
     * @param accessToken
     * @param uploadid          预上传precreate接口下发的uploadid
     * @param baiduUploadFileVo
     */
    public static BaiduNetDiskMergeFile mergeFile(String accessToken, String uploadid, BaiduUploadFileVo baiduUploadFileVo) {
        BaiduNetDiskMergeFile mergeFileDto = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_MERGE_FILE_URL +
                    "method=create" + //本接口固定为create
                    "&access_token=" + accessToken //接口鉴权认证参数,标识用户
            );
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setRequestMethod("POST");
            httpConn.setRequestProperty("User-Agent", "pan.baidu.com");
            httpConn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            httpConn.setDoOutput(true);

            OutputStreamWriter writer = new OutputStreamWriter(httpConn.getOutputStream());
            writer.write("path=" + BaiduNetDiskUtil.urlEncoder(baiduUploadFileVo.getPath()) + //上传后使用的文件绝对路径,需要urlencode
                    "&size=" + baiduUploadFileVo.getSize() + //文件和目录两种情况:上传文件时,表示文件的大小,单位B;上传目录时,表示目录的大小,目录的话大小默认为0
                    "&isdir=" + baiduUploadFileVo.getIsdir() + //是否为目录,0 文件,1 目录
                    "&block_list=[\"" + baiduUploadFileVo.getBlockList() + "\"]" +//文件各分片MD5数组的json串
                    "&uploadid=" + uploadid + //预上传precreate接口下发的uploadid
                    "&rtype=3" //文件命名策略。1 表示当path冲突时,进行重命名 2 表示当path冲突且block_list不同时,进行重命名 3 当云端存在同名文件时,对该文件进行覆盖
            );
            writer.flush();
            writer.close();
            httpConn.getOutputStream().close();

            int responseCode = httpConn.getResponseCode();
            System.out.println("Response Code : " + responseCode);
            BufferedReader in = new BufferedReader(new InputStreamReader(httpConn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("分片上传-创建文件响应结果:{} " + response.toString());
            mergeFileDto = JSON.parseObject(response.toString(), BaiduNetDiskMergeFile.class);
            if (mergeFileDto == null || mergeFileDto.getErrno() != 0) {
                System.out.println("合并文件失败");
            }
            return mergeFileDto;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("合并文件失败");
        }
        return null;
    }

    /**
     * 获取文件的 md5
     *
     * @param obj
     * @return
     */
    public static BaiduUploadFileVo getFileMd5(Object obj) {
        BaiduUploadFileVo uploadFileVo = new BaiduUploadFileVo();
        try {
            StringBuffer md5s = new StringBuffer();
            File file = null;
            if (obj instanceof String) {
                file = new File((String) obj);
            }
            if (obj instanceof File) {
                file = (File) obj;
            }
            long splitSize = BaiduNetDiskConstant.BAIDUNETDISK_SLICE_SIZE * 1024 * 1024;//单片文件大小
            long fileSize = file.length();
            uploadFileVo.setSize(fileSize);
            /**
             * 文件小于4m 无需切片
             */
            if (fileSize < splitSize) {
                //获取文件的md5
                md5s.append(BigFileMD5Util.getMD5(file));
                uploadFileVo.setBlockList(md5s.toString());
                return uploadFileVo;
            }
            /**
             * 对大于4m的文件进行切片
             */
            RandomAccessFile raf = new RandomAccessFile(file, "r");
            //要切多少片
            int count = (int) (fileSize % splitSize != 0 ? fileSize / splitSize + 1 : fileSize / splitSize);
            for (int i = 0; i < count; i++) {
                RandomAccessFileInputStream randomAccessFileInputStream =
                        new RandomAccessFileInputStream(raf, i * splitSize, (int) splitSize);
                //获取分片文件的md5
                md5s.append(BigFileMD5Util.getMD5(randomAccessFileInputStream) + "\",\"");
            }
            String md5Str = md5s.toString();
            md5s = new StringBuffer(md5Str.substring(0, md5Str.length() - 3));
            uploadFileVo.setBlockList(md5s.toString());
            return uploadFileVo;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件上传失败,获取分片文件MD5失败");
        }
        return null;
    }

    /**
     * 单步上传
     *
     * @param accessToken
     * @param path
     * @param file
     * @return
     */
    public boolean singleUpload(String accessToken, String path, File file) {
        try {
            Map<String, Object> map = new HashMap<>();
            String url = BaiduNetDiskConstant.BAIDUNETDISK_SINGLE_UPLOAD_URL +
                    "method=upload" + //本接口固定为upload
                    "&access_token=" + accessToken + //接口鉴权认证参数,标识用户
                    "&path=" + BaiduNetDiskUtil.urlEncoder(path) + //上传的文件绝对路径
                    "&ondup=newcopy"; //上传的文件绝对路径冲突时的策略。fail(默认:冲突时失败)overwrite(冲突时覆盖) newcopy(冲突时重命名)
            map.put("file", file);
            //上传文件
            HttpUtil.post(url, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件上传失败");
        }
        return false;
    }
}

package boot.test.dto;

import lombok.Data;

import java.util.List;


/**
 * 百度网盘百度网盘分片上传之预上传
 */
@Data
public class BaiduNetDiskPrecreate extends BaiduRespondBase {
    /**
     * 文件的绝对路径
     */
    private String path;
    /**
     * 上传唯一ID标识此上传任务
     */
    private String uploadid;
    /**
     * 系统内部状态字段
     */
    private Integer returnType;
    /**
     * 需要上传的分片序号列表,索引从0开始
     */
    private List blockList;

}

package boot.test.dto;

import lombok.Data;

/**
 * 百度网盘分片上传之合并文件
 */
@Data
public class BaiduNetDiskMergeFile extends BaiduRespondBase {
    /**
     * 文件在云端的唯一标识ID
     */
    private Long fsId;
    /**
     * 文件的MD5,只有提交文件时才返回,提交目录时没有该值
     */
    private String md5;
    /**
     * 文件名
     */
    private String serverFilename;
    /**
     * 分类类型, 1 视频 2 音频 3 图片 4 文档 5 应用 6 其他 7 种子
     */
    private Integer category;
    /**
     * 上传后使用的文件绝对路径
     */
    private String path;
    /**
     * 文件大小,单位B
     */
    private Long size;
    /**
     * 文件创建时间
     */
    private Long ctime;
    /**
     * 文件修改时间
     */
    private Long mtime;
    /**
     * 是否目录,0 文件、1 目录
     */
    private Integer isdir;

    public Long getCtime() {
        if (ctime != null) {
            return ctime * 1000;
        }
        return ctime;
    }

    public Long getMtime() {
        if (mtime != null) {
            return mtime * 1000;
        }
        return mtime;
    }

}

package boot.test.vo;

import lombok.Data;

@Data
public class BaiduUploadFileVo {
    private String path;
    /**
     * 文件和目录两种情况:上传文件时,表示文件的大小,单位B;上传目录时,表示目录的大小,目录的话大小默认为0
     */
    private Long size;
    
    private Integer isdir;
    /**
     * block_list的含义如下,如果上传的文件小于4MB,其md5值(32位小写)即为block_list字符串数组的唯一元素;
     * 如果上传的文件大于4MB,需要将上传的文件按照4MB大小在本地切分成分片,不足4MB的分片自动成为最后一个分片,
     * 所有分片的md5值(32位小写)组成的字符串数组即为block_list
     */
    private String blockList;

}

测试

  public static void main(String[] args) {
        String accessToken = BaiduNetDiskConstant.ACCESSTOKEN;
        String absoluteFilePath = "D:\\BaiduNetdiskDownload\\hhxi.zip";
        /**
         * 文件分片并获取md5值
         */
        BaiduUploadFileVo baiduUploadFileVo = BaiduNetDiskUpload.getFileMd5(absoluteFilePath);
        baiduUploadFileVo.setPath(BaiduNetDiskConstant.BAIDUNETDISK_APP_PATH + "hhxi.zip");
        baiduUploadFileVo.setIsdir(0);
        /**
         * 预上传
         */
        BaiduNetDiskPrecreate precreate = BaiduNetDiskUpload.precreate(accessToken, baiduUploadFileVo);
        File f = new File(absoluteFilePath);
        BaiduNetDiskUpload.shardUpload(accessToken, precreate.getUploadid(), baiduUploadFileVo.getPath(), f);
        /**
         * 创建文件
         */
        BaiduNetDiskMergeFile mergeFileDto = BaiduNetDiskUpload.mergeFile(accessToken, precreate.getUploadid(), baiduUploadFileVo);
        System.out.println(mergeFileDto.toString());
    }

5. 文件下载(可获取进度)–方法一

package boot.test.baidu;

import boot.test.constant.BaiduNetDiskConstant;
import boot.test.dto.BaiduNetDiskMergeFile;
import boot.test.dto.BaiduNetDiskPrecreate;
import boot.test.utils.BaiduNetDiskUtil;
import boot.test.vo.BaiduUploadFileVo;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.http.Header;
import cn.hutool.http.HttpException;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicLong;


/**
 * 百度网盘文件下载类
 */
@Slf4j
public class BaiduNetDiskDownload {
  /**
     * 查询文件信息
     *
     * @param accessToken
     * @param fileIds     文件id数组
     */
    public static List<BaiduNetDiskFileInfo> getFileInfos(String accessToken, Long[] fileIds) {
        BufferedReader in = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_MULTIMEDIA_URL +
                    "method=filemetas" + //本接口固定为filemetas
                    "&access_token=" + accessToken +//接口鉴权参数
                    "&fsids=" + BaiduNetDiskUtil.urlEncoder(Arrays.toString(fileIds)) +//文件id数组,数组中元素是uint64类型,数组大小上限是:100
                    "&thumb=1" +//是否需要缩略图地址,0为否,1为是,默认为0
                    "&dlink=1" +//是否需要下载地址,0为否,1为是,默认为0。获取到dlink后,参考下载文档进行下载操作
                    "&extra=1" +//图片是否需要拍摄时间、原图分辨率等其他信息,0 否、1 是,默认0
                    "&needmedia=1" +//视频是否需要展示时长信息 0 否、1 是,默认0
                    "&detail=1" //频是否需要展示长,宽等信息。0 否、1 是,默认0
            );
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("获取百度网盘文件信息响应结果:{} " + response.toString());
            JSONObject responseJson = JSON.parseObject(response.toString());
            if (responseJson.getInteger("errno") != 0) {
                System.out.println("获取文件信息失败");
            }
            return JSONObject.parseArray(responseJson.getString("list"), BaiduNetDiskFileInfo.class);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取文件信息失败");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 文件下载
     *
     * @param dLink       dlink字段即为文件的下载地址  通过【查询文件信息接口】获取
     * @param accessToken
     * @return
     */
    public static boolean downLoad(String dLink, String fileName, String accessToken) {
        try {
            URL url = new URL(dLink + "&access_token=" + accessToken);
            HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
            httpConn.setRequestMethod("GET");
            httpConn.setRequestProperty("User-Agent", "pan.baidu.com");
            httpConn.setRequestProperty("Host", "d.pcs.baidu.com");

            int responseCode = httpConn.getResponseCode();
            if (responseCode == 302) {
                final long[] downloadedSize = {0};
                String location = httpConn.getHeaderField("Location");
                HttpUtil.downloadFile(location, FileUtil.file("D:\\" + fileName), new StreamProgress() {

                    @Override
                    public void start() {
                        System.out.println("开始下载。。。。");
                    }

                    @Override
                    public void progress(long progressSize) {
//                        FileUtil.readableFileSize(progressSize)   将字节转为M或G
                        System.out.println("当前传输的大小为:" + FileUtil.readableFileSize(progressSize) + ", 每秒传输大小:" + FileUtil.readableFileSize(progressSize - downloadedSize[0]));
                        downloadedSize[0] = progressSize;
                    }

                    @Override
                    public void finish() {
                        System.out.println("下载完成!");
                    }
                });
            }

            log.info("文件下载完成");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("文件下载失败");
        }
        return false;
    }
}

package boot.test.dto;

import lombok.Data;

/**
 * 百度网盘 查询文件信息
 */
@Data
public class BaiduNetDiskFileInfo {
    /**
     * 文件类型,含义如下:1 视频, 2 音乐,3 图片,4 文档,5 应用,6 其他,7 种子
     */
    private Integer category;
    /**
     * 文件下载地址,参考下载文档进行下载操作
     */
    private String dlink;
    /**
     * 文件名
     */
    private String filename;
    /**
     * 是否是目录,为1表示目录,为0表示非目录
     */
    private Integer isdir;
    /**
     * 文件的服务器创建Unix时间戳,单位秒
     */
    private Long serverCtime;
    /**
     * 文件的服务器修改Unix时间戳,单位秒
     */
    private Long serverMtime;
    /**
     * 文件大小,单位字节
     */
    private Long size;
    /**
     * 缩略图地址
     */
    private String thumbs;
    /**
     * 图片高度
     */
    private Integer height;
    /**
     * 图片宽度
     */
    private Integer width;
    /**
     * 图片拍摄时间
     */
    private Long dateTaken;
    /**
     * 图片旋转方向信息
     */
    private String orientation;

    public Long getServerCtime() {
        if (serverCtime != null) {
            return serverCtime * 1000;
        }
        return serverCtime;
    }

    public Long getServerMtime() {
        if (serverMtime != null) {
            return serverMtime * 1000;
        }
        return serverMtime;
    }

    public Long getDateTaken() {
        if (dateTaken != null) {
            return dateTaken * 1000;
        }
        return dateTaken;
    }
}

测试

public static void main(String[] args) {
        String accessToken = BaiduNetDiskConstant.ACCESSTOKEN;

        /**
         * 获取文件列表
         */
        BaiduFileListVo baiduFileListVo = new BaiduFileListVo();
        baiduFileListVo.setDir(BaiduNetDiskConstant.BAIDUNETDISK_APP_PATH);
        List<BaiduNetDiskFileList> baiduFileListByPath = getFileList(baiduFileListVo, accessToken);
        System.out.println(baiduFileListByPath.toString());

        /**
         * 获取文件信息
         */
        Long[] ids = {1076025667018234l, 415956271116370l};//👆👆👆👆👆👆👆👆从文件列表中获取👆👆👆👆👆👆👆👆👆👆
        List<BaiduNetDiskFileInfo> fileInfos = getFileInfos(accessToken, ids);
        for (BaiduNetDiskFileInfo fileInfo : fileInfos) {
            System.out.println(fileInfo.toString());
        }

        /**
         * 文件下载
         */
        BaiduNetDiskFileInfo baiduNetDiskFileInfo = fileInfos.get(0);
        boolean b = BaiduNetDiskUpload.downLoad(baiduNetDiskFileInfo.getDlink(), baiduNetDiskFileInfo.getFilename(), accessToken);
    }

6. 获取文件列表

package boot.test.baidu;

import boot.test.constant.BaiduNetDiskConstant;
import boot.test.dto.*;
import boot.test.utils.BaiduNetDiskUtil;
import boot.test.vo.BaiduFileListVo;
import boot.test.vo.BaiduUploadFileVo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;
import java.util.List;

@Slf4j
public class BaiduNetDiskFileManager {

    /**
     * 获取用户网盘中的文件列表
     *
     * @param baiduFileListVo
     * @param accessToken
     */
    public static List<BaiduNetDiskFileList> getFileList(BaiduFileListVo baiduFileListVo, String accessToken) {
        BufferedReader in = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_FILE_LIST_URL +
                    "method=list" + //本接口固定为list
                    "&dir=" + BaiduNetDiskUtil.urlEncoder(baiduFileListVo.getDir()) + //需要list的目录,以/开头的绝对路径, 默认为/ 路径包含中文时需要UrlEncode编码
                    "&access_token=" + accessToken + //接口鉴权参数
                    "&web=web" + //值为1时,返回dir_empty属性和缩略图数据
                    "&folder=0" + //是否只返回文件夹,0 返回所有,1 只返回文件夹,且属性只返回path字段
                    "&order=time" //排序字段:默认为name;name表示先按文件类型排序,后按文件名称排序;
//                    "&desc=1" + //默认为升序,设置为1实现降序 (注:排序的对象是当前目录下所有文件,不是当前分页下的文件)
//                    "&start=0" + //起始位置,从0开始
//                    "&limit=10" + //查询数目,默认为1000,建议最大不超过1000
            );
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("获取百度网盘中的文件列表响应结果:{} " + response.toString());
            JSONObject resultJson = JSON.parseObject(response.toString());
            if (resultJson.getInteger("errno") != 0) {
                System.out.println("获取百度网盘文件列表失败");
            }
            return JSONObject.parseArray(resultJson.getString("list"), BaiduNetDiskFileList.class);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取百度网盘文件列表失败");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 获取百度网盘文档列表
     *
     * @param path
     * @param accessToken
     * @return
     */
    public List<BaiduNetDiskDocList> getDoclist(String path, String accessToken) {
        BufferedReader in = null;
        try {
            URL url = new URL(BaiduNetDiskConstant.BAIDUNETDISK_FILE_LIST_URL +
                    "method=doclist" + //本接口固定为doclist
                    "&parent_path=" + BaiduNetDiskUtil.urlEncoder(path) + //目录名称,以/开头的绝对路径, 默认为/  路径包含中文时需要UrlEncode编码
                    "&access_token=" + accessToken + //接口鉴权参数
                    "&web=1"  //为1时返回文档预览地址lodocpreview
//                    "&page=1" + //页码,从1开始, 如果不指定页码,则为不分页模式,返回所有的结果。如果指定page参数,则按修改时间倒序排列
//                    "&num=5" //一页返回的文档数, 默认值为1000,建议最大值不超过1000
            );
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String inputLine;
            StringBuffer response = new StringBuffer();
            while ((inputLine = in.readLine()) != null) {
                response.append(inputLine);
            }
            log.info("获取百度网盘文档列表响应结果:{} " + response.toString());
            JSONObject responseJson = JSON.parseObject(response.toString());
            if (responseJson.getInteger("errno") != 0) {
                System.out.println("获取百度网盘文档列表失败");
            }
            return JSONObject.parseArray(responseJson.getString("info"), BaiduNetDiskDocList.class);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("获取百度网盘文档列表失败");
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e2) {
                    e2.printStackTrace();
                }
            }
        }
        return null;
    }
}

package boot.test.dto;

import lombok.Data;

/**
 * 百度网盘文件列表
 */
@Data
public class BaiduNetDiskFileList {
    /**
     * 文件在云端的唯一标识ID
     */
    private Long fsId;
    /**
     * 文件的绝对路径
     */
    private String path;
    /**
     * 文件名称
     */
    private String serverFilename;
    /**
     * 文件大小,单位B
     */
    private Long size;
    /**
     * 文件在服务器修改时间
     */
    private Long serverMtime;
    /**
     * 文件在服务器创建时间
     */
    private Long serverCtime;
    /**
     * 文件在客户端修改时间
     */
    private Long localMtime;
    /**
     * 文件在客户端创建时间
     */
    private Long localCtime;
    /**
     * 是否为目录,0 文件、1 目录
     */
    private Integer isdir;
    /**
     * 文件类型,1 视频、2 音频、3 图片、4 文档、5 应用、6 其他、7 种子
     */
    private Integer category;
    /**
     * 云端哈希(非文件真实MD5),只有是文件类型时,该字段才存在
     */
    private String md5;
    /**
     * 该目录是否存在子目录,只有请求参数web=1且该条目为目录时,该字段才存在, 0为存在, 1为不存在
     */
    private Integer dirEmpty;
    /**
     * 只有请求参数web=1且该条目分类为图片时,该字段才存在,包含三个尺寸的缩略图URL
     */
    private String thumbs;

    public Long getServerCtime() {
        if (serverCtime != null) {
            return serverCtime * 1000;
        }
        return serverCtime;
    }

    public Long getServerMtime() {
        if (serverMtime != null) {
            return serverMtime * 1000;
        }
        return serverMtime;
    }

    public Long getLocalMtime() {
        if (localMtime != null) {
            return localMtime * 1000;
        }
        return localMtime;
    }

    public Long getLocalCtime() {
        if (localCtime != null) {
            return localCtime * 1000;
        }
        return localCtime;
    }
}

package boot.test.dto;

import lombok.Data;

/**
 * 用户网盘中文档列表
 */
@Data
public class BaiduNetDiskDocList {
    /**
     * 文件在云端的唯一标识
     */
    private Long fsId;
    /**
     * 文件名
     */
    private String serverFilename;
    /**
     * 文件路径
     */
    private String path;
    /**
     * 文件类型
     */
    private Integer category;
    /**
     * 文件大小
     */
    private Long size;
    /**
     * 是否是目录,0为否,1为是
     */
    private Integer isdir;
    /**
     * 文件在客户端创建时间
     */
    private Long localCtime;
    /**
     * 文件在客户端修改时间
     */
    private Long localMtime;
    /**
     * 文件在服务端创建时间
     */
    private Long serverCtime;
    /**
     * 文件在服务端修改时间
     */
    private Long serverMtime;
    /**
     * 云端哈希(非文件真实MD5)
     */
    private String md5;
    private String objectKey;
    private Integer share;
//    private String lodocpreview;
//    private String docpreview;

    public Long getServerCtime() {
        if (serverCtime != null) {
            return serverCtime * 1000;
        }
        return serverCtime;
    }

    public Long getServerMtime() {
        if (serverMtime != null) {
            return serverMtime * 1000;
        }
        return serverMtime;
    }

    public Long getLocalMtime() {
        if (localMtime != null) {
            return localMtime * 1000;
        }
        return localMtime;
    }

    public Long getLocalCtime() {
        if (localCtime != null) {
            return localCtime * 1000;
        }
        return localCtime;
    }
}

测试

    public static void main(String[] args) {
        String accessToken = BaiduNetDiskConstant.ACCESSTOKEN;
        /**
         * 获取文件列表
         */
        BaiduFileListVo baiduFileListVo = new BaiduFileListVo();
        baiduFileListVo.setDir(BaiduNetDiskConstant.BAIDUNETDISK_APP_PATH);
        List<BaiduNetDiskFileList> baiduFileListByPath = getFileList(baiduFileListVo, accessToken);
        System.out.println(baiduFileListByPath.toString());
    }

7. 文件分片上传(不可获取进度)–方法二

7. 文件下载(不可获取进度)–方法二

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1697266.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[数据集][目标检测]手枪机枪刀检测数据集VOC+YOLO格式5990张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;5990 标注数量(xml文件个数)&#xff1a;5990 标注数量(txt文件个数)&#xff1a;5990 标注…

健身房会员管理系统服务预约小程序的作用是什么

拥有完美身材/减肥/锻炼等前往健身房是个不错的选择&#xff0c;商家生意开展需要吸引同城客户并转化&#xff0c;客户也有自己的判断需要找到更全面的场地&#xff1b;完善客户消费流程利于品牌发展和不断获客转化。 运用【雨科】平台搭建健身房管理系统小程序&#xff0c;多…

SpringBoot【1】集成 Druid

SpringBoot 集成 Druid 前言创建项目修改 pom.xml 文件添加配置文件开发 java 代码启动类 - DruidApplication配置文件-propertiesDruidConfigPropertyDruidMonitorProperty 配置文件-configDruidConfig 控制层DruidController 运行验证Druid 的监控应用程序 前言 JDK版本&…

html5网页-浏览器中实现高德地图定位功能

介绍 HTML5是当前Web开发中最常用的技术之一&#xff0c;而地图应用又是其中一个非常常见的需求。高德地图是国内最受欢迎的地图服务提供商之一&#xff0c;他们提供了一系列的API&#xff0c;方便开发者在自己的网站或应用中集成地图功能。 接下来我们如何使用HTML5浏览器和高…

Unity开发——XLua热更新之Hotfix配置(包含xlua获取与导入)

一、Git上获取xlua 最新的xlua包&#xff0c;下载地址链接&#xff1a;https://github.com/Tencent/xLua 二、Unity添加xlua 解压xlua压缩包后&#xff0c;将xlua里的Assets里的文件直接复制进Unity的Assets文件夹下。 成功导入后&#xff0c;unity工具栏会出现xlua选项。 …

【C++提高编程-04】----C++之Vector容器实战

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

初步认识栈和队列

Hello&#xff0c;everyone&#xff0c;今天小编讲解栈和队列的知识&#xff01;&#xff01;&#xff01; 1.栈 1.1栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。 进行数据插入和删除操作的一端 称为栈顶&…

Mysql 找出未提交事务的SQL及死锁

未提交事务&#xff1a; 通过查看information_schema.INNODB_TRX视图,您可以了解当前系统中正在运行的事务情况,从而进行问题排查和性能优化。 SELECT * FROM information_schema.innodb_trx; 通过trx_state为RUNNIG,trx_started判断是否有一直RUNNING的事务。 如果有未提交…

Linux修炼之路之冯系结构,操作系统

目录 一&#xff1a;冯诺依曼体系结构 1.五大组件 2.存储器存在的意义 3.几个问题 二&#xff1a;操作系统 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 一&#xff1a;冯诺依曼体系结构 我们当代的计算机的基本构成都是由冯诺依曼…

【深度学习】第1章

概论: 机器学习是对研究问题进行模型假设,利用计算机从训练数据中学习得到模型参数,并最终对数据进行预测和分析,其基础主要是归纳和统计。 深度学习是一种实现机器学习的技术,是机器学习重要的分支。其源于人工神经网络的研究。深度学习的模型结构是一种含多隐层的神经…

MySQL增删查改进阶

数据库约束表的关系增删查改 目录 一.数据库约束类型 NOT NULL约束类型 UNIQUE 唯一约束 DEFAULT 默认值约束 PRIMARY KEY&#xff1a;主键约束 FOREIGN KEY :W外键约束 二&#xff0c;查询 count&#xff08;&#xff09;两种用法 sum&#xff0c;avg&#xff0c;max…

python文件处理之os模块和shutil模块

目录 1.os模块 os.path.exists(path)&#xff1a;文件或者目录存在与否判断 os.path.isfile(path)&#xff1a;判断是否是文件 os.path.isdir(path)&#xff1a;判断是否是文件夹 os.remove(path)&#xff1a;尝试删除文件 os.rmdir(path)&#xff1a;尝试删除目录 os.m…

【设计模式】——装饰模式(包装器模式)

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…

行为型设计模式之模板模式

文章目录 概述原理结构图实现 小结 概述 模板方法模式(template method pattern)原始定义是&#xff1a;在操作中定义算法的框架&#xff0c;将一些步骤推迟到子类中。模板方法让子类在不改变算法结构的情况下重新定义算法的某些步骤。 模板方法中的算法可以理解为广义上的业…

Linux驱动(3)- LInux USB驱动层次

在Linux系统中&#xff0c;提供了主机侧和设备侧USB驱动框架。 从主机侧&#xff0c;需要编写USB驱动包括主机控制器驱动&#xff0c;设备驱动两类&#xff0c;USB 主机控制驱动程序控制插入其中的USB设备。 USB设备驱动程序控制该设备如何作为从设备与主机进行通信。 1.主机…

文件夹打开出错?这里有你需要的数据恢复与预防指南

在日常使用电脑时&#xff0c;我们有时会遇到文件夹打开出错的情况。当你尝试访问某个文件夹时&#xff0c;系统可能会弹出一个错误提示&#xff0c;告诉你无法打开该文件夹。这种情况不仅会影响我们的工作效率&#xff0c;还可能导致重要数据的丢失。接下来&#xff0c;我们将…

Flutter-自定义折叠流布局实现

需求 在 Flutter 开发中&#xff0c;常常需要实现自定义布局以满足不同的需求。本文将介绍如何通过自定义组件实现一个折叠流布局&#xff0c;该组件能够显示一系列标签&#xff0c;并且在内容超出一定行数时&#xff0c;可以展开和收起。 效果 该折叠流布局可以显示一组标签…

ROCm上运行Transformer

10.7. Transformer — 动手学深度学习 2.0.0 documentation (d2l.ai) 代码 import math import pandas as pd import torch from torch import nn from d2l import torch as d2l#save class PositionWiseFFN(nn.Module):"""基于位置的前馈网络""&qu…

【uni-best+UView】使用mitt实现自定义错误对话框

痛点 目前在设计一个uni-best的前端全局的异常提示信息&#xff0c;如果采用Toast方式&#xff0c;对微信支持的不友好。微信的7中文长度连个NPE信息都无法完整显示&#xff0c;更不用提Stacktrace的复杂报错了。如果使用对话框&#xff0c;必须在页面先预先定义&#xff0c;对…