springMVC面经

1. 什么是MVC?

在这里插入图片描述

用户的请求会到达 Servlet,然后根据请求调用相应的 Java Bean,并把所有的显示结果交给 JSP 去完成,这样的模式我们就称为 MVC 模式。

MVC是一种设计模式,在这种模式下软件被分为三层,即Model(模型)、View(视图)、Controller(控制器)。Model代表的是数据,View代表的是用户界面,Controller代表的是数据的处理逻辑,它是Model和View这两层的桥梁。将软件分层的好处是,可以将对象之间的耦合度降低,便于代码的维护。
MVC是一种软件架构的思想,将软件按照模型、视图、控制器来划分

M:Model,模型层,指工程中的JavaBean,作用是处理数据 dao,bean

JavaBean分为两类:

一类称为实体类Bean:专门存储业务数据的,如 Student、User 等
一类称为业务处理 Bean:指 Service 或 Dao 对象,专门用于处理业务逻辑和数据访问。

V:View,视图层,指工程中的html或jsp等页面,作用是与用户进行交互,展示数据

C:Controller,控制层,指工程中的servlet,作用是接收请求和响应浏览器

MVC的工作流程:

用户通过视图层发送请求到服务器,在服务器中请求被Controller接收,Controller调用相应的Model层处理请求,处理完毕将结果返回到Controller,Controller再根据请求处理的结果找到相应的View视图,渲染数据后最终响应给浏览器

1.1 什么是SpringMVC

Spring MVC 是一个基于 Java 的实现了 MVC 设计模式的请求驱动类型的轻量级 Web 框架,通过把 Model,View,Controller 分离,将 web 层进行职责解耦,把复杂的 web 应用分成逻辑清晰的几部分,简化开发,减少出错,方便组内开发人员之间的配合

SpringMVC是Spring的一个后续产品,是Spring的一个子项目

SpringMVC 是 Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 Strust、WebWork、Strust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案。

注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台servlet

1.2 SpringMVC的特点

  • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
  • 基于原生的Servlet,通过了功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理
  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
  • 代码清新简洁,大幅度提升开发效率
  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可
  • 性能卓著,尤其适合现代大型、超大型互联网项目要求

2. DAO层是做什么的?

DAO是Data Access Object的缩写,即数据访问对象,在项目中它通常作为独立的一层,专门用于访问数据库。这一层的具体实现技术有很多,常用的有Spring JDBC、Hibernate、JPA、MyBatis等,在Spring框架下无论采用哪一种技术访问数据库,它的编程模式都是统一的。

3. 介绍一下Spring MVC的执行流程

  • 整个过程开始于客户端发出的一个HTTP请求,Web应用服务器接收到这个请求。如果匹配DispatcherServlet的请求映射路径,则Web容器将该请求转交给DispatcherServlet处理。

  • DispatcherServlet接收到这个请求后,将根据请求的信息(包括URL、HTTP方法、请求报文头、请求参数、Cookie等)及HandlerMapping的配置找到处理请求的处理器(Handler)。可将HandlerMapping看做路由控制器,将Handler看做目标主机。值得注意的是,在Spring MVC中并没有定义一个Handler接口,实际上任何一个Object都可以成为请求处理器。

  • 当DispatcherServlet根据HandlerMapping得到对应当前请求的Handler后,通过HandlerAdapter对Handler进行封装,再以统一的适配器接口调用Handler。HandlerAdapter是Spring MVC框架级接口,顾名思义,HandlerAdapter是一个适配器,它用统一的接口对各种Handler方法进行调用。

  • 处理器完成业务逻 辑的处理后,将返回一个ModelAndView给DispatcherServlet,ModelAndView包含了视图逻辑名和模型数据信息。

  • ModelAndView中包含的是“逻辑视图名”而非真正的视图对象,DispatcherServlet借由ViewResolver完成逻辑视图名到真实视图对象的解析工作。

  • 当得到真实的视图对象View后,DispatcherServlet就使用这个View对象对ModelAndView中的模型数据进行视图渲染。

  • 最终客户端得到的响应消息可能是一个普通的HTML页面,也可能是一个XML或JSON串,甚至是一张图片或一个PDF文档等不同的媒体形式。

4. 说一说你知道的Spring MVC注解

  • @RequestMapping:

    作用:该注解的作用就是用来处理请求地址映射的,也就是说将其中的处理器方法映射到url路径上。

    属性:

    method:是让你指定请求的method的类型,比如常用的有get和post。

    value:是指请求的实际地址,如果是多个地址就用{}来指定就可以啦。

    produces:指定返回的内容类型,当request请求头中的Accept类型中包含指定的类型才可以返回的。

    consumes:指定处理请求的提交内容类型,比如一些json、html、text等的类型。

    headers:指定request中必须包含那些的headed值时,它才会用该方法处理请求的。

    params:指定request中一定要有的参数值,它才会使用该方法处理请求。

  • @RequestParam:

    作用:是将请求参数绑定到你的控制器的方法参数上,是Spring MVC中的接收普通参数的注解。

    属性:

    value是请求参数中的名称。

    required是请求参数是否必须提供参数,它的默认是true,意思是表示必须提供。

  • @RequestBody:

    作用:如果作用在方法上,就表示该方法的返回结果是直接按写入的Http responsebody中(一般在异步获取数据时使用的注解)。

    属性:required,是否必须有请求体。它的默认值是true,在使用该注解时,值得注意的当为true时get的请求方式是报错的,如果你取值为false的话,get的请求是null。

  • @PathVaribale:

    作用:该注解是用于绑定url中的占位符,但是注意,spring3.0以后,url才开始支持占位符的,它是Spring MVC支持的rest风格url的一个重要的标志。

5. 介绍一下Spring MVC的拦截器

拦截器会对处理器进行拦截,这样通过拦截器就可以增强处理器的功能。Spring MVC中,所有的拦截器都需要实现HandlerInterceptor接口,该接口包含如下三个方法:preHandle()、postHandle()、afterCompletion()。

这些方法的执行流程如下图:
在这里插入图片描述

  • 通过上图可以看出,Spring MVC拦截器的执行流程如下:

    执行preHandle方法,它会返回一个布尔值。如果为false,则结束所有流程,如果为true,则执行下一步。

    执行处理器逻辑,它包含控制器的功能。

    执行postHandle方法。

    执行视图解析和视图渲染。

    执行afterCompletion方法。

  • Spring MVC拦截器的开发步骤如下:

    开发拦截器:

      实现handlerInterceptor接口,从三个方法中选择合适的方法,实现拦截时要执行的具体业务逻辑。
    

    注册拦截器:

      定义配置类,并让它实现WebMvcConfigurer接口,在接口的addInterceptors方法中,
      注册拦截器,并定义该拦截器匹配哪些请求路径。
    

6. 怎么去做请求拦截?

参考答案

如果是对Controller记性拦截,则可以使用Spring MVC的拦截器。

如果是对所有的请求(如访问静态资源的请求)进行拦截,则可以使用Filter。

如果是对除了Controller之外的其他Bean的请求进行拦截,则可以使用Spring AOP。

补充

1、转发和重定向的区别

转发和重定向的区别及使用方法(全)

SpringMVC中的视图是View接口,视图的作用渲染数据,将模型Model中的数据展示给用户

SpringMVC视图的种类很多,默认有转发视图重定向视图

  • 转发是一次请求,第一次是浏览器法发送(第二次是发生在服务器内部),我们说的一次是浏览器发送的一次请求。(因为第二次是发生在服务器内部,所以转发的地址栏还是第一次请求的地址栏)

  • 重定向是两次请求,第一次是访问servlet,第二次是访问重定向的地址。(最终的地址栏地址是重定向的地址)

  • 转发可以获取请求域中的数据,重定向不可以,因为转发是一次请求,用到的request是同一个。
    重定向浏览器发两次请求,两次请求就是两个request对象

  • 转发可以访问web-inf里的对象,重定向不行,因为web-inf有安全性,只能通过服务器访问,不能通过浏览器访问

  • 转发不能跨域,重定向可以。跨域也就是说 转发发生在服务器内部,只能访问服务器内部的资源。重定向可以访问外部资源,比如重定向到百度

1.1、ThymeleafView

当控制器方法中所设置的视图名称没有任何前缀时,此时的视图名称会被SpringMVC配置文件中所配置的视图解析器解析,视图名称拼接视图前缀和视图后缀所得到的最终路径,会通过转发的方式实现跳转

1.2、转发视图(用的很少)-- 前缀"forward:"

SpringMVC中默认的转发视图是InternalResourceView

SpringMVC中创建转发视图的情况:

当控制器方法中所设置的视图名称以"forward:"为前缀时,创建InternalResourceView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"forward:"去掉,剩余部分作为最终路径通过转发的方式实现跳转

例如"forward:/",“forward:/employee”

<a th:href="@{/testForward}">测试InternalResourceView</a><br>
@RequestMapping("/testForward")
    public String testForward(){
        return "forward:/testThymeleafView";
    }

1.3、重定向视图(用的多)-- 前缀"redirect:"

SpringMVC中默认的重定向视图是RedirectView

当控制器方法中所设置的视图名称以"redirect:"为前缀时,创建RedirectView视图,此时的视图名称不会被SpringMVC配置文件中所配置的视图解析器解析,而是会将前缀"redirect:"去掉,剩余部分作为最终路径通过重定向的方式实现跳转

例如"redirect:/",重定向到首页
“redirect:/employee”

<a th:href="@{/testRedirect}">测试RedirectView</a><br>
 @RequestMapping("/testRedirect")
    public String testRedirect(){
        return "redirect:/testThymeleafView";
    }

2、RESTful(一种软件架构的风格,也就是格式)

用也行,不用也行
RESTFul从入门到精通超全解析(全)

1、RESTful简介
REST:Representational State Transfer,表现层资源状态转移。

2、RESTful的实现
具体说,就是 HTTP 协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。

它们分别对应四种基本操作:GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源。

REST 风格提倡 URL 地址使用统一的风格设计,从前到后各个单词使用斜杠分开,不使用问号键值对方式携带请求参数,而是将要发送给服务器的数据作为 URL 地址的一部分,以保证整体风格的一致性。
在这里插入图片描述

3、HiddenHttpMethodFilter

由于浏览器只支持发送get和post方式的请求,那么该如何发送put和delete请求呢?

SpringMVC 提供了 HiddenHttpMethodFilter 帮助我们将 POST 请求转换为 DELETE 或 PUT 请求

HiddenHttpMethodFilter 处理put和delete请求的条件:

a>当前请求的请求方式必须为post

b>当前请求必须传输请求参数_method

满足以上条件,HiddenHttpMethodFilter 过滤器就会将当前请求的请求方式转换为请求参数_method的值,因此请求参数_method的值才是最终的请求方式

<form th:action="@{/user}" method="post">  
    <input type="hidden" name="_method" value="PUT">
    用户名:<input type="text" name="username"><br>
    密码:<input type="password" name="password"><br>
    <input type="submit" value="修改"><br>
</form>
@RequestMapping(value = "/user", method = RequestMethod.PUT)
    public String updateUser(String username, String password){
        System.out.println("修改用户信息:"+username+","+password);
        return "success";
    }

4、HttpMessageConverter

HttpMessageConverter,报文信息转换器,将请求报文转换为Java对象,或将Java对象转换为响应报文

HttpMessageConverter提供了两个注解和两个类型:@RequestBody,@ResponseBody,RequestEntity,ResponseEntity

HttpMessageConverter提供了两个注解和两个类型:

@RequestBody,RequestEntity
@ResponseBody,ResponseEntity

@ResponseBody(用的多)用于标识控制器方法
@ResponseBody用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器

<a th:href="@{/testResponseBody}">通过@ResponseBody响应浏览器数据</a><br>
@RequestMapping("/testResponseBody")
@ResponseBody
public String testResponseBody(){
    return "success"; //响应给浏览器的数据,也就是响应到浏览器的响应体

结果:浏览器页面显示success,不再跳转到success.html页面了

4.1 问题提出:@ResponseBody直接响应浏览器User对象报错

因为不是字符串数据,浏览器接受服务器的响应数据必须是字符串格式

4.2、SpringMVC处理json(解决 4.1 问题)

注意:实体类、map转换为json是json对象,list转换为json是json数组

@ResponseBody处理json的步骤:

a>导入jackson的依赖

b>在SpringMVC的核心配置文件中开启mvc的注解驱动,此时在HandlerAdaptor中会自动装配一个消息转换器:MappingJackson2HttpMessageConverter,可以将响应到浏览器的Java对象转换为Json格式的字符串

<mvc:annotation-driven />

c>在处理器方法上使用@ResponseBody注解进行标识

d>将Java对象直接作为控制器方法的返回值返回,就会自动转换为Json格式的字符串

@RequestMapping("/testResponseUser")
@ResponseBody
public User testResponseUser(){
    return new User(1001,"admin","123456",23,"男");
}

浏览器的页面中展示的结果:

{“id”:1001,“username”:“admin”,“password”:“123456”,“age”:23,“sex”:“男”}

4.3、SpringMVC处理ajax

ajax是页面不发生跳转的情况下与服务器交互

4.4、@RestController注解

@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解

4.5、ResponseEntity(用的多)

ResponseEntity用于控制器方法的返回值类型,该控制器方法的返回值就是响应到浏览器的响应报文

5、拦截器

简介
控制器controller(也叫处理器),控制器方法被调用之后返回的是统一的ModelandView对象。

拦截器是拦截控制器方法的,拦截器的三个抽象方法一个在控制器方法执行之前、一个在控制器方法执行之后、一个在渲染视图完毕之后。

5.1、拦截器的配置

SpringMVC中的拦截器用于拦截控制器方法的执行

SpringMVC中的拦截器需要实现HandlerInterceptor接口

SpringMVC的拦截器必须在SpringMVC的配置文件中进行配置:

注意:一个bean就是ioc容器中的一个组件,一个对象。

5.2、拦截器的三个抽象方法

SpringMVC中的拦截器有三个抽象方法:

preHandle:控制器方法执行之前执行preHandle(),其boolean类型的返回值表示是否拦截或放行,返回true为放行,即调用控制器方法;返回false表示拦截,即不调用控制器方法

postHandle:控制器方法执行之后执行postHandle()

afterComplation:处理完视图和模型数据,渲染视图完毕之后执行afterComplation()

5.3、 若每个拦截器的preHandle()都返回true

此时多个拦截器的执行顺序和拦截器在SpringMVC的配置文件的配置顺序有关:

preHandle()会按照配置的顺序执行,
而postHandle()和afterComplation()会按照配置的反序执行

5.4、 若某个拦截器的preHandle()返回了false

preHandle()返回false和它之前的拦截器的preHandle()都会执行,
postHandle()都不执行,
返回false的拦截器之前的拦截器的afterComplation()会执行

假如有5个拦截器,现在第3个preHandle()设置了false,那么1,2,3拦截器的preHandle()都会执行;postHandle()都不执行;拦截器2的afterComplation()会执行

6、异常处理器

6.1、基于配置的异常处理

SpringMVC提供了一个处理控制器方法执行过程中所出现的异常的接口:HandlerExceptionResolver

HandlerExceptionResolver接口的实现类有:DefaultHandlerExceptionResolver和SimpleMappingExceptionResolver

SpringMVC提供了自定义的异常处理器SimpleMappingExceptionResolver,

6.2、基于注解的异常处理

@ControllerAdvice将当前类标识为异常处理的组件,@ControllerAdvice这个和@component都是差不多标识组件的意思

@ExceptionHandler用于设置所标识方法处理的异常

ex表示当前请求处理中出现的异常对象

//@ControllerAdvice将当前类标识为异常处理的组件
@ControllerAdvice
public class ExceptionController {

    //@ExceptionHandler用于设置所标识方法处理的异常
    @ExceptionHandler(ArithmeticException.class)
    //ex表示当前请求处理中出现的异常对象
    public String handleArithmeticException(Exception ex, Model model){
        model.addAttribute("ex", ex);
        return "error";
    }

}

7、SpringMVC的执行流程

在这里插入图片描述

简洁版流程

1、 用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器

拦截器(如果有则生成)一并返回给DispatcherServlet。

4、 DispatcherServlet调用HandlerAdapter处理器适配器。

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、 Controller执行完成返回ModelAndView。

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、 ViewReslover解析后返回具体View。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。

8、SpringMVC常用组件

  • DispatcherServlet:前端控制器,不需要工程师开发,由框架提供

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

  • HandlerMapping:处理器映射器,不需要工程师开发,由框架提供

作用:根据请求的url、method等信息查找Handler,即控制器方法

  • Handler:处理器,需要工程师开发

作用:在DispatcherServlet的控制下Handler对具体的用户请求进行处理

  • HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供

作用:通过HandlerAdapter对处理器(控制器方法)进行执行

  • ViewResolver:视图解析器,不需要工程师开发,由框架提供

作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView

  • View:视图

作用:将模型数据通过页面展示给用户

9、DispatcherServlet初始化过程

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。

a>初始化WebApplicationContext
b>创建WebApplicationContext
c>DispatcherServlet初始化策略

FrameworkServlet创建WebApplicationContext后,刷新容器,调用onRefresh(wac),此方法在DispatcherServlet中进行了重写,调用了initStrategies(context)方法,初始化策略,即初始化DispatcherServlet的各个组件

10、Spring MVC 十一个处理流程的详细解释?

  1. 浏览器发送请求,请求具体发到谁呢?先发到前端控制器,也就是说所有的请求都给发到前端控制器,前端控制器是所有请求的入口,但前端控制器不能处理业务请求,它只是一个请求的转发
  2. 谁来处理业务请求呢?Handler 处理器来真正处理业务请求,那么问题来了,前端控制器如何来找到这个 Handler 处理器呢?处理器映射器记录的就是请求的 url 和处理的方法之间的映射关系,这个映射关系是怎么建立起来的呢?就是通过 @RequestMapping 这个注解来建立起来的,这个映射关系就相当于一个 Map(key-value 这种形式),key 就是请求的 url,value 就是处理的 Handler。现在,前端控制器拿到这个请求之后,要找到对应的 Handler,怎么找呢?就要找处理器映射器,问它请求谁来处理?
  3. 处理器映射器会根据你请求的 url 来找对应的处理器,找不到就会报错,如果找到之后,这时,它就会返回一个处理器执行链,这个处理器执行链里面除了有 Handler 之外,还有拦截器(这儿我们可以开发自己的拦截器),然后返回给前端控制器
  4. 前端控制器依然不能处理这个业务请求,它这时做的还有另外一件事情,因为返回 Handler,它也不知道这个 Handler 是什么类型,因为在 springmvc 中 Handler 除了可以是注解形式的之外,其实还可以是非注解形式的(非注解形式我们一般不用),前端控制器并不知道这个 Handler 到底是什么类型的,那就没办法执行它,那总得找个东西执行,这时它就会把这个事交给另外一个组件来处理,这个组件就叫处理器适配器,这个处理器适配器就是来适配不同类型的 Handler。它就会根据你不同类型的 Handler 来选择不同类型的适配器来执行它
  5. 假如当前 Handler 是注解形式的,那么它就会选择注解形式的处理器适配器来执行这个 Handler。Handler 就执行了,也就是说我们 Controller 类中的那个方法就执行了,方法执行之后,里面的业务就处理了
  6. 业务处理之后,最后返回一个 ModelAndView。处理器适配器拿到这个结果是没有用的,它的作用就是执行这个 Handler,把这个 Handler 执行完之后,它的事就做完了
  7. 做完之后,拿到这个返回结果,那么它会原封不动地把这个返回结果扔给前端控制器,这时处理器适配器的事就做完了
  8. 前端控制器拿到这个 ModelAndView,它还是没有办法处理,它还是不能返回 html,这时它要找到相应的 jsp,因为 ModelAndView 即包含模型又包含视图,这个视图指定我们要用谁来渲染这个数据。我们要渲染数据,这时它就要找一个视图解析器来解析这个视图,由于这个视图也有很多种(我们最常见的视图是 jsp,除了 jsp,其实还有其他的,比如说还可以是报表,还可以是 pdf,还可以是 freemaker 等),它会找不同的视图解析器来处理。因为现在我们最常用的视图是 jsp,所以它就找到 jsp 对应的视图解析器
  9. 找到这个视图解析器,它来把这个视图解析,解析完了之后它会返回一个 View 对象
  10. 最后我们再调用这个视图解析器的渲染视图这个过程,渲染视图这个过程其实就是对于我们的 jsp 来说,就是把这个数据渲染成 html
  11. 最终渲染成 html 之后,就响应给用户

11、 Spring MVC 的控制器是不是单例模式?存在什么问题?怎么解决?

是单例模式。所以在多线程访问的时候有线程安全问题。不要用同步,会影响性能的,解决方案是在控制器里面不能写字段

12、 Spring MVC 常用的注解?

@RequestMapping:用于处理请求 url 映射的注解,可用于类或方法上。用于类上,则表示类中的所有响应请求的方法都是以该地址作为父路径
@RequestBody:注解实现接收 http 请求的 json 数据,将 json 转换为 java 对象
@ResponseBody:注解实现将 conreoller 方法返回对象转化为 json 对象响应给客户

13 、如何在拦截请求中拦截 get 方式提交的方法?

在 @RequestMapping 注解里面加上 method=RequestMethod.GET

14、 如何在方法中得到 Request 或 Session?

直接在方法的形参中声明 request,Spring MVC 就自动把 request 对象传入

15、 如何在拦截的方法里得到从前台传入的参数?

直接在形参里面声明这个参数即可,但名字必须和传过来的参数一样

16、 如果前台有很多个参数传入,并且这些参数都是一个对象的,如何得到这个对象?

直接在方法中声明这个对象即可,Spring MVC 就自动会把属性赋值到这个对象里面

17、 Spring MVC 中函数的返回值是什么?

返回值可以有很多类型,例如 String,ModelAndView。ModelAndView 把视图和数据合并在一起,但一般用 String 比较好

18 、Spring MVC 如何实现一个拦截器?

一是实现 HandlerInterceptor 接口,一是继承适配器类

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农小C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值