OVLS在线学习平台spring+boot+ssm+crud+ajax+zuul+redis+mysql+ribbon+feign(一.用户服务.注册功能+登录功能)

一.需求

1.OVLS数据库结构
在这里插入图片描述
2.OVLS采用技术

后端:SpringMVC、SpringBoot、SpringCloud、MyBatis、Restful、Redis、MySQL等

前端:jquery、ajax、bootstrap、jquery插件

3.架构思想:

前后分离模式(Vue+Ajax、jQuery+Ajax)
后端采用restful服务模式-restful服务架构
微服务架构(SpringBoot+SpringCloud)
系统缓存(redis)
静态资源服务器(Nginx)
流媒体服务器(red5,rtmp|rtmpt)
SpringCloud服务管理(注册、查找、调用、集群、容错、网关等)
...支付功能、集群

在这里插入图片描述

二.项目创建(准备工作三件事)

创建一个maven Project项目,取名为ovls-user

  1. pom.xml导入jar包

  2. 添加application.properties

  3. 添加启动类

    1.导包:

<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>cn.xdl</groupId>
  <artifactId>ovls-user</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <dependencies>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-web</artifactId>
  		<version>2.0.5.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-jdbc</artifactId>
  		<version>2.0.5.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.1.46</version>
  	</dependency>
  	<dependency>
  		<groupId>org.mybatis.spring.boot</groupId>
  		<artifactId>mybatis-spring-boot-starter</artifactId>
  		<version>1.3.2</version>
  	</dependency>
  	<dependency>
  		<groupId>com.github.pagehelper</groupId>
  		<artifactId>pagehelper-spring-boot-starter</artifactId>
  		<version>1.2.5</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-data-redis</artifactId>
  		<version>2.0.3.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-test</artifactId>
  		<version>2.0.5.RELEASE</version>
  	</dependency>
  	<dependency>
  		<groupId>org.springframework.boot</groupId>
  		<artifactId>spring-boot-starter-aop</artifactId>
  		<version>2.0.3.RELEASE</version>
  	</dependency>
  </dependencies>
</project>

2.添加配置文件(用户服务7001)
在src/main/resources里面添加appliction.properties

#设置访问端口
server port=7001
#连接数据库
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/ovls?userUnicode=true&characterEncoding=utf8
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#连接redis
#spring.redis.host=localhost
#spring.redis.port=6379

3.创建启动类
在src/main/java创建一个cn.xdl.ovls包,再创建UserRunBoot类

package cn.xdl.ovls;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication//启动程序
public class UserRunBoot {

	public static void main(String[] args) {
		SpringApplication.run(UserRunBoot.class, args);	
	}
}

三.restful服务(注册)

1.注册服务

发送post请求:/user/regist post
流程:
/user/regist–>
UserController–>
UserService–>
UserMapper–>
返回JSON结果

2.创建包名

控制器cn.xdl.ovls.controller
接口cn.xdl.ovls.dao
实体cn.xdl.ovls.entity
服务cn.xdl.ovls.service

一.user.dao接口DAO

1.从MyBatis Generator工具拿出创建的实体类User并序列化User

package cn.xdl.ovls.entity;
import java.io.Serializable;
import java.util.Date;
//序列化
public class User implements Serializable{
    /**
     * ID编号(主键)
     */
    private Integer id;
    /**
     * 账号
     */
    private String name;
    /**
     * 密码
     */
    private String password;
    /**
     * 昵称
     */
    private String nickName;
    /**
     * 职位
     */
    private String position;
    /**
     * 性别
     */
    private String sex;
    /**
     * 所在地
     */
    private String location;
    /**
     * 个性签名
     */
    private String signature;
    /**
     * 头像路径
     */
    private String image;
    /**
     * 注册时间
     */
    private Date regtime;
    /**
     *密码加盐
     */
    private String salt;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name == null ? null : name.trim();
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password == null ? null : password.trim();
    }
    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName == null ? null : nickName.trim();
    }
    public String getPosition() {
        return position;
    }
    public void setPosition(String position) {
        this.position = position == null ? null : position.trim();
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex == null ? null : sex.trim();
    }
    public String getLocation() {
        return location;
    }
    public void setLocation(String location) {
        this.location = location == null ? null : location.trim();
    }
    public String getSignature() {
        return signature;
    }
    public void setSignature(String signature) {
        this.signature = signature == null ? null : signature.trim();
    }
    public String getImage() {
        return image;
    }
    public void setImage(String image) {
        this.image = image == null ? null : image.trim();
    }
    public Date getRegtime() {
        return regtime;
    }
    public void setRegtime(Date regtime) {
        this.regtime = regtime;
    }
    public String getSalt() {
        return salt;
    }
    public void setSalt(String salt) {
        this.salt = salt == null ? null : salt.trim();
    }
}

2.从MyBatis Generator工具拿出创建的DAO接口和实现类UserMapper接口和UserSqlProvider实现类

3.在启动类添加映射扫描器

@MapperScan(basePackages={"cn.xdl.ovls.dao"})

4.添加dao测试类TestUserMapper

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import cn.xdl.ovls.UserRunBoot;
import cn.xdl.ovls.dao.UserMapper;
import cn.xdl.ovls.entity.User;
//在测试开始的时候自动创建Spring的应用上下文
@RunWith(SpringRunner.class)
//容器实例化,跟着UserRunBoot.class启动
@SpringBootTest(classes={UserRunBoot.class})
public class TestUserMapper {

	@Autowired//注入UserMapper
	private UserMapper userDao;
	
	/**
	 * 测试环境查询数据库中数据检测是否连接正常
	 */
	@Test
	public void test1(){
		//查询selectByPrimaryKey
		User user = userDao.selectByPrimaryKey(1);
		if(user != null){
			//有输出用户名和密码
			System.out.println(user.getName()+" "+user.getPassword() );
		}else{
			//无输出差无此人
			System.out.println("查无此人");
		}
	}
}

测试结果
在这里插入图片描述

二.服务service
1.UserMapper.java先在dao包的UserMapper接口里面

package cn.xdl.ovls.dao;
import cn.xdl.ovls.entity.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.InsertProvider;
import org.apache.ibatis.annotations.Result;
import org.apache.ibatis.annotations.Results;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.ibatis.annotations.UpdateProvider;
import org.apache.ibatis.type.JdbcType;
public interface UserMapper {
    /**
     */
	@Delete({
		"delete from user",
		"where id = #{id,jdbcType=INTEGER}"
	})
    int deleteByPrimaryKey(Integer id);
    /**
     * 添加
     */
	@Insert({
        "insert into user (id, name, ",
        "password, nick_name, ",
        "position, sex, location, ",
        "signature, image, ",
        "regtime, salt)",
        "values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, ",
        "#{password,jdbcType=VARCHAR}, #{nickName,jdbcType=VARCHAR}, ",
        "#{position,jdbcType=VARCHAR}, #{sex,jdbcType=VARCHAR}, #{location,jdbcType=VARCHAR}, ",
        "#{signature,jdbcType=VARCHAR}, #{image,jdbcType=VARCHAR}, ",
        "#{regtime,jdbcType=TIMESTAMP}, #{salt,jdbcType=VARCHAR})"
    })
    int insert(User record);
    /**
     * 按照字段添加
     */
	@InsertProvider(type=UserSqlProvider.class,method="insertSelective")
    int insertSelective(User record);
    /**
     */
	 @Select({
	        "select",
	        "id, name, password, nick_name, position, sex, location, signature, image, regtime, ",
	        "salt",
	        "from user",
	        "where id = #{id,jdbcType=INTEGER}"
	    })
	    @Results({
	        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
	        @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
	        @Result(column="password", property="password", jdbcType=JdbcType.VARCHAR),
	        @Result(column="nick_name", property="nickName", jdbcType=JdbcType.VARCHAR),
	        @Result(column="position", property="position", jdbcType=JdbcType.VARCHAR),
	        @Result(column="sex", property="sex", jdbcType=JdbcType.VARCHAR),
	        @Result(column="location", property="location", jdbcType=JdbcType.VARCHAR),
	        @Result(column="signature", property="signature", jdbcType=JdbcType.VARCHAR),
	        @Result(column="image", property="image", jdbcType=JdbcType.VARCHAR),
	        @Result(column="regtime", property="regtime", jdbcType=JdbcType.TIMESTAMP),
	        @Result(column="salt", property="salt", jdbcType=JdbcType.VARCHAR)
	    })
    User selectByPrimaryKey(Integer id);
		/**
		 * 插入在这里判断用户是否存在 根据用户名查询
		 */
		 
    /**
     */
@UpdateProvider(type=UserSqlProvider.class,method="updateByPrimaryKeySelective")
    int updateByPrimaryKeySelective(User record);
    /**
     */
	@Update({
        "update user",
        "set name = #{name,jdbcType=VARCHAR},",
          "password = #{password,jdbcType=VARCHAR},",
          "nick_name = #{nickName,jdbcType=VARCHAR},",
          "position = #{position,jdbcType=VARCHAR},",
          "sex = #{sex,jdbcType=VARCHAR},",
          "location = #{location,jdbcType=VARCHAR},",
          "signature = #{signature,jdbcType=VARCHAR},",
          "image = #{image,jdbcType=VARCHAR},",
          "regtime = #{regtime,jdbcType=TIMESTAMP},",
          "salt = #{salt,jdbcType=VARCHAR}",
        "where id = #{id,jdbcType=INTEGER}"		
	})
    int updateByPrimaryKey(User record);
}

添加以下方法

		/**
		 *判断用户是否存在 根据用户名查询
		 */
	    @Select({
	        "select",
	        "id, name, password, nick_name, position, sex, location, signature, image, regtime, ",
	        "salt",
	        "from user",
	        "where name = #{name,jdbcType=VARCHAR}"
	    })
	    @Results({
	        @Result(column="id", property="id", jdbcType=JdbcType.INTEGER, id=true),
	        @Result(column="name", property="name", jdbcType=JdbcType.VARCHAR),
	        @Result(column="password", property="password", jdbcType=JdbcType.VARCHAR),
	        @Result(column="nick_name", property="nickName", jdbcType=JdbcType.VARCHAR),
	        @Result(column="position", property="position", jdbcType=JdbcType.VARCHAR),
	        @Result(column="sex", property="sex", jdbcType=JdbcType.VARCHAR),
	        @Result(column="location", property="location", jdbcType=JdbcType.VARCHAR),
	        @Result(column="signature", property="signature", jdbcType=JdbcType.VARCHAR),
	        @Result(column="image", property="image", jdbcType=JdbcType.VARCHAR),
	        @Result(column="regtime", property="regtime", jdbcType=JdbcType.TIMESTAMP),
	        @Result(column="salt", property="salt", jdbcType=JdbcType.VARCHAR)
	    })
	User selectByName(String name);

2.编写服务service

package cn.xdl.ovls.service;
import cn.xdl.ovls.util.OvlsResult;
/**
 * 需求文档:用户管理:登录.注册.修改密码.修改个人信息.登录检查功能
 */
public interface UserStrvice {
	/**
	 * 一.注册
	 */
	public OvlsResult addUser(String name,String password);
}

3.设定约定方法状态码常量(增加状态码可读性)
在cn.xdl.ovls.util包中增加OvlsConstant类

package cn.xdl.ovls.util;
public class OvlsConstant {
	public static final int SUCCESS = 0; //成功
	public static final int ERROR = -1; //异常
	public static final int ERROR1 = 1; //失败1
	public static final int ERROR2 = 2; //失败2
	public static final int ERROR3 = 3; //失败3
	public static final String SUCCESS_MSG = "操作成功";
	public static final String ERROR_MSG = "操作异常";
	public static final String REGIST_ERROR1_MSG = "用户名被占用";
	public static final String LOGIN_ERROR1_MSG = "用户名不存在";
	public static final String LOGIN_ERROR2_MSG = "用户密码不正确";
}

三.实现类UserServiceImpl继承UserStrvice

package cn.xdl.ovls.service;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.xdl.ovls.dao.UserMapper;
import cn.xdl.ovls.entity.User;
import cn.xdl.ovls.util.OvlsConstant;
import cn.xdl.ovls.util.OvlsResult;
import cn.xdl.ovls.util.PasswordUtil;
import net.bytebuddy.asm.Advice.Return;
@Service//扫描
public class UserServiceImpl implements UserStrvice {
	@Autowired//通过UserMapper注入
	private UserMapper userDao;
	/**
	 * 一.2注册
	 * 插入语句:无返回值,只有两种情况1.成功2.抛异常
	 */
	public OvlsResult addUser(String name, String password) {
		//构建一个result
		OvlsResult result = new OvlsResult();
		//判断用户名是否存在
		User user = userDao.selectByName(name);
		if(user != null){
			//setStatus设置状态
			result.setStatus(OvlsConstant.ERROR1);
			//setMsg设置状态信息
		result.setMsg(OvlsConstant.REGIST_ERROR1_MSG);
			//输出返回值
			return result;
		}
		//添加用户
		user = new User();
		user.setName(name);
		//TODO 密码加密处理
		String salt = PasswordUtil.salt();
		//通MD5加密处理
		String md5Pwd = PasswordUtil.md5(password+salt);
		//设置加密密码
		user.setPassword(md5Pwd);
		//设置盐值
		user.setSalt(salt);
		user.setRegtime(new Date());//注册时间.系统当前时间
		userDao.insertSelective(user);
		result.setStatus(OvlsConstant.SUCCESS);
		result.setMsg(OvlsConstant.SUCCESS_MSG);
		return result;
	}
}

四.局部异常处理(出异常全部走这里)

package cn.xdl.ovls.controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import cn.xdl.ovls.util.OvlsResult;
@ControllerAdvice
public class MyErrorController {
	/**
	 * @ExceptionHandler处理Controller抛出的异常
	 * @ResponseBody用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区
	 * handlerException处理器异常解析器
	 * setStatus设置状态
	 * setMsg设置状态信息
	 */
	@ExceptionHandler
	@ResponseBody
	public Object handlerException(Exception ex){
		OvlsResult result = new OvlsResult();
		result.setStatus(-1);
		result.setMsg("系统异常");
		return result;
	}
}

五.接口UserController
作用是接收请求和接收参数
返回结果多的话可以自定义返回值代表什么
1.先添加一个实体类OvlsResult在cn.xdl.ovls.util包里

package cn.xdl.ovls.util;
public class OvlsResult {
	//定义状态及状态信息
	private int status;
	private String msg;
	public int getStatus() {
		return status;
	}
	public void setStatus(int status) {
		this.status = status;
	}
	public String getMsg() {
		return msg;
	}
	public void setMsg(String msg) {
		this.msg = msg;
	}
}

2.注册接口UserController

package cn.xdl.ovls.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import cn.xdl.ovls.service.UserStrvice;
import cn.xdl.ovls.util.OvlsConstant;
import cn.xdl.ovls.util.OvlsResult;

@RestController//处理返回的数据格式,使用了该类型注解后,该类下的所有方法都会返回json数据格式不再是视图,不会进行转跳
public class UserController {
	
	@Autowired//通过UserMapper注入
	private UserStrvice userService;
	
	/**
	 * 一.1注册用户
	 */
	@PostMapping("user/regist")
	public OvlsResult result(String name,String password){
		//构建一个对象,返回结果
		OvlsResult result = userService.addUser(name,password);
		return result;
	}
	
	/**
	 * 异常处理
	 */
	@ExceptionHandler
	public Object handlerException(Exception ex){
		OvlsResult result = new OvlsResult();
		result.setStatus(OvlsConstant.ERROR);
		result.setMsg(OvlsConstant.ERROR_MSG);
		return result;
	}
}

测试注册结果先启动UserRunBoot服务
在这里插入图片描述
注册成功
在这里插入图片描述
用户被占用
在这里插入图片描述

二.登录功能

流程

设计需求:/user/login POST请求 用户.密码

设计流程:
/user/login–>
UserController–>
UserService–>
UserMapper–>
返回JSON结果

一.接口UserService里面添加登录

	/**
	 * 二.登录
	 */
	public OvlsResult checkUser(String name,String password);
}

二.实现类UserServiceImpl里面添加登录

/**
	 * 二.登录
	 * 更新和删除语句:有返回值(顺利执行返回0,要么顺利执行返回1或多,抛异常)
	 */
	public OvlsResult checkUser(String name,String password){
		OvlsResult result = new OvlsResult();
		//2.1先根据用户名查询,用户名不存在
		User user = userDao.selectByName(name);
		if(user == null){
			result.setStatus(OvlsConstant.ERROR1);
			result.setMsg(OvlsConstant.LOGIN_ERROR1_MSG);
			return result;
		}
		//2.2如果用户存在,对比密码,密码不正确
		//user的密码是数据库的加密处理的密码,创建这个密码时拿到Salt后再md5
		String md5Pwd = PasswordUtil.md5((password+user.getSalt()));
		if(!md5Pwd.equals(user.getPassword())){
			result.setStatus(OvlsConstant.ERROR2);
			result.setMsg(OvlsConstant.LOGIN_ERROR2_MSG);
			return result;
		}
		//2.3用户名和密码正确
		result.setStatus(OvlsConstant.SUCCESS);
		result.setMsg(OvlsConstant.SUCCESS_MSG);
		return result;
	}

三.控制器UserController里添加登录

	/**
	 * 二.登录
	 * 查询这里涉及到密码用get不安全,所以用post安全
	 */
	@PostMapping("/user/login")
	public OvlsResult login(String name,String password){
		OvlsResult result = userService.checkUser(name,password);
		return result;
	}

四.单体测试类TestUserLogin(正常,无数据,错误)

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import cn.xdl.ovls.UserRunBoot;
import cn.xdl.ovls.controller.UserController;
import cn.xdl.ovls.util.OvlsConstant;
import cn.xdl.ovls.util.OvlsResult;

@RunWith(SpringRunner.class)
@SpringBootTest(classes={UserRunBoot.class})
public class TestUserLogin {
	@Autowired
	private UserController controller;
	/**
	 * 一.测试正确结果
	 */
	@Test
	public void test1() throws Exception{
		MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build();
		RequestBuilder registRequest = 
				MockMvcRequestBuilders.post("/user/login")
				.param("name", "xdl02")
				.param("password", "123456");
		MvcResult result = mock.perform(registRequest).andReturn();
		System.out.println(result.getResponse().getStatus());
		String str = result.getResponse().getContentAsString();
		System.out.println(str);
		//将返回的json字符串转成Ovlsresult对象,进行断言比对
		ObjectMapper mapper = new ObjectMapper();
		OvlsResult ovlsResult = mapper.readValue(str, OvlsResult.class);
		Assert.assertEquals(OvlsConstant.SUCCESS, ovlsResult.getStatus());
	}
	
	/**
	 * 二.测试查询用户名不存在
	 */
	@Test
	public void test2() throws Exception{
		MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build();
		RequestBuilder registRequest = 
				MockMvcRequestBuilders.post("/user/login")
				.param("name", "xdl03")
				.param("password", "123456");
		MvcResult result = mock.perform(registRequest).andReturn();
		System.out.println(result.getResponse().getStatus());
		String str = result.getResponse().getContentAsString();
		System.out.println(str);
		//将返回的json字符串转成Ovlsresult对象,进行断言比对
		ObjectMapper mapper = new ObjectMapper();
		OvlsResult ovlsResult = mapper.readValue(str, OvlsResult.class);
		Assert.assertEquals(OvlsConstant.ERROR1, ovlsResult.getStatus());
	}
	
	/**
	 * 三.测试密码错误结果
	 */
	@Test
	public void test3() throws Exception{
		MockMvc mock = MockMvcBuilders.standaloneSetup(controller).build();
		RequestBuilder registRequest = 
				MockMvcRequestBuilders.post("/user/login")
				.param("name", "xdl02")
				.param("password", "1234567");
		MvcResult result = mock.perform(registRequest).andReturn();
		System.out.println(result.getResponse().getStatus());
		String str = result.getResponse().getContentAsString();
		System.out.println(str);
		//将返回的json字符串转成Ovlsresult对象,进行断言比对
		ObjectMapper mapper = new ObjectMapper();
		OvlsResult ovlsResult = mapper.readValue(str, OvlsResult.class);
		Assert.assertEquals(OvlsConstant.ERROR2, ovlsResult.getStatus());
	}
}

测试登录结果先启动UserRunBoot服务
在这里插入图片描述
1.登录成功
2.用户名不存在
3.密码错误
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值