安装minio,并使用Springboot整合Minio

Docker安装Minio

一、查看docker环境是否正常

在命令行使用docker search minIO

二、下载minIO的镜像

docker pull minio/minio

三、创建minIO容器

docker images

docker run \
--name minio \
-p 9000:9000  \
-p 9090:9090  \
-d --restart=always \
-e "MINIO_ROOT_USER=admin" \
-e "MINIO_ROOT_PASSWORD=MinIO@Hist0#1003" \
-v /home/data:/data \
-v /home/config:/root/.minio \
minio/minio server  /data --console-address ":9090" --address ":9000"
  • 这里的 \ 指的是命令还没有输入完,还需要继续输入命令,先不要执行的意思。
  • 这里的9090端口指的是minio的客户端端口。虽然设置9090,但是我们在访问9000的时候,他也会自动跳到9090。
  • 9000端口是minio的服务端端口,我们程序在连接minio的时候,就是通过这个端口来连接的。
  • -v就是docker run当中的挂载,这里的/mydata/minio/data:/data意思就是将容器的/data目录和宿主机的/mydata/minio/data目录做映射,这样我们想要查看容器的文件的时候,就不需要看容器当中的文件了。

注意在执行命令的时候,他是会自动在宿主机当中创建目录的。我们不需要手动创建。

minio所上传的文件默认都是存储在容器的data目录下的!

假如删除容器了宿主机当中挂载的目录是不会删除的。假如没有使用-v挂载目录,那他在宿主机的存储位置的文件会直接删除的。

宿主机的挂载目录一定是根目录,如果是相对路径会有问题。还有容器当中的目录也是必须是绝对路径(根路径就是带/的)。

所谓的挂载其实就是将容器目录和宿主机目录进行绑定了,操作宿主机目录,容器目录也会变化,操作容器目录,宿主机目录也会变化。这样做的目的 可以间接理解为就是数据持久化,防止容器误删,导致数据丢失的情况。

  • MINIO_ROOT_USER:账号 MINIO_ROOT_PASSWORD:密码 (正常账号应该不低于3位,密码不低于8位,不然容器会启动不成功)
  • --console-address 指定客户端端口
  • -d --restart=always 代表重启linux的时候容器自动启动
  • --name minio 容器名称

window安装

 Springboot整合Minio

整体结构

<dependency>
    <groupId>io.minio</groupId>
    <artifactId>minio</artifactId>
    <version>8.5.2</version>
</dependency>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.example</groupId>
  <artifactId>minio</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <name>minio</name>
  <description>minio</description>
  <properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <spring-boot.version>2.6.13</spring-boot.version>
  </properties>
  <dependencies>
    <!--minio -->
    <dependency>
      <groupId>io.minio</groupId>
      <artifactId>minio</artifactId>
      <version>8.2.1</version>
    </dependency>


    <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.2</version>
    </dependency>

    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
    </dependency>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
      <groupId>org.apache.ant</groupId>
      <artifactId>ant</artifactId>
      <version>1.9.9</version>
    </dependency>
    <dependency>
      <groupId>org.liquibase</groupId>
      <artifactId>liquibase-core</artifactId>
      <version>4.9.1</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>2.11.0</version>
    </dependency>


  </dependencies>
  <dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>${spring-boot.version}</version>
        <type>pom</type>
        <scope>import</scope>
      </dependency>
    </dependencies>
  </dependencyManagement>

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
          <encoding>UTF-8</encoding>
        </configuration>
          </plugin>
          <plugin>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-maven-plugin</artifactId>
          <version>${spring-boot.version}</version>
          <configuration>
          <mainClass>com.example.minio.MinioApplication</mainClass>
          <skip>true</skip>
          </configuration>
          <executions>
          <execution>
          <id>repackage</id>
          <goals>
          <goal>repackage</goal>
          </goals>
          </execution>
          </executions>
          </plugin>
          </plugins>
          </build>

          </project>
server:
  port: 8003

spring:
  minio:
    access-key: admin      #key就是docker初始化是设置的,密钥相同
    secret-key: MinIO@Hist0#1003
    url: http://123.249.27.251:9000
    bucket-name: est   # 登陆minio创建的文件桶
#    minio-prefix: aa   #MinIO上传路径前缀,可无
package com.example.minio.config;

import io.minio.MinioClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

/**
 *  读取配置文件的内容赋值给属性
 */

@Data
@Component
@ConfigurationProperties(prefix = "spring.minio")
public class MinioCloudStorageConfig {

    //accessKey类似于用户ID,用于唯一标识你的账户
    private String accessKey;

    //secretKey是你账户的密码
    private String secretKey;

    // Minio 服务端 api地址
    private String url;

    //默认存储桶
    private String bucketName;

    //MinIO上传路径前缀
    private String minioPrefix;

    /**
     * 构建 操作Minio的客户端
     * @return
     */
    @Bean
    public MinioClient minioClient() {
        return MinioClient.builder()
        .endpoint(url)
        .credentials(accessKey, secretKey)
        .build();
    }

}
package com.example.minio.service;


import liquibase.repackaged.org.apache.commons.lang3.StringUtils;
import org.apache.tools.ant.util.DateUtils;


import java.io.InputStream;
import java.util.Date;
import java.util.UUID;

public abstract class AbstractCloudStorageService {
    /**
     * 定义文件路径
     *
     * @param prefix 前缀
     * @param suffix 后缀
     * @return 返回上传路径
     */
    public String getPath(String prefix, String suffix) {
        //生成uuid
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        String path = DateUtils.format(new Date(), "yyyyMMdd") + "/" + uuid;
        if (StringUtils.isNotBlank(prefix)) {
            path = prefix + "/" + path ;
        }
        return path + "." + suffix;
    }

    /**
     * 文件上传
     * @param data    文件字节数组
     * @param path    文件路径,包含文件名
     * @return        返回http地址
     */
    public abstract String upload(byte[] data, String path);

    /**
     * 文件上传
     * @param data     文件字节数组
     * @param suffix   后缀
     * @return         返回http地址
     */
    public abstract String uploadSuffix(byte[] data, String suffix);

    /**
     * 文件上传
     * @param inputStream   字节流
     * @param path          文件路径,包含文件名
     * @return              返回http地址
     */
    public abstract String upload(InputStream inputStream, String path);

    /**
     * 文件上传
     * @param inputStream  字节流
     * @param suffix       后缀
     * @return             返回http地址
     */
    public abstract String uploadSuffix(InputStream inputStream, String suffix);
}
package com.example.minio.service;

import com.example.minio.config.MinioCloudStorageConfig;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

@Service
@Slf4j
public class MinioCloudStorageService extends AbstractCloudStorageService{
    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioCloudStorageConfig configuration;




    @Override
    public String upload(byte[] data, String path) {
        return upload(new ByteArrayInputStream(data), path);
    }

    @Override
    public String uploadSuffix(byte[] data, String suffix) {
        System.out.println(configuration);
        return upload(data,getPath(configuration.getMinioPrefix(),suffix));
    }

    @Override
    public String upload(InputStream inputStream, String path) {
        // 使用putObject上传一个文件到存储桶中。
        try {
            minioClient.putObject(PutObjectArgs.builder()
                                  .bucket(configuration.getBucketName())
                                  .object(path)
                                  .stream(inputStream, inputStream.available(), -1)
                                  .contentType("image/jpeg") //设置传递文件的内容类型,不需要下载就能直接预览
                                  .build());
        } catch (Exception e){
            e.printStackTrace();
        }
        return configuration.getUrl()+"/"+configuration.getBucketName()+"/"+path;
    }

    @Override
    public String uploadSuffix(InputStream inputStream, String suffix) {
        return upload(inputStream,getPath(configuration.getMinioPrefix(),suffix));
    }
}

package com.example.minio.controller;

import com.example.minio.service.MinioCloudStorageService;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.apache.commons.io.FilenameUtils;
import javax.annotation.Resource;
import java.io.ByteArrayInputStream;
import java.io.IOException;

/**
 * 通用请求处理
 */
@RestController
public class MinIoController {
    @Resource
    MinioCloudStorageService minIoService;
    /**
     * 区别在于,使用getBytes()数据已经从流中读取,而使用getInputStream()您仍然必须读取数据。
     *
     * 您使用的取决于您想要处理内容的内容。如果它是一个只想写入磁盘的图像,那么getBytes()将是最好的,
     * 但如果它是要解析的文本并与之执行的文本,那么GetInputStream()可能会更好。
     */

    /**
     * 使用getBytes()获取内容
     * @param file
     * @throws IOException
     */
    @PostMapping("/upload")
    public void uploadToFile(@RequestParam("file") MultipartFile file) throws IOException {
       //getOriginalFileName方法获取的是文件的完整名称,包括文件名称+文件拓展名
        String extension = FilenameUtils.getExtension(file.getOriginalFilename()); //后缀
        String s = minIoService.uploadSuffix(file.getBytes(), extension);

    }

    /**
     * 使用getInputStream()获取内容
     * @param file
     * @throws IOException
     */
    @PostMapping("/upload2")
    public void uploadToFile2(@RequestParam("file") MultipartFile file) throws IOException {

        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
        System.out.println(file.getInputStream());
        String s = minIoService.uploadSuffix(file.getInputStream(), extension);

    }


}

MultipartFile接口

用于接收前端传递的上传文件,图片等数据。

主要方法:

1、 //getInputStream() 方法 返回InputStream读取文件的内容

InputStream in = file.getInputStream();

2、//getOriginalFilename()方法是得到原来的文件名在客户机的文件系统名称(可能包含路径信息,也可能只是文件名,这取决于所使用的浏览器。)

String OriginalFilename = file.getOriginalFilename();

3、//getName() 方法 返回参数的名称 这里返回的上传文件的组件的名称

String fileName = file.getName()

4、//transferTo() 用来把 MultipartFile 转换成 File

File f = new File(“d:\ts.jpg”);

file.transferTo(f);

5、//isEmpty() 判断是否为空,或者上传的文件是否有内容

6、//getBytes() 将文件内容转化成一个byte[] 返回

7、//getSize() 返回文件大小 以字节为单位

8、//getContentType() 返回文件的内容类

(.xls 类型返回:application/vnd.ms-excel

.docx 类型返回:application/vnd.openxmlformats-officedocument.wordprocessingml.document

.pdf 类型返回:application/pdf

.jpg 类型返回:image/jpeg)

报错:

😍链接无法访问

错误就在于minIO默认是private 我们需要把它设置成public

 

文件不下载直接预览

putObject方法:
这个方法是一个重载的方法,基本的参数就是
bucketName : 上传的捅名称
objectName : 上传成功的文件名字
filename : 上传的文件路径 InputStream : 可以通过流的方式上传文件
PutObjectOptions : 设置 Content-Type map等参数
在默认的情况下 Content-Type 设置的 是 application/octet-stream 下载,所以上传的时候我们要区分文件设置不同的 Content-Type

image.png



HTTP Content-type

文件扩展名

Content-Type(Mime-Type)

文件扩展名

Content-Type(Mime-Type)

.*( 二进制流,不知道下载文件类型)

application/octet-stream

.tif

image/tiff

.001

application/x-001

.301

application/x-301

.323

text/h323

.906

application/x-906

.907

drawing/907

.a11

application/x-a11

.acp

audio/x-mei-aac

.ai

application/postscript

.aif

audio/aiff

.aifc

audio/aiff

.aiff

audio/aiff

.anv

application/x-anv

.asa

text/asa

.asf

video/x-ms-asf

.asp

text/asp

.asx

video/x-ms-asf

.au

audio/basic

.avi

video/avi

.awf

application/vnd.adobe.workflow

.biz

text/xml

.bmp

application/x-bmp

.bot

application/x-bot

.c4t

application/x-c4t

.c90

application/x-c90

.cal

application/x-cals

.cat

application/vnd.ms-pki.seccat

.cdf

application/x-netcdf

.cdr

application/x-cdr

.cel

application/x-cel

.cer

application/x-x509-ca-cert

.cg4

application/x-g4

.cgm

application/x-cgm

.cit

application/x-cit

.class

java/*

.cml

text/xml

.cmp

application/x-cmp

.cmx

application/x-cmx

.cot

application/x-cot

.crl

application/pkix-crl

.crt

application/x-x509-ca-cert

.csi

application/x-csi

.css

text/css

.cut

application/x-cut

.dbf

application/x-dbf

.dbm

application/x-dbm

.dbx

application/x-dbx

.dcd

text/xml

.dcx

application/x-dcx

.der

application/x-x509-ca-cert

.dgn

application/x-dgn

.dib

application/x-dib

.dll

application/x-msdownload

.doc

application/msword

.dot

application/msword

.drw

application/x-drw

.dtd

text/xml

.dwf

Model/vnd.dwf

.dwf

application/x-dwf

.dwg

application/x-dwg

.dxb

application/x-dxb

.dxf

application/x-dxf

.edn

application/vnd.adobe.edn

.emf

application/x-emf

.eml

message/rfc822

.ent

text/xml

.epi

application/x-epi

.eps

application/x-ps

.eps

application/postscript

.etd

application/x-ebx

.exe

application/x-msdownload

.fax

image/fax

.fdf

application/vnd.fdf

.fif

application/fractals

.fo

text/xml

.frm

application/x-frm

.g4

application/x-g4

.gbr

application/x-gbr

.

application/x-

.gif

image/gif

.gl2

application/x-gl2

.gp4

application/x-gp4

.hgl

application/x-hgl

.hmr

application/x-hmr

.hpg

application/x-hpgl

.hpl

application/x-hpl

.hqx

application/mac-binhex40

.hrf

application/x-hrf

.hta

application/hta

.htc

text/x-component

.htm

text/html

.html

text/html

.htt

text/webviewhtml

.htx

text/html

.icb

application/x-icb

.ico

image/x-icon

.ico

application/x-ico

.iff

application/x-iff

.ig4

application/x-g4

.igs

application/x-igs

.iii

application/x-iphone

.img

application/x-img

.ins

application/x-internet-signup

.isp

application/x-internet-signup

.IVF

video/x-ivf

.java

java/*

.jfif

image/jpeg

.jpe

image/jpeg

.jpe

application/x-jpe

.jpeg

image/jpeg

.jpg

image/jpeg

.jpg

application/x-jpg

.js

application/x-javascript

.jsp

text/html

.la1

audio/x-liquid-file

.lar

application/x-laplayer-reg

.latex

application/x-latex

.lavs

audio/x-liquid-secure

.lbm

application/x-lbm

.lmsff

audio/x-la-lms

.ls

application/x-javascript

.ltr

application/x-ltr

.m1v

video/x-mpeg

.m2v

video/x-mpeg

.m3u

audio/mpegurl

.m4e

video/mpeg4

.mac

application/x-mac

.man

application/x-troff-man

.math

text/xml

.mdb

application/msaccess

.mdb

application/x-mdb

.mfp

application/x-shockwave-flash

.mht

message/rfc822

.mhtml

message/rfc822

.mi

application/x-mi

.mid

audio/mid

.midi

audio/mid

.mil

application/x-mil

.mml

text/xml

.mnd

audio/x-musicnet-download

.mns

audio/x-musicnet-stream

.mocha

application/x-javascript

.movie

video/x-sgi-movie

.mp1

audio/mp1

.mp2

audio/mp2

.mp2v

video/mpeg

.mp3

audio/mp3

.mp4

video/mpeg4 (video/mp4)

.mpa

video/x-mpg

.mpd

application/vnd.ms-project

.mpe

video/x-mpeg

.mpeg

video/mpg

.mpg

video/mpg

.mpga

audio/rn-mpeg

.mpp

application/vnd.ms-project

.mps

video/x-mpeg

.mpt

application/vnd.ms-project

.mpv

video/mpg

.mpv2

video/mpeg

.mpw

application/vnd.ms-project

.mpx

application/vnd.ms-project

.mtx

text/xml

.mxp

application/x-mmxp

.net

image/pnetvue

.nrf

application/x-nrf

.nws

message/rfc822

.odc

text/x-ms-odc

.out

application/x-out

.p10

application/pkcs10

.p12

application/x-pkcs12

.p7b

application/x-pkcs7-certificates

.p7c

application/pkcs7-mime

.p7m

application/pkcs7-mime

.p7r

application/x-pkcs7-certreqresp

.p7s

application/pkcs7-signature

.pc5

application/x-pc5

.pci

application/x-pci

.pcl

application/x-pcl

.pcx

application/x-pcx

.pdf

application/pdf

.pdf

application/pdf

.pdx

application/vnd.adobe.pdx

.pfx

application/x-pkcs12

.pgl

application/x-pgl

.pic

application/x-pic

.pko

application/vnd.ms-pki.pko

.pl

application/x-perl

.plg

text/html

.pls

audio/scpls

.plt

application/x-plt

.png

image/png

.png

application/x-png

.pot

application/vnd.ms-powerpoint

.ppa

application/vnd.ms-powerpoint

.ppm

application/x-ppm

.pps

application/vnd.ms-powerpoint

.ppt

application/vnd.ms-powerpoint

.ppt

application/x-ppt

.pr

application/x-pr

.prf

application/pics-rules

.prn

application/x-prn

.prt

application/x-prt

.ps

application/x-ps

.ps

application/postscript

.ptn

application/x-ptn

.pwz

application/vnd.ms-powerpoint

.r3t

text/vnd.rn-realtext3d

.ra

audio/vnd.rn-realaudio

.ram

audio/x-pn-realaudio

.ras

application/x-ras

.rat

application/rat-file

.rdf

text/xml

.rec

application/vnd.rn-recording

.red

application/x-red

.rgb

application/x-rgb

.rjs

application/vnd.rn-realsystem-rjs

.rjt

application/vnd.rn-realsystem-rjt

.rlc

application/x-rlc

.rle

application/x-rle

.rm

application/vnd.rn-realmedia

.rmf

application/vnd.adobe.rmf

.rmi

audio/mid

.rmj

application/vnd.rn-realsystem-rmj

.rmm

audio/x-pn-realaudio

.rmp

application/vnd.rn-rn_music_package

.rms

application/vnd.rn-realmedia-secure

.rmvb

application/vnd.rn-realmedia-vbr

.rmx

application/vnd.rn-realsystem-rmx

.rnx

application/vnd.rn-realplayer

.rp

image/vnd.rn-realpix

.rpm

audio/x-pn-realaudio-plugin

.rsml

application/vnd.rn-rsml

.rt

text/vnd.rn-realtext

.rtf

application/msword

.rtf

application/x-rtf

.rv

video/vnd.rn-realvideo

.sam

application/x-sam

.sat

application/x-sat

.sdp

application/sdp

.sdw

application/x-sdw

.sit

application/x-stuffit

.slb

application/x-slb

.sld

application/x-sld

.slk

drawing/x-slk

.smi

application/smil

.smil

application/smil

.smk

application/x-smk

.snd

audio/basic

.sol

text/plain

.sor

text/plain

.spc

application/x-pkcs7-certificates

.spl

application/futuresplash

.spp

text/xml

.ssm

application/streamingmedia

.sst

application/vnd.ms-pki.certstore

.stl

application/vnd.ms-pki.stl

.stm

text/html

.sty

application/x-sty

.svg

text/xml

.swf

application/x-shockwave-flash

.tdf

application/x-tdf

.tg4

application/x-tg4

.tga

application/x-tga

.tif

image/tiff

.tif

application/x-tif

.tiff

image/tiff

.tld

text/xml

.top

drawing/x-top

.torrent

application/x-bittorrent

.tsd

text/xml

.txt

text/plain

.uin

application/x-icq

.uls

text/iuls

.vcf

text/x-vcard

.vda

application/x-vda

.vdx

application/vnd.visio

.vml

text/xml

.vpg

application/x-vpeg005

.vsd

application/vnd.visio

.vsd

application/x-vsd

.vss

application/vnd.visio

.vst

application/vnd.visio

.vst

application/x-vst

.vsw

application/vnd.visio

.vsx

application/vnd.visio

.vtx

application/vnd.visio

.vxml

text/xml

.wav

audio/wav

.wax

audio/x-ms-wax

.wb1

application/x-wb1

.wb2

application/x-wb2

.wb3

application/x-wb3

.wbmp

image/vnd.wap.wbmp

.wiz

application/msword

.wk3

application/x-wk3

.wk4

application/x-wk4

.wkq

application/x-wkq

.wks

application/x-wks

.wm

video/x-ms-wm

.wma

audio/x-ms-wma

.wmd

application/x-ms-wmd

.wmf

application/x-wmf

.wml

text/vnd.wap.wml

.wmv

video/x-ms-wmv

.wmx

video/x-ms-wmx

.wmz

application/x-ms-wmz

.wp6

application/x-wp6

.wpd

application/x-wpd

.wpg

application/x-wpg

.wpl

application/vnd.ms-wpl

.wq1

application/x-wq1

.wr1

application/x-wr1

.wri

application/x-wri

.wrk

application/x-wrk

.ws

application/x-ws

.ws2

application/x-ws

.wsc

text/scriptlet

.wsdl

text/xml

.wvx

video/x-ms-wvx

.xdp

application/vnd.adobe.xdp

.xdr

text/xml

.xfd

application/vnd.adobe.xfd

.xfdf

application/vnd.adobe.xfdf

.xhtml

text/html

.xls

application/vnd.ms-excel

.xls

application/x-xls

.xlw

application/x-xlw

.xml

text/xml

.xpl

audio/scpls

.xq

text/xml

.xql

text/xml

.xquery

text/xml

.xsd

text/xml

.xsl

text/xml

.xslt

text/xml

.xwd

application/x-xwd

.x_b

application/x-x_b

.sis

application/vnd.symbian.install

.sisx

application/vnd.symbian.install

.x_t

application/x-x_t

.ipa

application/vnd.iphone

.apk

application/vnd.android.package-archive

.xap

application/x-silverlight-app

  • 22
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值