基于 Spring Mvc 一个简单项目的基本流程 <用户注册功能>(校正版)

本文详细介绍了基于SpringMvc框架开发用户注册功能的完整流程,涵盖项目创建、依赖配置、后端One.mapper(数据库操作)、业务逻辑(项目中端)、控制器编写,以及前端界面创建和测试。通过创建数据库表格、搭建项目目录、编写实体类、操作数据库接口和映射文件,再到业务逻辑处理和控制器接收前端数据,最后实现前端页面的交互。整个流程清晰地展示了SpringMvc项目开发的基本步骤。
摘要由CSDN通过智能技术生成


声名

提示:

  1. 这是原博客基于 Spring Mvc 一个简单项目的基本流程 <用户注册功能>的流程校正版,更符合常规开发项目的函数接口调用习惯,原版本更适合新手学习,原版本的基本内容都会在本博客展示。
  2. 本博客主要通过实现用户注册功能,帮助小白熟悉和理解以及使用在Spring Mvc框架下开发项目的基本流程
  3. 项目工具版本:2019.3 Idea64、MySQL5.5.6版本
  4. 版本一次修改,项目后端包括mapper、service、controller,前端仅有界面,但是由于个人理解出错,在写博客时目录配置错误(待改)

提示:以下是本篇文章正文内容,下面案例可供参考

一、创建与配置

1. 项目创建

  1. 创建新Project
    在这里插入图片描述
  2. 选择配置依赖,包括Web、SQL部分
    在这里插入图片描述

2. 依赖配置

2.1 配置pom.xml

在第33行换行增加一句:

<version>5.1.49</version>

在这里插入图片描述

2.2 配置application.properties

  1. 配置数据库
    在application.properties中配置(我的数据库密码为null,所以不写即可)
# 配置数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=
spring.datasource.url=jdbc:mysql://localhost:3306/upc_demo?characterEncoding=utf8
  1. 配置映射文件
    在resources目录下创建mappers文件夹
    在这里插入图片描述
    在application.properties中配置
mybatis.mapper-locations=classpath:mappers/*.xml
  1. 设置日志级别
    在application.properties中设置日记级别为debug级别,即控制台可以显示SQL语句,可让开发人员可以检测是否出错(等到项目全部完成后需要注释掉)
logging.level.com.upc.oa.mapper=debug
  1. 配置服务器:
    在application.properties中配置Web访问地址的端口和项目根目录
    配置:端口8088,项目根目录为 /oa
server.port=8088
server.servlet.context-path=/oa

服务地址:http://localhost:8088/oa

注意:

  • 服务器默认配置:端口8080,无根目录,由于tomcat服务器使用了8080,为了不冲突,我们一般重新配置
  • MySQL服务器使用了3306端口,所以一般我们配置自己服务器端口时也不选择3306
  1. 最终配置如下:
# 配置数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=
spring.datasource.url=jdbc:mysql://localhost:3306/upc_demo?characterEncoding=utf8

# 配置映射文件
mybatis.mapper-locations=classpath:mappers/*.xml

# 设置日志级别,显示SQL语句(项目完成后注释掉)
logging.level.com.upc.oa.mapper=debug

# 配置服务器
# 端口3306数据库使用了,端口8080tomcat使用了,所以我们要单独配置
server.port=8088
server.servlet.context-path=/oa

二、项目后端

注意:

One. mapper

1. 创建数据库表格

在navicat的对应数据库中,根据需求创建自己表格即可,我们创建存放用户注册信息的user_Info表格
在这里插入图片描述
注意:

  • 注意创建表格时userId是系统自增的主键,不需要用户注册时输入,所以后端的SQL语句中不需要插入userId数据
  • 注意userStatus表示用户账号的状态,默认为1即正常状态,若账号被删除或者拉黑可能是别的状态,这是后台管理员的任务,也不需要用户注册时输入,所以后端的SQL语句中也不需要插入userStatus数据,一般用户注册成功后都是默认为1

2. 搭建项目目录

在XXXApplication同级目录中创建:controller、mapper、service、po、dto的package
在这里插入图片描述

3. 创建实体类

3.1 自动生成po实体类
  1. 打开工具
    在这里插入图片描述
  2. 连接数据库
    在这里插入图片描述
  3. 修改配置
    在这里插入图片描述
  4. 选择要生成实体类的数据库表格,我们选择user_Info
    在这里插入图片描述
  5. 选择实体类存放文件,自动生产的实体类要统一放在po包里,ok后生成的UserInfo实体类存放在po包中
    在这里插入图片描述
3.2 创建dto实体类

dto实体类主要用于作传递参数的数据类型

  1. 在dto包下,创建dto实体类 Java class文件,命名为UserInfoDto(因为我们要继承UserInfo实体类)
    在这里插入图片描述
  2. 让UserInfoDto实体类继承UserInfo实体类即可
package com.upc.oa.dto;

import com.upc.oa.po.UserInfo;

public class UserinfoDto extends UserInfo {

}

4. 操作数据库

4.1 创建接口文件
(1) 创建函数接口

在mapper包中,创建UserInfo的函数接口,命名为UserInfoMapper
在这里插入图片描述

(2) 编写函数接口

主要编写一个接收参数的函数接口,注意声名@Mapper

package com.upc.oa.mapper;

import com.upc.oa.dto.UserinfoDto;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserinfoMapper {
    int save(UserinfoDto dto);
}
4.2 创建映射文件
(1) 创建文件
  1. 点击函数接口中的类名UserInfoMapper,选择黄色灯泡,选择蓝条部分,自动生成映射文件
    在这里插入图片描述
  2. 选择映射文件存放位置
    在这里插入图片描述
  3. 选择接口文件中我们编写的函数接口名sava,选择红色叹号,点击Generate statement
    在这里插入图片描述
  4. 选择生成语句类型,自动在映射文件中产生该函数接口的语句,我们是注册,就是向数据库插入数据,所以选择Insert Statement
    在这里插入图片描述
  5. 此时映射文件中已有如下代码:
    在这里插入图片描述
(2) 编写SQL语句
  1. 现在可以检测SQL语法的文件中编写,我们编写向user_info表格插入数据的插入语句
    在这里插入图片描述
  2. 粘贴在映射文件中并完成后续部分
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.upc.oa.mapper.UserinfoMapper">
    <insert id="save">
        insert into user_info
            (userName, userPwd, userRealName, userSex, userEmail)
        VALUES (#{userName},#{userPwd},#{userRealName},#{userSex},#{userEmail})
    </insert>
</mapper>
4.3 测试mapper

模拟mapper接收到Service提交的数据后,检测后端执行过程是否正确。
注意:
我们检测的是过程的正确性,尤其是对于后端内容涉及表格的增删改情况时,实际上我们不需要,也最好不要在测试阶段对数据库表格进行改动,所以我们在测试结束后要进行事物回滚,即测试结束后撤销对数据库的操作。这里涉及一个注解@Transactional,当测试结束后,这个注解会帮助我们进行事物回滚。

(1) 创建测试文件
  1. 创建文件
    在这里插入图片描述
  2. 选择要测试的函数接口
    在这里插入图片描述
(1) 编写测试文件
  1. 添加注解
    在这里插入图片描述
  2. 编写测试:主要是模拟前端传递来的数据,然后传递给函数接口
package com.upc.oa.mapper;

import com.upc.oa.dto.UserinfoDto;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;

import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class UserinfoMapperTest {

    @Resource
    private UserinfoMapper userinfoMapper;
    @Test
    @Transactional //执行成功后回滚数据
    void save() {
        // 设计、模拟前端传入的参数:创建结构体dto,给其中参数赋值
        UserinfoDto dto = new UserinfoDto();
        dto.setUserName("ross");
        dto.setUserPwd("666666");
        dto.setUserRealName("张三");
        dto.setUserEmail("daimi5566@126.com");
        
        // 调用函数接口userinfoMapper.save( )函数,操作成功返回 1,row为1
        int row = userinfoMapper.save(dto);
        
        // 这是一个函数:若row返回1,则提示操作成功
        assertEquals(1,row);
    }
}
(3) 测试

测试结果如下,即成功,即看到rollback[true]即告诉我们后端运行成功,并成功事务回滚了
在这里插入图片描述

Two. 业务逻辑(项目中端)

业务逻辑的必要性: 业务逻辑存在的主要原因:我们从前端接受的数据是没有处理过的数据,而后端由于涉及SQL语句,若所有数据都在后端进行整合处理就很麻烦,所以我们在前端和后端中增加了一层处理,这层可以用 Java 语言进行处理,这层处理称为“业务逻辑/业务处理”,可以理解为中端,所以业务逻辑也是整个项目最复杂的部分。
整个项目呈现总-分-总模式: 前端获得总的数据,中端将数据分类处理,后端获得总的处理结果对数据库进行操作

1. 创建业务逻辑接口

1.1 创建接口文件

在service包下创建Java class文件,命名为UserInfoService,这是业务逻辑的函数接口文件
在这里插入图片描述

1.2 编写接口文件

编写方法接口,接收前端的数据

package com.upc.oa.service;

import com.upc.oa.dto.UserinfoDto;

public interface UserInfoService {
    // 编写个函数接口,接受控制器得到的前端数据
    int doReg(UserinfoDto dto);
}

2. 编写业务逻辑

2.1 创建业务逻辑package

在service里创建impl(service implement即服务实施,就是业务逻辑)
在这里插入图片描述

2.2 创建业务逻辑文件
  1. 选择我们刚才的接口名,创建业务逻辑在这里插入图片描述
  2. 将文件存放在业务逻辑包
    在这里插入图片描述
  3. 选择要实现的函数接口
    在这里插入图片描述
  4. 效果如下:
    在这里插入图片描述
2.3 编写业务逻辑
package com.upc.oa.service.impl;

import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.mapper.UserinfoMapper;
import com.upc.oa.service.UserInfoService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

// 注解,声名这是业务逻辑
@Service
public class UserInfoServiceImpl implements UserInfoService {
    // 声名要对哪个映射文件进行操作,这里是调用后端的函数接口(把前端的数据转交到后端)
    @Resource
    private UserinfoMapper userinfoMapper;

    // 控制器的数据提交到后端方法的参数dto
    @Override
    public int doReg(UserinfoDto dto) {
        // 由于我们注册界面数据构成简单,可以直接转交给后端,
        // 所以这里对数据不做处理,直接将数据提交到后端的save函数接口,操作数据库
        return userinfoMapper.save(dto);
    }
}

Three. 控制器

1. 编写控制器

1.1 创建文件

在controller包中创建Java class文件
在这里插入图片描述

1.2 编写控制器
package com.upc.oa.controller;

import com.upc.oa.dto.UserinfoDto;
import com.upc.oa.service.UserInfoService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

// 声名注解
@RestController
// 配置路径 /user
@RequestMapping("/user")
public class UserController {
	// 声名我们调用的数据源
	@Resource
    private UserInfoService userInfoService;
    // 配置路径 /reg
    @RequestMapping("/reg")
    // Html文件将数据提交到reg方法的参数dto中,
    public int reg(UserinfoDto dto){
        // 此时我们需要将数据继续提交到业务逻辑中去,所以调用业务逻辑的doReg方法接受参数
        return userInfoService.doReg(dto);
    }
}

二、项目前端

2.1 创建文件

在static文件夹里创建login.html文件
在这里插入图片描述

2.2 Html部分

主要任务: 编写网页的基本内容

注意:

  • Html里的标签,也称为控件,控件大到div、table,小到 tr、td、input
  • 这里只提供我对html标签及其中属性的理解,至于详细用法可参考代码中的注解
标签(控件)个人理解
div区隔标记,将div标签中的控件,都放置在该div标签的区域内。我们除了可以修饰 html 界面本身的背景色,还可以单独修饰div标签区域的背景色。
from主要作用之一是向后端提交数据,但是本项目不再使用 from 表单提交数据,所以 from 表单添加与否无所谓,即使添加了也不用设置参数。
table约束 table 标签里的行和列,让它们更规整。表格顾名思义,表格里的行和列就是整整齐齐的,所以在table里创建的行和列都是自动规范的。
tr行标签,创建一行,该行可以放置很多列。
td列标签,创建一列,一般是嵌套在行标签里,等于是设置该行标签里的一列。
input输入标签,在界面中提供一个可输入文本框,input标签接收用户在对应文本框中的输入数据,除了可以提供输入文本框,还可提供单选按钮服务,非常银杏化。
button按钮标签,就是网页中的按钮,而若button的type是button,则button标签等同一个事件触发按钮,点击了它会触发一个事件,这个事件做什么我们自己编写;而它自带的有在 from 表单提交数据 post、重置文本框数据 reset 等等
标签中的属性个人理解
id=“”可以理解为控件的变量名,我们一般将需要进行修饰、操作的控件配置 id,目的是为了精确指定操作的控件。
type=“”类型,在input标签中,可以是文本类型、密码类型、单选项类型;在button选项中,可以是按钮类型,也可以是提交数据类型、重置文本框类型。
name=“”主要用于input,是为了 from 表单提交数据时,确定每个界面输入数据对应到后端的哪些参数,name要与对应后端的参数名一致
placeholder=“”主要用于input中,是在用户输入前的提示,文本框中的浅色文字
class=“”主要用于Css修饰Html界面时,类选择器选择有对应class的控件进行修饰

代码部分: 注意在body部分编写界面

    <!--框出区域-->
    <div id="container">
        <!--增加表单与否无所谓了,因为我们向后台提交数据不再用表单提交了,所以即使添加了表单也不用设置参数了-->
        <form>
            <!-- table可以约束我们定义的行和列,让它们更规整 -->
            <table>
                <!--设置 登录名 行-->
                <tr>
                    <td>登录名:</td>
                    <td>
                        <!--  id 控件的变量名,name是对应到后端的参数 (不过用不上了,写不写无所谓)   -->
                        <input type="text" id="userName" name="userName" placeholder="登录名称" class="input">
                    </td>
                    <!-- 多加一列,提示用户名填写什么 -->
                    <td>
                        <div id="userNameMsg">
                            登录名包含数字、字母任意组合
                        </div>
                    </td>
                </tr>

                <!--设置 密码行 行-->
                <tr>
                    <td>登录密码:</td>
                    <td>
                        <input type="password" id="userPwd" name="userPwd" placeholder="登录密码" class="input">
                    </td>
                    <td>
                        <div id="userPwdMsg">
                            登录密码6-12之间
                        </div>
                    </td>
                </tr>

                <!--设置 确认密码行 行-->
                <tr>
                    <td>确认密码:</td>
                    <td>
                        <!-- 这里是确认密码,不过不再向参数传递数据 -->
                        <input type="password" id="rePwd" placeholder="确认密码" class="input">
                    </td>
                    <td>
                        <div id="rePwdMsg">
                            确认密码必须与密码一致
                        </div>
                    </td>
                </tr>

                <!--设置 真实姓名 行-->
                <tr>
                    <td>姓名:</td>
                    <td>
                        <input type="text" id="userRealName" name="userRealName" class="input">
                    </td>
                    <td>
                        <div id="userRealNameMsg">请输入姓名</div>
                    </td>
                </tr>

                <!--设置 性别 行-->
                <tr>
                    <td>姓名:</td>
                    <td>
                        <!-- radio是单选按钮 ,名字分别叫男、女,选择男则前端返回的数值为 1,反之选择女返回2-->
                        <!-- 单选项里name是比加的属性,且要填对对应的后端参数 -->
                        <input type="radio" id="boy" name="userSex" value="1"checked><input type="radio" id="girl" name="userSex" value="2"checked></td>
                </tr>

                <!--设置 邮箱 行-->
                <tr>
                    <td>邮箱:</td>
                    <td>
                        <input type="email" id="userEmail" name="userEmail" class="input">
                    </td>
                    <td>
                        <div id="userEmailMsg">

                        </div>
                    </td>
                </tr>

                <!--设置 按钮 行-->
                <tr>
                    <td></td>
                    <td>
                        <button type="button" id="btnReg">注册</button>
                    </td>
                    <td>
                        <!--设置 重置按钮 -->
                        <button type="reset">重置</button>
                    </td>
                </tr>

            </table>
        </form>

    </div>

2.3 Css部分

主要任务: 修饰html编写的主体功能。
编写位置: 编码位置在head标签,添加style标签后即可编码。
存在问题: 界面主要控件都布置好了,这个修饰界面部分和界面控件部分是分离的,如何去修饰我们想要的控件呢?Css语法提供了三种方法去选择我们要修饰的控件,称为选择器(是不是很银杏化)

选择器作用(个人理解)
类选择器插眼法:我们要修饰的对象是谁,我们在对应控件里插个class=“className”属性,我们可以自己命名className
id选择器实名制法,每个控件基本都有自己的 id,我们要修饰哪个控件,直接选择这个控件的 id 进行修饰
标签选择器分类法:假如使用了 input标签的选择器,则它会自动将所有input控件都修饰

代码:
主要用法在代码注释中:

<head>
    <meta charset="UTF-8">
    <title>Title</title>
    
    <!--  sytle标签里写Css,修饰网页  -->
    <style type="text/css">
        /*
        *{} :标签选择器,*{}默认选择了所有标签
        margin: 0; :各个非嵌套关系的容器之间的边框间隔变为 0
        padding: 0; :嵌套关系的容器之间的间隔也为 0,(未懂)
        */
        *{
            margin: 0;
            padding: 0;
        }
        
        /*
        body{}:标签选择器,选择页面主体body控件进行修饰
         background-color: red; :设置主体背景色是红色
        */
        body{
            background-color: red;
        }

        /*
        body,html{}:标签选择器,选择了body、html控件进行修饰
        width: 100%; height: 100%; :宽高都为100%,是为了辅助div撑满网页而作的操作
        */
        html,body{
            width: 100%;
            height: 100%;
        }
        
        /*
         #container{} :id选择器,选择的是id="container"的控件进行修饰,就是下面的div控件
         background-color: #cae8ff; :让该控件的背景色为#cae8ff
         height: 100%; :该div控件的高设置为主体的100%程度,即撑满主体(但前提是body,html{}的宽高都要100%,前面已经进行设置)
        */
        #container{
            background-color: #cae8ff;
            height: 100%;
        }

        /*
        .input{}:类选择器,默认修饰所有带有class="input"属性的控件,我们给几个input控件配置了该class
        我们不但设置了宽、高、到其他边框的间隔大小,还有:
        border-radius: 5px; :边框线的粗为5px
        border: 1px solid; :边框的线为间隔为1px的虚线
        */
        .input{
            width: 200px;
            height: 30px;
            margin: 10px;
            border-radius: 5px;
            border: 1px solid;
        }
        
        /*
        .input:hover{} :类选择器,对所有有class="input"属性的控件进行修饰
        border-color: red; :当鼠标光标悬浮在被修饰的空间上时,边框变成红色-->
        */
        .input:hover{
            border-color: red;
        }
        
        /*
        button{} :标签选择器,自动修饰所有button的标签控件
        我们设置了按钮大小 以及形状,除此之外还有:
        border-radius: 50%:以高度的50%、宽度的50%进行画圈,当宽高相同时会进行画圆 ;不一致时多为椭圆
        border-radius: 10px; :绘画圆角矩形
        border: 1px gray dashed; :设置边框为间隔为1px的灰色虚线
        font-size: 20px; :按钮字体大小为20px
        margin-left: 10px; :设置框内字体据框左边为20px
        */
        button{
            width: 100px;
            height: 40px;
            border-radius: 10px;
            border: 1px gray dashed;
            font-size: 20px;
            margin-left: 10px;
        }
        
        /*
        button:hover{} :标签选择器,对所有的button标签控件进行修饰
        cursor: pointer;:设置当鼠标光标悬浮在所有button控件上时,都显示小手  -->
        */
        button:hover{
            cursor: pointer;
        }

    </style>

</head>

2.4 Js部分

主要任务: 使用jQuery获取前端用户输入的数据,并提交给控制器

(1) 配置jQuery
  1. 在resources目录下的static文件夹创建jquery文件夹,将jquery函数库文件放入其中
    在这里插入图片描述
  2. ReBuild一次项目,此项目才会加载jQuery函数库
    在这里插入图片描述
(2) 编码

在body标签中编写,在Html界面部分之后编写即可,注意Js部分都需要在script标签中写

<!--  引入jquery  -->
<script src="jquery/jquery-3.6.0.min.js"></script>
<!-- 编写jquery脚本 -->
<script>
    jQuery(
        function () {
        // 这里是java语言
        // 使用jQuery找id为btnReg的控件,找的就是注册按钮
        // .click():给注册按钮添加click事件,即点击后对应按钮后触发click的事件,
        // click事件的具体内容我们自己定义,这里click事件就是获取页面提交的信息
        jQuery("#btnReg").click(function () {

            //获取页面数据-----------------------------------------------

            //对于input标签的输入控件,通过定位 id 就直接获取对应控件得到的数据
            var userName = jQuery("#userName").val();
            var userPwd = jQuery("#userPwd").val();
            var rePwd = jQuery("#rePwd").val();
            var userRealName = jQuery("#userRealName").val()
            var userEmail = jQuery("#userEmail").val();

            // // 特殊处理 单选项择按钮
            // // (我们按钮设定;选择男前端返回数值 1,选择女前端返回数值 2)

            // // 方法一:
            // // 先默认为男,即数值 1
            // var uerSex="1";
            // // 如果 id 为 girl 的按钮控件被选中,则修改为 2,即选择女数值为 2
            // if (jQuery("#girl").checked()){
            //     userSex="2";
            // }

            // 方法二:直接获取radio中被选中的那个按钮的值(适用于只有一种单选项按钮的情况,如果除了男女,还有一种选择职业的单选项,那就不可用方法二了)
            var userSex = jQuery("input:radio:checked").val();

            // 另一种写法:找 input 控件中 name 为 userSex 的按钮(前提是input里有写name属性),根据它的选中值来获取
            // var userSex = jQuery("input[name='userSex']:checked").val();

            // 在控制台显示我们得到的数据
            console.log(userName);
            console.log(userSex);
            console.log(userPwd);

            //向控制台提交数据-----------------------------------------------

            //构建json(javaScript对象)格式的数据
            //"后端参数名":jQuery变量名 , :引号里对应的是后端的参数名,冒号后是我们定义的获取页面数据的变量名
            var user={
                "userName":userName,
                "userPwd":userPwd,
                "userSex":userSex,
                "userRealName":userRealName,
                "userEmail":userEmail
            }


            // 往后台发送请求 ajax,提交数据
            // jQuery.post("url",json_data,function(rst)):
            // url是需要传送到的控制器的路径,这里是将json格式的user数据提交到user控制器的reg方法中去,这里应该先创建控制器,配置好路径,才能写url,不过也可以在这里编好url,创建控制器时命名一致即可
            // Json_data:就是传送的json数据,这里写user
            // function(rst):其中rst,就是控制器接受数据后反馈的值
            jQuery.post("user/reg",user,function (rst) {
                // // 向控制台输出rst,就可以知道我们提交成功与否
                console.log(rst);

                // 如果rst等于1表示控制器成功接受参数
                if(rst==1)
                {
                    //向前端网页弹出窗口提示注册成功
                    alert("注册成功");
                }
            });

        });

    })
</script>

三、运行

1. 启动主程序

在这里插入图片描述

2. 进入界面

在这里插入图片描述
我们进入login.html界面即可(注意注册重复的用户后台会报错)
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值