掌握Spring框架中的文件上传功能:使用CommonsMultipartResolver

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在Spring MVC框架中,文件上传是一个常规功能,其中 CommonsMultipartResolver 作为多部分解析器扮演着关键角色。本文深入分析了 CommonsMultipartResolver 的工作原理,并详细说明了如何在Spring MVC中配置和使用它来处理文件上传。包括配置解析器、编写处理文件上传的Controller层代码、前端表单创建、文件存储和处理方法以及错误处理和验证机制,旨在帮助开发者全面理解并实现安全可靠的文件上传功能。 Spring CommonsMultipartResolver 上传文件

1. 文件上传在Spring MVC中的应用

在Web开发中,文件上传是一种常见的功能需求,特别是在涉及用户交互的应用程序中。Spring MVC框架提供了一种简洁的方式来实现文件上传功能,这使得开发者能够轻松地集成此功能到他们的应用程序中。Spring MVC不仅支持传统请求的文件上传,还允许开发者以声明式的方式处理文件上传请求,从而提高代码的可读性和可维护性。

文件上传的实现涉及到前端表单的创建和后端控制器的配置。前端表单需要有特定的设置来允许用户选择文件进行上传。而后端控制器则负责处理这些上传的文件,这包括接收文件、保存文件以及执行相关的业务逻辑。

在Spring MVC中,文件上传功能的实现依赖于 MultipartResolver 接口的实现类。在接下来的章节中,我们将深入了解 CommonsMultipartResolver ,这是Spring MVC中用于处理文件上传的默认解析器,探讨其配置方法、参数详解以及如何在Controller层实现文件上传的处理流程。

2. CommonsMultipartResolver简介

2.1 CommonsMultipartResolver的作用与特点

2.1.1 文件上传的必要性与优势

在Web应用中,文件上传是常见需求之一,尤其在社交媒体、文档共享平台和电子商务等场景中更是必不可少。文件上传允许用户提交文件,这样应用可以处理并存储这些文件,提供更丰富的内容和功能。

文件上传的优势主要体现在以下几个方面:

  • 用户交互性增强 :用户可以上传图片、视频等多媒体内容,丰富网站内容,提高用户参与度。
  • 数据收集与处理 :企业可以通过文件上传收集用户数据,为数据分析和处理提供原始材料。
  • 文件分享与分发 :用户可以分享文档、演示文稿等文件,便于知识和信息的快速传播。

2.1.2 CommonsMultipartResolver的设计理念

Apache Commons FileUpload组件中的 CommonsMultipartResolver 是一个专为Spring MVC框架设计的文件上传解析器,旨在简化文件上传处理。它允许开发者以一种声明式的方式处理文件上传请求,无需直接操作底层的Servlet API。

CommonsMultipartResolver 的设计理念包括:

  • 简洁易用 :通过简单的配置即可在Spring MVC项目中实现文件上传功能。
  • 灵活性 :支持不同的文件存储方式(如存储到磁盘或内存)。
  • 可扩展性 :开发者可以根据具体需求进行扩展,比如自定义文件上传过滤器。

2.2 CommonsMultipartResolver与Spring MVC的集成

2.2.1 Spring MVC对文件上传的支持

Spring MVC通过 DispatcherServlet 提供了对文件上传的内置支持,开发者可以很方便地通过 @RequestParam 注解来获取上传的文件。但在处理大文件或进行文件类型限制等高级特性时,需要借助 CommonsMultipartResolver 来实现更复杂的文件上传功能。

2.2.2 CommonsMultipartResolver的工作原理

CommonsMultipartResolver 的工作原理可以通过以下几个步骤来概括:

  1. 解析请求 :拦截器检查传入的请求是否为multipart类型。
  2. 文件解析 :使用 Apache Commons FileUpload 库来解析multipart请求,并将文件数据封装为 MultipartFile 对象。
  3. 文件处理 :将 MultipartFile 对象提供给Spring MVC的Controller层,开发者可以在这里编写业务逻辑处理文件。

示例代码: java @RequestMapping(value = "/upload", method = RequestMethod.POST) public String handleFileUpload(@RequestParam("file") MultipartFile file, Model model) { if (!file.isEmpty()) { try { // 获取文件原始名称 String originalFilename = file.getOriginalFilename(); // 文件保存路径 String savePath = "/path/to/save/" + originalFilename; // 将文件保存到磁盘 file.transferTo(new File(savePath)); model.addAttribute("message", "文件上传成功!"); } catch (Exception e) { model.addAttribute("message", "文件上传失败:" + e.getMessage()); } } return "uploadStatus"; }

通过上述代码,当文件被成功上传后, MultipartFile 对象的 transferTo 方法会被调用来保存文件到指定位置。如果上传过程中发生错误,则会捕获异常并返回错误信息。

CommonsMultipartResolver 在文件上传中的应用,使得文件上传变得更加高效和安全。在下一章节中,我们将详细介绍如何在Spring MVC项目中配置和使用 CommonsMultipartResolver

3. CommonsMultipartResolver配置方法

配置Spring MVC中的文件上传功能是开发者经常需要面对的一个任务。CommonsMultipartResolver 是Spring提供的一个用于处理文件上传的类,它通过Apache Commons FileUpload库来支持文件上传功能。对于不同的部署环境和需求,开发者可以选择不同的配置方式:传统的XML配置或更为现代的Java配置。

3.1 CommonsMultipartResolver的配置步骤

3.1.1 XML配置方式

在Spring的XML配置文件中,配置CommonsMultipartResolver的步骤相对直接。以下是一个基本的配置示例:

<!-- 在beans标签内添加CommonsMultipartResolver的bean -->
<bean id="multipartResolver" class="***monsMultipartResolver">
    <!-- 设置最大上传大小 -->
    <property name="maxUploadSize" value="5242880"/> <!-- 5MB -->
    <!-- 设置文件上传时使用的编码 -->
    <property name="defaultEncoding" value="UTF-8"/>
</bean>

在这个配置中, maxUploadSize 属性设置了文件上传的最大限制,单位为字节。这是一个非常重要的安全特性,可以防止用户上传过大的文件导致服务器资源耗尽。 defaultEncoding 属性则指定了文件名和表单字段的编码方式,确保文件名在不同的浏览器和操作系统中正确处理。

3.1.2 Java配置方式

随着Spring Boot的流行,Java配置方式在项目中变得越来越普遍。对于CommonsMultipartResolver,你可以在配置类中添加如下代码:

@Bean
public CommonsMultipartResolver multipartResolver() {
    CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
    // 设置最大上传大小
    multipartResolver.setMaxUploadSize(5242880); // 5MB
    // 设置文件上传时使用的编码
    multipartResolver.setDefaultEncoding("UTF-8");
    return multipartResolver;
}

这种方式与XML配置很相似,但提供了更好的类型安全和IDE支持,因为Java配置都是通过标准的Java类进行配置。

3.2 CommonsMultipartResolver的参数详解

了解CommonsMultipartResolver的参数对于正确配置文件上传功能至关重要。

3.2.1 maxUploadSize属性的作用与设置

maxUploadSize 属性用于限制上传文件的最大大小。在实际应用中,这个参数需要根据业务需求和服务器的配置来设置。

  • 如果设置的值太大,可能会导致服务器过载;
  • 如果设置的值太小,则可能限制用户的合法上传需求。

合理的值应结合服务器的内存大小和预期的业务流量来决定。

3.2.2 defaultEncoding属性的配置及其影响

defaultEncoding 属性用于指定文件名的字符编码。通常设置为 UTF-8 ,这能确保文件名在不同语言环境下的一致性和正确性。

不同的编码设置可能会导致在文件上传过程中,中文等特殊字符出现乱码。因此,保证文件名的正确解码对于用户体验至关重要。

3.2.3 其他参数对文件上传的影响

除了 maxUploadSize defaultEncoding 外,CommonsMultipartResolver还有一些其他参数,如:

  • maxInMemorySize :设定当文件小于该值时,文件是否直接保存在内存中;
  • uploadTempDir :设置临时文件存储的目录;
  • resolveLazily :设定是否延迟解析多部分请求。

这些参数提供了额外的配置灵活性,使得CommonsMultipartResolver能够更好地适应不同的应用场景。

通过以上的配置方法和参数解析,开发者可以灵活地在Spring MVC应用中配置文件上传功能,满足各种业务场景的需求。下面的章节会进一步探讨如何在Controller层处理文件上传请求,以及如何创建支持文件上传的前端表单。

4. 文件上传Controller层实现

在文件上传功能中,Controller层起着至关重要的作用,它直接与用户交互,处理请求并调用服务层完成业务逻辑,然后将结果反馈给前端。本章节将深入探讨Controller层在文件上传处理流程中的角色,以及如何实现文件上传的业务逻辑。

4.1 Controller层文件上传的处理流程

4.1.1 请求映射与文件接收

在Spring MVC中,文件上传的请求通常被映射到一个特定的Controller方法上。这一步骤涉及到HTTP请求的接收和MultipartFile对象的处理,MultipartFile是Spring提供的一个接口,用于处理上传的文件。

示例代码
@PostMapping("/upload")
public String handleFileUpload(@RequestParam("file") MultipartFile file, Model model) {
    if (file.isEmpty()) {
        model.addAttribute("message", "Please select a file to upload.");
        return "uploadStatus";
    }
    try {
        // 获取文件信息并进行处理,例如保存到服务器
        String originalFilename = file.getOriginalFilename();
        // ... 文件保存逻辑 ...
    } catch (Exception e) {
        model.addAttribute("message", "Failed to upload file: " + e.getMessage());
        return "uploadStatus";
    }
    model.addAttribute("message", "You successfully uploaded '" + originalFilename + "'");
    return "uploadStatus";
}
代码逻辑分析
  • @PostMapping("/upload") 是一个处理POST请求的映射注解, /upload 是请求的URL。
  • @RequestParam("file") 注解用于从请求中获取名为 file 的文件。
  • MultipartFile file 参数是Spring MVC自动绑定的,代表上传的文件。
  • 方法中首先检查文件是否为空。如果是,则返回错误信息。
  • 使用 file.getOriginalFilename() 获取上传文件的原始文件名。
  • 文件保存逻辑被省略,实际情况中应该将文件保存在服务器上的适当位置。
  • 异常处理通过检查异常信息,并将错误信息返回给前端。

4.1.2 文件信息的获取与处理

当文件成功上传到Controller后,我们常常需要获取文件的元数据信息,比如文件类型、大小、内容等,以便进行进一步的处理或验证。

文件信息处理示例代码
// 假设file已经被定义并包含了一个有效的MultipartFile对象
String contentType = file.getContentType(); // 获取文件MIME类型
long size = file.getSize(); // 获取文件大小,以字节为单位
InputStream inputStream = file.getInputStream(); // 获取文件内容的输入流
参数说明
  • contentType : 该属性获取文件的MIME类型,它可以帮助我们了解文件是图片、视频、文档还是其他类型。
  • size : 获取文件大小,以字节为单位,这对于处理大文件和限制上传文件大小非常有用。
  • inputStream : 通过这个输入流,我们可以读取文件内容。它用于文件的进一步处理,如保存、转换等。

4.2 文件上传的业务逻辑实现

4.2.1 文件上传的业务需求分析

在实际开发中,文件上传往往伴随着特定的业务需求。这些需求可能包括文件大小限制、文件类型检查、安全性校验等。在实现文件上传的Controller层代码时,必须考虑这些需求,并在代码中实现相应的逻辑。

4.2.2 Controller层代码实现及注意事项

根据不同的业务需求,Controller层的实现会有所不同。以下是一些常见的实践和注意事项:

示例代码
@PostMapping("/upload")
public String handleFileUpload(
    @RequestParam("file") MultipartFile file,
    @RequestParam("description") String description,
    Model model) {
    if (file.isEmpty()) {
        model.addAttribute("message", "Please select a file to upload.");
        return "uploadStatus";
    }

    String originalFilename = file.getOriginalFilename();
    String contentType = file.getContentType();
    long size = file.getSize();
    // 业务逻辑:验证文件大小
    if (size > MAX_FILE_SIZE) {
        model.addAttribute("message", "File size is too large.");
        return "uploadStatus";
    }

    // 业务逻辑:验证文件类型
    if (!isValidContentType(contentType)) {
        model.addAttribute("message", "Invalid file type.");
        return "uploadStatus";
    }

    // 文件保存逻辑(省略)
    model.addAttribute("message", "Upload successful for file: " + originalFilename);
    return "uploadStatus";
}
逻辑分析
  • 使用 @RequestParam("description") 来获取用户可能为上传的文件提供的额外描述信息。
  • 验证文件是否为空,然后获取文件的元数据信息。
  • 对文件大小和类型进行了基本的验证,这些可以由业务需求决定。
  • isValidContentType 方法是一个假设的方法,用于检查文件的MIME类型是否被允许。
  • 文件保存逻辑应具体实现文件的存储,例如写入服务器磁盘或云存储服务。

注意事项:

  • 一定要有文件大小和类型的校验,防止恶意上传或错误类型文件的上传。
  • 在实现文件保存时要考虑到线程安全问题,特别是在高并发场景。
  • 应当对上传失败的情况进行适当的错误处理,并给出明确的用户提示。
  • 对于大文件上传,需要考虑到性能优化问题,如分片上传或流式处理。
  • 业务逻辑应当清晰,遵循良好的编程实践,易于维护和扩展。

5. 前端HTML表单创建

5.1 HTML表单与文件上传的关系

5.1.1 表单元素的基础知识

在Web应用中,表单是与用户交互的主要方式之一,它允许用户输入数据并提交给服务器。HTML表单是由 <form> 元素定义的,这个元素可以包含输入字段、标签、按钮等,用户可以填写这些字段然后提交表单。表单处理流程通常包括数据的输入、验证以及最终的提交,而文件上传则是表单提交的一种特殊形式。

文件上传功能要求表单的 enctype 属性必须设置为 multipart/form-data ,这是因为数据将要以二进制流的方式进行传输,而不是常规的 application/x-www-form-urlencoded 编码方式。这种编码方式能够将表单数据编码为名称/值对,这对于文本数据是足够的,但不适用于文件这样的二进制数据。

5.1.2 如何创建支持文件上传的表单

要创建一个支持文件上传的表单,关键在于 <input> 元素的 type 属性。当 type 设置为 file 时,浏览器会提供一个文件选择器,让用户选择本地文件进行上传。同时,表单的 enctype 属性需要被设置为 multipart/form-data

下面是一个简单的示例:

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file" name="fileToUpload" id="fileToUpload">
  <input type="submit" value="Upload File" name="submit">
</form>

在这个例子中,当用户点击上传按钮后,表单会将文件数据以 multipart/form-data 编码方式发送到服务器上的 /upload 路径。在实际开发中,表单可能包含更多的字段,例如用户信息、图片描述等,这些都可以通过额外的输入字段来收集。

5.2 表单的样式与用户体验优化

5.2.1 表单设计的最佳实践

为了提供良好的用户体验,表单设计需要遵循一些最佳实践。以下几点对创建支持文件上传的表单尤为重要:

  • 清晰的标签与提示 :每个 <input> 元素旁边都应该有清晰的标签,让用户知道需要提供什么类型的数据。对于文件上传,应明确指出允许上传的文件类型和大小限制。
  • 即时验证 :在客户端进行即时验证可以快速反馈给用户输入的有效性,减少服务器负载和用户等待时间。
  • 进度指示 :文件上传可能需要一些时间,显示一个上传进度条可以提升用户体验,告知用户当前进度。
  • 兼容性测试 :不同的浏览器和设备可能会有不同的表现,确保在所有目标平台和设备上测试表单的兼容性是必要的。

5.2.2 增强上传体验的前端技巧

要增强上传体验,可以采取以下前端技巧:

  • 拖放上传 :允许用户通过拖放文件到特定区域来上传文件,这可以提高表单的易用性。
  • 文件预览 :在文件上传之前,提供文件的预览功能可以减少无效上传的发生,尤其是对于图片和文档等文件类型。
  • 分步上传 :将上传过程分解为多个步骤可以降低复杂性,例如先选择文件,然后确认上传信息。
  • 响应式设计 :确保表单在移动设备和不同屏幕尺寸下都能正确显示和操作。

接下来,我们将展示如何使用CSS和JavaScript来实现这些用户体验的优化技巧。

6. 文件存储与处理方法

在文件上传的应用中,存储和处理是确保数据完整性和访问效率的关键环节。本章节将深入探讨文件存储策略的选择以及文件处理的高级技术,以实现一个既安全又高效的文件管理机制。

6.1 文件存储策略的选择

文件存储在服务器上,一般有本地存储和分布式存储两种策略可供选择。每种存储方式都有其独特的优势和潜在的风险,选择合适的存储策略对于系统的整体性能和可扩展性至关重要。

6.1.1 本地存储与分布式存储的比较

本地存储 是将文件直接保存在应用服务器的本地磁盘上。这种方式操作简单,读写速度快,但它的可扩展性较差,不适合高并发访问的场景。若文件访问量激增,可能会导致磁盘I/O成为瓶颈。

分布式存储 ,如使用Amazon S3、阿里云OSS或自建的分布式文件系统,能够提供更好的可扩展性,支持高并发访问,但其成本相对较高,并且网络延迟也可能影响性能。对于需要处理大量数据并且对访问速度有一定要求的系统,分布式存储是一个不错的选择。

6.1.2 安全性与性能考量

在选择存储策略时,安全性是不可忽视的因素。无论是本地存储还是分布式存储,都应采取措施来保证文件的安全性,例如使用HTTPS协议来加密传输过程中的数据,以及对敏感数据进行加密存储。

性能方面,本地存储可利用更快的I/O速度和较低的网络延迟,但分布式存储可以通过负载均衡分散请求压力,提高系统的并发处理能力。在文件存储策略选择时,需要根据实际应用场景和需求,权衡成本、安全性和性能,做出最合适的选择。

6.2 文件处理的高级技术

文件上传成功后,往往需要进行一些额外的处理操作,如重命名、目录管理、预览以及安全性校验等。这些操作对用户体验和系统的安全性都有直接的影响。

6.2.1 文件重命名与目录管理

上传的文件通常需要重命名以避免覆盖已存在的同名文件,同时还可以添加时间戳或唯一标识来确保文件名的唯一性。通过在文件名中加入特定的前缀或后缀,也可以方便地按照上传时间和用户进行分类管理。

目录管理是指对上传的文件进行合理组织,通常可以按用户、时间或其他属性来创建不同的目录。目录的管理可以使用文件系统的目录结构,也可以是数据库中的虚拟目录,具体取决于文件存储的方式。

6.2.2 文件预览与安全性校验

为了提高用户体验,某些类型的文件,如图片、文档等,需要提供预览功能。可以通过文件转换工具将这些文件转换为网页可以直接预览的格式,或者通过集成第三方预览服务来实现。

安全性校验是防止恶意文件上传的重要环节。包括但不限于扫描文件的病毒、检查文件类型是否符合白名单、验证文件内容是否含有敏感信息等。这些校验可以在客户端进行,也可以在服务器端完成,具体实现方式取决于系统的安全策略和性能考量。

通过本章节的讨论,我们了解了文件存储策略的选择和文件处理的高级技术。这些知识能够帮助开发者构建出既高效又安全的文件上传系统。在接下来的章节中,我们将进一步探讨文件上传错误处理和验证,确保文件上传的安全性和稳定性。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:在Spring MVC框架中,文件上传是一个常规功能,其中 CommonsMultipartResolver 作为多部分解析器扮演着关键角色。本文深入分析了 CommonsMultipartResolver 的工作原理,并详细说明了如何在Spring MVC中配置和使用它来处理文件上传。包括配置解析器、编写处理文件上传的Controller层代码、前端表单创建、文件存储和处理方法以及错误处理和验证机制,旨在帮助开发者全面理解并实现安全可靠的文件上传功能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

### 回答1: 1. 首先,需要在VSCode中安装C++插件,可以在扩展商店中搜索"C++",然后安装Microsoft官方提供的"C++"插件。 2. 接着,需要在本地安装C++编译器,比如gcc或者clang。可以在终端中输入"g++ --version"或者"clang++ --version"来检查是否已经安装。 3. 在VSCode中打开leetcode题目的文件夹,可以使用"Open Folder"命令,或者直接在终端中进入该文件夹。 4. 在VSCode中打开终端,可以使用"Terminal"菜单或者快捷键"Ctrl + ` "。 5. 在终端中输入命令"touch main.cpp",创建一个名为"main.cpp"的文件。 6. 在VSCode中打开"main.cpp"文件,开始编写代码。 7. 编写完代码后,在终端中输入命令"g++ main.cpp -o main",将代码编译成可执行文件。 8. 在终端中输入命令"./main",运行可执行文件,查看代码是否正确。 9. 如果代码正确,可以将代码提交到leetcode网站进行测试。 ### 回答2: VSCode 是一种非常流行的开源代码编辑器,可以用于编写各种计算机编程语言。LeetCode 是一种学习和练习算法的平台,它提供了许多编程问题和测试数据,使得程序员可以通过解决这些问题来提高编程能力。 为了在 VSCode 上刷 LeetCode,首先我们需要安装 C 语言的编译器和调试器。常见的 C 语言编译器有 gcc 和 clang,它们可以在大多数操作系统上运行,例如 Windows、Mac、Linux 等。同时,为了方便调试,我们可以安装 VSCode 的插件,例如 C/C++、Code Runner 等。 安装好编译器和插件后,我们需要在 VSCode 中创建一个新的 C 语言项目,例如可以在终端中使用命令 `mkdir my_leetcode` 创建一个新的目录,然后在 VSCode 中打开这个目录。接着,在 VSCode 的编辑器中创建一个新的 C 文件,例如 `main.c`,并且在这个文件中编写自己的 LeetCode 解法代码。要注意,我们需要包含正确的头文件,并且使用 main 函数来调用我们编写的算法。 编写完代码后,我们可以使用插件中的 Code Runner 来运行这个程序。在编辑器中按下快捷键 Ctrl+Alt+N,或者通过右键菜单选择 Run Code,就可以编译并运行我们的代码。同时,Code Runner 还可以在终端中显示程序的输出结果,方便调试和查看。 除了 Code Runner,我们还可以使用 VSCode 中内置的调试器来单步运行代码,查看变量的值和程序的执行流程。要使用调试器,我们需要在代码中打断点,然后点击 VSCode 的调试按钮来启动调试器。一旦程序到达断点,就可以逐步进行调试并查看变量的值,从而检查算法的正确性和性能。 总之,使用 VSCode 刷 LeetCode 能够较为方便地进行代码编写、调试和运行。我们只需要安装好对应的编译器和插件,然后按照标准的 C 语言写法来编写算法即可。通过不断地练习和掌握,我们能够更好地提高自己的编程水平和算法思维能力。 ### 回答3: VSCode是一种轻量级的代码编辑器,可以为编写代码提供丰富的功能和工具。它具有强大的语法高亮功能,可以轻松地切换不同的语言模式。对于刷leetcode来说,VSCode可以作为一个开发环境使用,主要有以下几个步骤: 第一步,安装和配置C/C++插件。在VSCode中,您需要安装一个C/C++插件,它可以用来编写和调试C/C++代码。安装该插件后,您需要根据自己的需求进行配置模板,以便更好地适应您的编程风格。 第二步,安装leetcode插件。为了方便,您可以通过在VSCode中安装leetcode插件,轻松访问leetcode网站并刷题。该插件提供了很多实用功能,包括搜索和筛选题目,提交代码并获得反馈等。 第三步,编写代码。通过安装C/C++插件,您可以在VSCode中轻松编写C/C++代码。在刷leetcode时,您可以使用VSCode的一些功能,例如代码折叠、语法高亮、代码补全等。 第四步,调试代码。VSCode中的C/C++插件还提供了一个非常强大的调试工具,可以帮助您调试C/C++代码。您可以在断点处暂停代码执行,查看变量值和堆栈信息等。这将大大简化调试过程。 总之,VSCode作为一个轻量级代码编辑器,具有强大的功能和工具,可以帮助您更轻松地刷leetcode。安装C/C++和leetcode插件以及适当的配置,可以大大提高您的编程效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值