SpringMVC(一)---应用

1. Spring简介

1.1 MVC 体系结构

三层架构

我们的开发架构⼀般都是基于两种形式,⼀种是 C/S 架构,也就是客户端/服务器;另⼀种是 B/S 架构,也就是浏览器服务器。在 JavaEE 开发中,⼏乎全都是基于 B/S 架构的开发。那么在 B/S 架构中,系统标准的三层架构包括:表现层、业务层、持久层。三层架构在我们的实际开发中使⽤的⾮常多,所以我们课程中的案例也都是基于三层架构设计的。

  • 表现层 :也就是我们常说的web 层。它负责接收客户端请求,向客户端响应结果,通常客户端使⽤http 协议请求web 层,web 需要接收 http 请求,完成 http 响应。
    表现层包括展示层和控制层:控制层负责接收请求,展示层负责结果的展示。
    表现层依赖业务层,接收到客户端请求⼀般会调⽤业务层进⾏业务处理,并将处理结果响应给客户端。
    表现层的设计⼀般都使⽤ MVC 模型。(MVC 是表现层的设计模型,和其他层没有关系)
  • 业务层 :也就是我们常说的 service 层。它负责业务逻辑处理,和我们开发项⽬的需求息息相关。web 层依赖业务层,但是业务层不依赖 web 层。
    业务层在业务处理时可能会依赖持久层,如果要对数据持久化需要保证事务⼀致性。(也就是我们说的, 事务应该放到业务层来控制)
  • 持久层 :也就是我们是常说的 dao 层。负责数据持久化,包括数据层即数据库和数据访问层,数据库是对数据进⾏持久化的载体,数据访问层是业务层和持久层交互的接⼝,业务层需要通过数据访问层将数据持久化到数据库中。通俗的讲,持久层就是和数据库交互,对数据库表进⾏增删改查的。

MVC设计模式

MVC 全名是 Model View Controller,是 模型(model)-视图(view)-控制器(controller) 的缩写, 是⼀种⽤于设计创建 Web 应⽤程序表现层的模式。MVC 中每个部分各司其职:

  • Model(模型):模型包含业务模型和数据模型,数据模型⽤于封装数据,业务模型⽤于处理业务。
  • View(视图): 通常指的就是我们的 jsp 或者 html。作⽤⼀般就是展示数据的。通常视图是依据模型数据创建的。
  • Controller(控制器): 是应⽤程序中处理⽤户交互的部分。作⽤⼀般就是处理程序逻辑的。
    MVC提倡:每⼀层只编写⾃⼰的东⻄,不编写任何其他的代码;分层是为了解耦,解耦是为了维护⽅便和分⼯协作。

1.2 Spring MVC 是什么?

SpringMVC 全名叫 Spring Web MVC,是⼀种基于 Java 的实现 MVC 设计模型的请求驱动类型的轻量级Web 框架,属于 SpringFrameWork 的后续产品。
SpringMVC 已经成为 ⽬前最主流的 MVC 框架 之⼀,并且 随着 Spring3.0 的发布,全⾯超越 Struts2,成为最优秀的 MVC 框架。servlet、struts实现接⼝、springmvc中要让⼀个java类能够处理请求只需要添加注解就ok
它通过⼀套注解,让⼀个简单的 Java 类成为处理请求的控制器,⽽⽆须实现任何接⼝。同时它还⽀持RESTful 编程⻛格的请求。
总之:Spring MVC和Struts2⼀样,都是 为了解决表现层问题 的web框架,它们都是基于 MVC 设计模式的。⽽这些表现层框架的主要职责就是处理前端HTTP请求。
Spring MVC 本质可以认为是对servlet的封装,简化了我们serlvet的开发
作⽤:1)接收请求 2)返回响应,跳转⻚⾯
在这里插入图片描述

2. Spring Web MVC ⼯作流程

开发过程:

1)配置DispatcherServlet前端控制器

<servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

2)开发处理具体业务逻辑的Handler(@Controller、@RequestMapping)

@Controller
@RequestMapping("/demo")
public class DemoController {

    @RequestMapping("/handle01")
    public ModelAndView handle01(){
        Date date = new Date();

        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("date",date);
        //逻辑视图名
        modelAndView.setViewName("sucess");
        return modelAndView;
    }
}

3)xml配置⽂件配置controller扫描,配置springmvc三⼤件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
            http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd
            http://www.springframework.org/schema/mvc
            http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--    开启controller扫描-->
    <context:component-scan base-package="com.lagou.edu.controller" />

<!--       配置springmvc视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>

    </bean>


<!--    springmvc三大件:Spring视图解析器,处理映射器,处理适应器-->
    <mvc:annotation-driven/>
</beans>

4)将xml⽂件路径告诉springmvc(DispatcherServlet)

<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>

    </bean>
  • web.xml
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:springmvc.xml</param-value>
    </init-param>
  </servlet>
<!-- 路径拦截,交给springmvc处理 -->
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>

    <!--
      方式一:带后缀,比如*.action  *.do *.aaa
             该种方式比较精确、方便,在以前和现在企业中都有很大的使用比例
      方式二:/ 不会拦截 .jsp,但是会拦截.html等静态资源(静态资源:除了servlet和jsp之外的js、css、png等)

            为什么配置为/ 会拦截静态资源???
                因为tomcat容器中有一个web.xml(父),你的项目中也有一个web.xml(子),是一个继承关系
                      父web.xml中有一个DefaultServlet,  url-pattern 是一个 /
                      此时我们自己的web.xml中也配置了一个 / ,覆写了父web.xml的配置
            为什么不拦截.jsp呢?
                因为父web.xml中有一个JspServlet,这个servlet拦截.jsp文件,而我们并没有覆写这个配置,
                所以springmvc此时不拦截jsp,jsp的处理交给了tomcat


            如何解决/拦截静态资源这件事?


      方式三:/* 拦截所有,包括.jsp
    -->
    <!--拦截匹配规则的url请求,进入springmvc框架处理-->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

/**
     * url: http://localhost:8080/demo/handle01
     */
    @RequestMapping("/handle01")
    public ModelAndView handle01(@ModelAttribute("name") String name) {

        int c = 1/0;


        Date date = new Date();// 服务器时间
        // 返回服务器时间到前端页面
        // 封装了数据和页面信息的 ModelAndView
        ModelAndView modelAndView = new ModelAndView();
        // addObject 其实是向请求域中request.setAttribute("date",date);
        modelAndView.addObject("date",date);
        // 视图信息(封装跳转的页面信息) 逻辑视图名
        modelAndView.setViewName("success");
        return modelAndView;
    }

    /**
     * SpringMVC在handler方法上传入Map、Model和ModelMap参数,并向这些参数中保存数据(放入到请求域),都可以在页面获取到
     *
     * 它们之间是什么关系?
     * 运行时的具体类型都是BindingAwareModelMap,相当于给BindingAwareModelMap中保存的数据都会放在请求域中
     *
     *  Map(jdk中的接口)        Model(spring的接口)
     *
     *  ModelMap(class,实现Map接口)
     *
     *
     *
     *
     *              BindingAwareModelMap继承了ExtendedModelMap,ExtendedModelMap继承了ModelMap,实现了Model接口
     *
     */




    /**
     * 直接声明形参ModelMap,封装数据
     * url: http://localhost:8080/demo/handle11
     *
     * =================modelmap:class org.springframework.validation.support.BindingAwareModelMap
     */
    @RequestMapping("/handle11")
    public String handle11(ModelMap modelMap) {
        Date date = new Date();// 服务器时间
        modelMap.addAttribute("date",date);
        System.out.println("=================modelmap:" + modelMap.getClass());
        return "success";
    }


    /**
     * 直接声明形参Model,封装数据
     * url: http://localhost:8080/demo/handle12
     * =================model:class org.springframework.validation.support.BindingAwareModelMap
     */
    @RequestMapping("/handle12")
    public String handle12(Model model) {
        Date date = new Date();
        model.addAttribute("date",date);
        System.out.println("=================model:" + model.getClass());
        return "success";
    }


    /**
     * 直接声明形参Map集合,封装数据
     * url: http://localhost:8080/demo/handle13
     * =================map:class org.springframework.validation.support.BindingAwareModelMap
     */
    @RequestMapping("/handle13")
    public String handle13(Map<String,Object> map) {
        Date date = new Date();
        map.put("date",date);
        System.out.println("=================map:" + map.getClass());
        return "success";
    }
  • springmvc.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd
">

    
    <!--开启controller扫描-->
    <context:component-scan base-package="com.lagou.edu.controller"/>


    <!--配置springmvc的视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>


    <!--
        自动注册最合适的处理器映射器,处理器适配器(调用handler方法)
    -->
    <mvc:annotation-driven conversion-service="conversionServiceBean"/>


    <!--注册自定义类型转换器-->
    <bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="com.lagou.edu.converter.DateConverter"></bean>
            </set>
        </property>
    </bean>


    <!--静态资源配置,方案一-->
    <!--
        原理:添加该标签配置之后,会在SpringMVC上下文中定义一个DefaultServletHttpRequestHandler对象
             这个对象如同一个检查人员,对进入DispatcherServlet的url请求进行过滤筛查,如果发现是一个静态资源请求
             那么会把请求转由web应用服务器(tomcat)默认的DefaultServlet来处理,如果不是静态资源请求,那么继续由
             SpringMVC框架处理
             
    -->
    <!--<mvc:default-servlet-handler/>-->



    <!--静态资源配置,方案二,SpringMVC框架自己处理静态资源
        mapping:约定的静态资源的url规则
        location:指定的静态资源的存放位置

    -->
    <mvc:resources location="classpath:/"  mapping="/resources/**"/>
    <mvc:resources location="/WEB-INF/js/" mapping="/js/**"/>


    <mvc:interceptors>
        <!--拦截所有handler-->
        <!--<bean class="com.lagou.edu.interceptor.MyIntercepter01"/>-->
        
        <mvc:interceptor>
            <!--配置当前拦截器的url拦截规则,**代表当前目录下及其子目录下的所有url-->
            <mvc:mapping path="/**"/>
            <!--exclude-mapping可以在mapping的基础上排除一些url拦截-->
            <!--<mvc:exclude-mapping path="/demo/**"/>-->
            <bean class="com.lagou.edu.interceptor.MyIntercepter01"/>
        </mvc:interceptor>


        <mvc:interceptor>
            <mvc:mapping path="/**"/>
            <bean class="com.lagou.edu.interceptor.MyIntercepter02"/>
        </mvc:interceptor>
        
    </mvc:interceptors>


    <!--多元素解析器
        id固定为multipartResolver
    -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!--设置上传文件大小上限,单位是字节,-1代表没有限制也是默认的-->
        <property name="maxUploadSize" value="5000000"/>
    </bean>

</beans>

2.1 Spring MVC 请求处理流程

在这里插入图片描述

  • 流程说明
    第⼀步:⽤户发送请求⾄前端控制器DispatcherServlet
    第⼆步:DispatcherServlet收到请求调⽤HandlerMapping处理器映射器
    第三步:处理器映射器根据请求Url找到具体的Handler(后端控制器),⽣成处理器对象及处理器拦截器(如果 有则⽣成)⼀并返回DispatcherServlet
    第四步:DispatcherServlet调⽤HandlerAdapter处理器适配器去调⽤Handler
    第五步:处理器适配器执⾏Handler
    第六步:Handler执⾏完成给处理器适配器返回ModelAndView
    第七步:处理器适配器向前端控制器返回 ModelAndView,ModelAndView 是SpringMVC 框架的⼀个底层对 象,包括 Model 和 View
    第⼋步:前端控制器请求视图解析器去进⾏视图解析,根据逻辑视图名来解析真正的视图。
    第九步:视图解析器向前端控制器返回View
    第⼗步:前端控制器进⾏视图渲染,就是将模型数据(在 ModelAndView 对象中)填充到 request 域
    第⼗⼀步:前端控制器向⽤户响应结果

3. 请求参数绑定(串讲)

请求参数绑定:说⽩了SpringMVC如何接收请求参数

http协议(超⽂本传输协议): 他的意思就是所有得文件传输都是文本类型

接收时用字符串接收然后再用字符串类型转换成其他类型

原⽣servlet接收⼀个整型参数:
1)String ageStr = request.getParameter(“age”);
2) Integer age = Integer.parseInt(ageStr);
SpringMVC框架对Servlet的封装,简化了servlet的很多操作
SpringMVC在接收整型参数的时候,直接在Handler⽅法中声明形参即可
@RequestMapping(“xxx”)
public String handle(Integer age) {
System.out.println(age);
}
参数绑定:取出参数值绑定到handler⽅法的形参上

  • 默认⽀持 Servlet API 作为⽅法参数
    当需要使⽤HttpServletRequest、HttpServletResponse、HttpSession等原⽣servlet对象时,直接在handler⽅法中形参声明使⽤即可。
/** 
* 
* SpringMVC 对原⽣servlet api的⽀持 url:/demo/handle02?id=1 
* 
* 如果要在SpringMVC中使⽤servlet原⽣对象,⽐如
HttpServletRequest\HttpServletResponse\HttpSession,直接在Handler⽅法形参中声
明使⽤即可 
* 
*/ 
@RequestMapping("/handle02")
public ModelAndView handle02(HttpServletRequest request, HttpServletResponse response,HttpSession session) {
	 String id = request.getParameter("id");
	 Date date = new Date();
	 ModelAndView modelAndView = new ModelAndView();
	 modelAndView.addObject("date",date);
	 modelAndView.setViewName("success");
	 return modelAndView;
}
  • 绑定简单类型参数
    简单数据类型:⼋种基本数据类型及其包装类型
    参数类型推荐使⽤包装数据类型,因为基础数据类型不可以为null
    整型:Integer、int
    字符串:String
    单精度:Float、float
    双精度:Double、double
    布尔型:Boolean、boolean
    说明:对于布尔类型的参数,请求的参数值为true或false。或者1或0

注意:绑定简单数据类型参数,只需要直接声明形参即可(形参参数名和传递的参数名要保持⼀致,建议 使⽤包装类型,当形参参数名和传递参数名不⼀致时可以使⽤@RequestParam注解进⾏⼿动映射)@RequestParam()括号里面得参数名称和url里面得名称一样得

SpringMVC 接收简单数据类型参数 url:/demo/handle03?id=1
注意:接收简单数据类型参数,直接在handler⽅法的形参中声明即可,框架会取出参数值然后绑定到对应参数上
要求:传递的参数名和声明的形参名称保持⼀致

	@RequestMapping("/handle03")
	public ModelAndView handle03(@RequestParam("ids") Integer 	id,Boolean flag) { 
		Date date = new Date();
		ModelAndView modelAndView = new ModelAndView();
		modelAndView.addObject("date",date); 
		modelAndView.setViewName("success"); 
		return modelAndView;
	 }
  • 绑定Pojo类型参数
    SpringMVC接收pojo类型参数 url:/demo/handle04?id=1&username=zhangsan
    接收pojo类型参数,直接形参声明即可,类型就是Pojo的类型,形参名⽆所谓
    但是要求传递的参数名必须和Pojo的属性名保持⼀致
@RequestMapping("/handle04")
 
	public ModelAndView handle04(User user) { 
		Date date = new Date();
		ModelAndView modelAndView = new ModelAndView(); 
		modelAndView.addObject("date",date);
		modelAndView.setViewName("success");
		return modelAndView;
	}
  • 绑定Pojo包装对象参数

包装类型 QueryVo

package com.lagou.edu.pojo;

public class QueryVo {
 
	private String mail;
	private String phone; 
	// 嵌套了另外的Pojo对象
	private User user;
	public String getMail() {
		return mail;
	}
 
	public void setMail(String mail) {
 		this.mail = mail;
 	}
 
	public String getPhone() {
		return phone;
	}
 
	public void setPhone(String phone) {
		this.phone = phone;
	}
 
	public User getUser() {
		return user;
	}
 
	public void setUser(User user) {
		this.user = user;
 	}
}

Handler⽅法

/* 
* SpringMVC接收pojo包装类型参数 url:/demo/handle05?user.id=1&user.username=zhangsan 
* 不管包装Pojo与否,它⾸先是⼀个pojo,那么就可以按照上述pojo的要求来
* 1、绑定时候直接形参声明即可
* 2、传参参数名和pojo属性保持⼀致,如果不能够定位数据项,那么通过属性名 + "." 的⽅式进⼀步锁定数据 
*
*/
 
@RequestMapping("/handle05")
public ModelAndView handle05(QueryVo queryVo) {
	Date date = new Date();
	ModelAndView modelAndView = new ModelAndView();
	modelAndView.addObject("date",date);
	modelAndView.setViewName("success");
	return modelAndView;
}
  • 绑定⽇期类型参数(需要配置⾃定义类型转换器)
    前端jsp
<fieldset>
<p>测试⽤例:SpringMVC接收⽇期类型参数</p>
<a href="/demo/handle06?birthday=2019-10-08">点击测试</a>
</fieldset>

后台Handler⽅法

/**
* 绑定⽇期类型参数
* 定义⼀个SpringMVC的类型转换器
接⼝,扩展实现接⼝接⼝,注册你的实现
* @param birthday 
* @return
*/
 
@RequestMapping("/handle06")
public ModelAndView handle06(Date birthday) { 
	Date date = new Date();ModelAndView modelAndView = new
	ModelAndView(); 
	modelAndView.addObject("date",date);
	modelAndView.setViewName("success");
	return modelAndView;
 }

⾃定义类型转换器

package com.lagou.edu.converter;
import org.springframework.core.convert.converter.Converter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author 应癫
* ⾃定义类型转换器
* S:source,源类型
* T:target:⽬标类型
*/
public class DateConverter implements Converter<String, Date> {
 
@Override
 
public Date convert(String source) {
 
// 完成字符串向⽇期的转换
 
SimpleDateFormat simpleDateFormat = new
SimpleDateFormat("yyyy-MM-dd");
 
try {
 
Date parse = simpleDateFormat.parse(source);
 
return parse;
 } catch (ParseException e) {
 
e.printStackTrace();
 }
 
return null;
 }
}

注册⾃定义类型转换器

<!--
 
⾃动注册最合适的处理器映射器,处理器适配器(调⽤handler⽅法)
 
-->
 
<mvc:annotation-driven conversion-service="conversionServiceBean"/>
 
<!--注册⾃定义类型转换器-->
	<bean id="conversionServiceBean" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> 
		<property name="converters">
			<set>
				<bean class="com.lagou.edu.converter.DateConverter">
				</bean>
			</set>
 
	</property> 
</bean>

附录⼀ 乱码问题解决

  • Post请求乱码,web.xml中加⼊过滤器
<!-- 解决post乱码问题 -->
<filter>
	<filter-name>encoding</filter-name>
	<filter-class>
	 	org.springframework.web.filter.CharacterEncodingFilter
	</filter-class>
 
<!-- 设置编码参是UTF8 -->
	<init-param>
		<param-name>encoding</param-name>
		<param-value>UTF-8</param-value> 
	</init-param>
	<init-param>
		<param-name>forceEncoding</param-name>
		<param-value>true</param-value>
	</init-param>
</filter>

<filter-mapping>
	<filter-name>encoding</filter-name>
	<url-pattern>/*</url-pattern>
</filter-mapping>
  • Get请求乱码(Get请求乱码需要修改tomcat下server.xml的配置)
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080"
protocol="HTTP/1.1" redirectPort="8443"/>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于配置文件的Spring MVC应用中,实现登录功能需要编写以下源代码: 1. LoginController.java: @Controller public class LoginController { @RequestMapping(value = "/login", method = RequestMethod.GET) public String showLoginForm() { return "login"; } @RequestMapping(value = "/login", method = RequestMethod.POST) public String login(@RequestParam("username") String username, @RequestParam("password") String password, Model model) { if (username.equals("admin") && password.equals("123456")) { model.addAttribute("username", username); return "success"; } else { model.addAttribute("error", "用户名或密码错误"); return "login"; } } } 2. login.jsp: <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录页面</title> </head> <body> <h1>登录</h1> <form method="POST" action="/login"> <label for="username">用户名:</label> <input type="text" id="username" name="username"> <label for="password">密码:</label> <input type="password" id="password" name="password"> <input type="submit" value="登录"> </form> <c:if test="${not empty error}"> <p>${error}</p> </c:if> </body> </html> 3. success.jsp: <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登录成功</title> </head> <body> <h1>登录成功</h1> <p>欢迎,${username}!</p> </body> </html> 以上代码实现了一个简单的登录功能。用户输入用户名和密码后,点击登录按钮提交表单,后台LoginController中的login方法根据用户名和密码进行验证。如果验证通过,将用户名存入Model中,并返回success视图,显示登录成功页面,页面中会显示欢迎用户名。如果验证不通过,将错误信息存入Model中,并返回login视图,显示登录页面,并提示用户名或密码错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值