SpringBoot实战

准备工作

public class Department {

    private Integer id;
    private String dapartmentName;
//员工
public class Employee {

    private Integer id;
    private String lastName;
    private String email;
    private Integer gender;//0:女 1:男
    private Department department;
    private Date birth;

模拟数据库

//部门dao
@Repository
public class DepartmentDao {

    //模拟数据库中的数据
    private static Map<Integer, Department> departments=null;
    static {
        departments=new HashMap<Integer, Department>();//创建一个部门表
        departments.put(101,new Department(101,"教学部"));
        departments.put(101,new Department(102,"市场部"));
        departments.put(101,new Department(103,"教研部"));
        departments.put(101,new Department(104,"运营部"));
        departments.put(101,new Department(105,"后勤部"));
    }

    //获得所有部门信息
    public Collection<Department> getDepartment(){
        return departments.values();
    }

    //通过id获取到部门
    public Department getDepartment(Integer id){
        return departments.get(id);
    }

}
//员工dao
@Repository
public class EmployeeDao {

    //模拟数据库中的数据
    private static Map<Integer, Employee> employees=null;
    //员工所属部门
    @Autowired
    private DepartmentDao departmentDao;

    static {
        employees=new HashMap<Integer, Employee>();//创建一个部门表

        employees.put(101,new Employee(101,"AA","2222461@qq.com",1,new Department(101,"教学部"),new Date()));
        employees.put(102,new Employee(102,"BB","2222222@qq.com",0,new Department(102,"市场部"),new Date()));
        employees.put(103,new Employee(103,"CC","2222222@qq.com",1,new Department(103,"教研部"),new Date()));
        employees.put(104,new Employee(104,"DD","2222222@qq.com",0,new Department(104,"运营部"),new Date()));
        employees.put(105,new Employee(105,"EE","2222222@qq.com",1,new Department(105,"后勤部"),new Date()));
    }
    //主键自增
    private static Integer intId=10086;
    //增加一个员工
    private void save(Employee employee){
        if (employee.getId() == null){
            employee.setId(intId++);
        }
        employee.setDepartment(departmentDao.getDepartment(employee.getDepartment().getId()));
        employees.put(employee.getId(),employee);
    }

    //查询全部员工信息
    public Collection<Employee> getAll(){
        return employees.values();
    }

    //通过id查询员工
    public Employee getEmployeedById(Integer id){
        return employees.get(id);
    }

    //删除员工
    public void delete(Integer id){
        employees.remove(id);
    }
}

首页

  1. 首页配置,注意点,所有页面的静态资源都需要使用thymeleaf接管,使用@{/ } 相当于绝对路径

/相当于class目录根目录

server.servlet.context-path=/lt   相当于项目的虚拟目录

访问首页

方法一 不推荐使用

 //访问这两个目录都能到达index.html 首页
    @RequestMapping({"/","/index.html"})
    public String index(){
        return "index";
    }

方法二 自定义视图解析器 推荐

@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("index");
        registry.addViewController("/index.html").setViewName("index");
    }
}

访问首页发现静态资源加载不进来,因为Thymeleaf模板之后要把引入的css改成Thymeleaf支持的格式

导入命名空间

 xmlns:th="http://www.thymeleaf.org"
<link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

页面国际化

有的时候,我们的网站会去涉及中英文甚至多语言的切换,这时候我们就需要学习国际化了!

准备工作

先在IDEA中统一设置properties的编码问题!
在这里插入图片描述
编写国际化配置文件,抽取页面需要显示的国际化页面消息。我们可以去登录页面查看一下,哪些内容我们需要编写国际化的配置!

配置文件编写

1、我们在resources资源文件下新建一个i18n目录,存放国际化配置文件

2、建立一个login.properties文件,还有一个login_zh_CN.properties;发现IDEA自动识别了我们要做国际化操作;文件夹变了! 发现两个文件被合并了
在这里插入图片描述
3、我们可以在这上面去新建一个文件;
在这里插入图片描述
弹出如下页面:我们再添加一个英文的;在这里插入图片描述
这样就快捷多了!
在这里插入图片描述
4、接下来,我们就来编写配置,我们可以看到idea下面有另外一个视图 可视化配置;
在这里插入图片描述
这个视图我们点击 + 号就可以直接添加属性了;我们新建一个login.tip,可以看到边上有三个文件框可以输入

第一个框代表默认

在这里插入图片描述
我们添加一下首页的内容!
在这里插入图片描述
然后依次添加其他页面内容即可!

名字随意起

在这里插入图片描述
然后去查看我们的配置文件;

login.properties :默认

login.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

英文:

login.btn=Sign in
login.password=Password
login.remember=Remember me
login.tip=Please sign in
login.username=Username

中文:

ogin.btn=登录
login.password=密码
login.remember=记住我
login.tip=请登录
login.username=用户名

OK,配置文件步骤搞定!

配置文件生效探究

我们去看一下SpringBoot对国际化的自动配置!这里又涉及到一个类:MessageSourceAutoConfiguration

里面有一个方法,这里发现SpringBoot已经自动配置好了管理我们国际化资源文件的组件 ResourceBundleMessageSource;

// 获取 properties 传递过来的值进行判断
@Bean
public MessageSource messageSource(MessageSourceProperties properties) {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    if (StringUtils.hasText(properties.getBasename())) {
        // 设置国际化文件的基础名(去掉语言国家代码的)
        messageSource.setBasenames(
            StringUtils.commaDelimitedListToStringArray(
                                       StringUtils.trimAllWhitespace(properties.getBasename())));
    }
    if (properties.getEncoding() != null) {
        messageSource.setDefaultEncoding(properties.getEncoding().name());
    }
    messageSource.setFallbackToSystemLocale(properties.isFallbackToSystemLocale());
    Duration cacheDuration = properties.getCacheDuration();
    if (cacheDuration != null) {
        messageSource.setCacheMillis(cacheDuration.toMillis());
    }
    messageSource.setAlwaysUseMessageFormat(properties.isAlwaysUseMessageFormat());
    messageSource.setUseCodeAsDefaultMessage(properties.isUseCodeAsDefaultMessage());
    return messageSource;
}

我们真实 的情况是放在了i18n目录下,所以我们要去配置这个messages的路径;

spring.messages.basename=i18n.login

配置页面国际化值

去页面获取国际化的值,查看Thymeleaf的文档,找到message取值操作为:#{…}。我们去页面测试下:

IDEA还有提示,非常智能的!
在这里插入图片描述
我们可以去启动项目,访问一下,发现已经自动识别为中文的了!
在这里插入图片描述
但是我们想要更好!可以 根据按钮自动切换 中文英文!

配置国际化解析

在Spring中有一个国际化的Locale (区域信息对象);里面有一个叫做LocaleResolver (获取区域信息对象)的解析器!

我们去我们webmvc自动配置文件,寻找一下!看到SpringBoot默认配置:

@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(prefix = "spring.mvc", name = "locale")
public LocaleResolver localeResolver() {
    // 容器中没有就自己配,有的话就用用户配置的
    if (this.mvcProperties.getLocaleResolver() == WebMvcProperties.LocaleResolver.FIXED) {
        return new FixedLocaleResolver(this.mvcProperties.getLocale());
    }
    // 接收头国际化分解
    AcceptHeaderLocaleResolver localeResolver = new AcceptHeaderLocaleResolver();
    localeResolver.setDefaultLocale(this.mvcProperties.getLocale());
    return localeResolver;
}

AcceptHeaderLocaleResolver 这个类中有一个方法

public Locale resolveLocale(HttpServletRequest request) {
    Locale defaultLocale = this.getDefaultLocale();
    // 默认的就是根据请求头带来的区域信息获取Locale进行国际化
    if (defaultLocale != null && request.getHeader("Accept-Language") == null) {
        return defaultLocale;
    } else {
        Locale requestLocale = request.getLocale();
        List<Locale> supportedLocales = this.getSupportedLocales();
        if (!supportedLocales.isEmpty() && !supportedLocales.contains(requestLocale)) {
            Locale supportedLocale = this.findSupportedLocale(request, supportedLocales);
            if (supportedLocale != null) {
                return supportedLocale;
            } else {
                return defaultLocale != null ? defaultLocale : requestLocale;
            }
        } else {
            return requestLocale;
        }
    }
}

那假如我们现在想点击链接让我们的国际化资源生效,就需要让我们自己的Locale生效!

我们去自己写一个自己的LocaleResolver,可以在链接上携带区域信息!

修改一下前端页面的跳转连接: l是L

<!-- 这里传入参数不需要使用 ?使用 (key=value)-->
<a class="btn btn-sm" th:href="@{/index.html(l='zh_CN')}">中文</a>
<a class="btn btn-sm" th:href="@{/index.html(l='en_US')}">English</a>

我们去写一个处理的组件类!

import org.springframework.util.StringUtils;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

//可以在链接上携带区域信息
public class MyLocaleResolver implements LocaleResolver {

    //解析请求
    @Override
    public Locale resolveLocale(HttpServletRequest request) {
		//获取请求中的语言参数
        String language = request.getParameter("l");     //l是L
        Locale locale = Locale.getDefault(); // 如果没有获取到就使用系统默认的
        //如果请求链接不为空
        if (!StringUtils.isEmpty(language)){
            //分割请求参数
            String[] split = language.split("_");
            //国家,地区
            locale = new Locale(split[0],split[1]);
        }
        return locale;
    }

    @Override
    public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {

    }
}

为了让我们的区域化信息能够生效,我们需要再配置一下这个组件!在我们自己的MvcConofig下添加bean;
在这里插入图片描述

@Bean
public LocaleResolver localeResolver(){
    return new MyLocaleResolver();
}

我们重启项目,来访问一下,发现点击按钮可以实现成功切换!

注意:

  • 我们需要配置i18n文件
  • 我们如果需要在项目中按钮自动切换,我们需要自定义一个组件LocaleResolver
  • 记得将自己写的组件配置到spring容器中 @Bean
  • 国际化获取#{}

登录

发请求

<form class="form-signin" th:action="@{/user/login}" >

controller

@Controller
public class LoginController {

    @RequestMapping("/user/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password, Model model){
        if (!StringUtils.isEmpty(username)  && "123456".equals(password)){
            //只是一个虚拟的地址  走解析器到真正的登录页面  掩藏真正的主页
            return "redirect:/main.html";
        }else {
            model.addAttribute("msg","用户名或者密码错误");
            return "index";
        }
    }

}

视图解析器

 //如果登陆成功让他走解析器到main.html只是一个路径,为了地址栏保护主页的名称
 registry.addViewController("/main.html").setViewName("dashboard");

登陆失败页面显示一句话

<!--如果msg的值为空,则不显示   thy模板的格式strings.isEmpty-->
<p style="color: red" th:text="${msg}" th:if="${not #strings.isEmpty(msg)}"></p>

发现问题

​ 可以直接访问main页面进入到主页 不登录 需要拦截器

拦截器

//定义拦截器
public class LoginHandlerInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //登录成功后,session中有用户数据
        Object user = request.getSession().getAttribute("loginUser");
        if (user == null){
            request.setAttribute("msg","没有登录,请先登录");
            request.getRequestDispatcher("/index.html").forward(request,response);
            return false;
        }else {
        return true;
        }
    }
}

配置拦截器

@Configuration
public class MyMVCConfig implements WebMvcConfigurer {

    //添加自定义拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //new LoginHandlerInterceptor()自定义的拦截器名字
        registry.addInterceptor(new LoginHandlerInterceptor()).
                addPathPatterns("/**").        //拦截所有请求
                excludePathPatterns("/index.html","/","/user/login","/css/**","/js/**","/img/**"); //放行登录页,登录请求,放行静态资源
    }
}    

controller

  session.setAttribute("loginUser",username);

查询

提取公共页面

定一个一个公共页面在templates目录下创建一个commons目录在创建一个commons.html当作公共页面

顶部 和侧边栏都是公共的

  1. th:fragment=“sidebar” 提取 名称自定义

  2. <div th:replace="~{commons/commons::topbar}"></div>   
    第一个参数是公共页面的位置/名字::名称
    

高亮显示

<a th:class="${active=='list.html'?'nav-link active':'nav-link'}" th:href="@{/emps}">

nav-link active会高亮显示 收到参数为list.html高亮显示

<div th:replace="~{commons/commons::sidebar(active='main.html')}"></div>

前面是引入公共资源 () 括号是开始传参

传递参数使用括号传参

显示数据

后台 是Date类型 前端显示Fri Aug 21 08:56:49 CST 2020

这样展示

<table class="table table-striped table-sm">
<thead>
<tr>
<th>id</th>
<th>lastName</th>
<th>email</th>
<th>gender</th>
<th>department</th>
<th>birth</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr th:each="emp:${emps}">
<td th:text="${emp.id}"></td>
<td th:text="${emp.lastName}"></td>
<td th:text="${emp.email}"></td>
<td th:text="${emp.gender==0?'':''}"></td>
<td th:text="${emp.department.getDapartmentName()}"></td>  //对象类型
<td th:text="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm:ss')}"></td>
<td >
<button class="btn btn-sm btn-primary">编辑</button>
<button class="btn btn-sm btn-danger">删除</button>
</td>
</tr>
</tbody>
</table>

增加

springboot默认的时间格式是2020/8/21 写2020-8-21 提交就会报错

在配置文件中修改

#时间日期格式化
spring.mvc.date-format=yyyy-MM-dd

前端

<h2><a class="btn btn-sm btn-success" th:href="@{/emp}">添加员工</a></h2>
<form th:action="@{/emp}" method="post">
						<div class="form-group">
							<label >lastName</label>
				<input type="text" name="lastName" class="form-control"placeholder="lt">
						</div>
						<div class="form-group">
							<label >email</label>
		<input type="email" name="email" class="form-control"placeholder="44565@qq.com">
						</div>
						<div class="form-group">
							<label >gender</label>
							<div class="form-check form-check-inline">
		<input class="form-check-input" type="radio" name="gender" value="1">
							<label class="form-check-label"></label>
							</div>
					<div class="form-check form-check-inline">
					<input class="form-check-input" type="radio" name="gender" value="0">
								<label class="form-check-label"></label>
							</div>
						</div>
						<div class="form-group">
							<label >department</label>
							<!--name是department.id传过去一个id-->
							<select class="form-control" name="department.id">
								<!--这是一个特殊类型,所以我们需要提交的是一个属性 department.id-->
				<option th:each="dept:${departments}"th:text="${dept.getDapartmentName()}" th:value="${dept.getId()}"></option>
							</select>
						</div>
						<div class="form-group">
							<label >birth</label>
							<input type="text" name="birth" class="form-control" placeholder="lt">
						</div>
						<button type="submit" class="btn btn-default">添加</button>
					</form>

controller

@GetMapping("/emp")
    public String toAddpage(Model model){
        //查询出部门的信息再页面展示选择
        Collection<Department> departments = departmentDao.getDepartment();
        System.out.println(departments.size());
        model.addAttribute("departments",departments);

        return "emp/add";
    }

    @PostMapping("/emp")
    public String addEmp(Employee employee){
        employeeDao.save(employee);
        return "redirect:emps";
    }

修改

参数这样传递

<a class="btn btn-sm btn-primary" th:href="@{/emp/}+${emp.getId()}">编辑</a>

controller

 //修改
    @GetMapping("/emp/{id}")
    public String toUpdateEmp(@PathVariable("id")Integer id,Model model){
        //查询原来的数据
        Employee employeedById = employeeDao.getEmployeedById(id);
        model.addAttribute("emp",employeedById);
        //查询出部门的信息
        Collection<Department> departments = departmentDao.getDepartment();
        System.out.println(departments.size());
        model.addAttribute("departments",departments);

        return "emp/update";
    }
    //修改
    @PostMapping("/updateEmp")
    public String updateEmp(Employee employee){
        employeeDao.save(employee);
        return "redirect:emps";
    }
<form th:action="@{/updateEmp}" method="post">
						<!--隐藏于传过去id-->
						<input type="hidden" name="id" th:value="${emp.getId()}">
						<div class="form-group">
							<label >lastName</label>
							<input th:value="${emp.getId()}" type="text" name="lastName" class="form-control"  placeholder="lt">
						</div>
						<div class="form-group">
							<label >email</label>
							<input th:value="${emp.getEmail()}" type="email" name="email" class="form-control"  placeholder="44565@qq.com">
						</div>
						<div class="form-group">
							<label >gender</label>
							<div class="form-check form-check-inline">
							<input th:checked="${emp.getGender()==1}" class="form-check-input" type="radio" name="gender" value="1">
							<label class="form-check-label"></label>
							</div>
							<div class="form-check form-check-inline">
								<input th:checked="${emp.getGender()==0}" class="form-check-input" type="radio" name="gender" value="0">
								<label class="form-check-label"></label>
							</div>
						</div>
						<div class="form-group">
							<label >department</label>

							<select class="form-control" name="department.id">
								<!--查询出来Department展示-->
								<option th:selected="${dept.getId()==emp.getDepartment().getId()}" th:each="dept:${departments}" th:text="${dept.getDapartmentName()}" th:value="${dept.getId()}"></option>
							</select>
						</div>
						<div class="form-group">
							<label >birth</label>
							<!--显示日期-->
							<input th:value="${#dates.format(emp.getBirth(),'yyyy-MM-dd HH:mm')}" type="text" name="birth" class="form-control" placeholder="lt">
						</div>
						<button type="submit" class="btn btn-default">修改</button>
					</form>

删除

<a class="btn btn-sm btn-danger" th:href="@{/delemp/}+${emp.getId()}">删除</a>

controller

 //删除
    @RequestMapping("/delemp/{id}")
    public String delempemP(@PathVariable("id") int id){
        employeeDao.delete(id);
        return "redirect:/emps";
    }

404页面

在templates目录下创建个error目录 创建个404.html出现错误springboot自动找这个页面,位置一定要对

任何错误都是这样。
在这里插入图片描述
想要不走视图解析器 必须加上redirect

总结

前端:

  • 模板 :别人写好的,我们拿来改成自己需要的
  • 框架:组件自己手动组合拼接 Bootstrap,Layui,Semantic-ui
    • 栅格系统
      在这里插入图片描述
SpringBoot实战(第4版)清晰文字版,第 1 章 入门 ................................................ 1 1.1 Spring 风云再起 ........................................ 1 1.1.1 重新认识 Spring ............................ 2 1.1.2 Spring Boot 精要 ........................... 3 1.1.3 Spring Boot 不是什么 ................... 6 1.2 Spring Boot 入门 ....................................... 6 1.2.1 安装 Spring Boot CLI .................... 7 1.2.2 使用 Spring Initializr 初始化 Spring Boot 项目 .......................... 10 1.3 小结 ......................................................... 18 第 2 章 开发第一个应用程序 .................... 19 2.1 运用 Spring Boot ..................................... 19 2.1.1 查看初始化的 Spring Boot 新项目 .......................................... 21 2.1.2 Spring Boot 项目构建过程 解析 .............................................. 24 2.2 使用起步依赖 .......................................... 27 2.2.1 指定基于功能的依赖 ................... 28 2.2.2 覆盖起步依赖引入的传递依赖 .... 29 2.3 使用自动配置 .......................................... 30 2.3.1 专注于应用程序功能 ................... 31 2.3.2 运行应用程序 .............................. 36 2.3.3 刚刚发生了什么 ........................... 38 2.4 小结 ......................................................... 41 第 3 章 自定义配置 .................................... 42 3.1 覆盖 Spring Boot 自动配置 ..................... 42 3.1.1 保护应用程序 .............................. 43 3.1.2 创建自定义的安全配置 ............... 44 3.1.3 掀开自动配置的神秘面纱 ........... 48 3.2 通过属性文件外置配置 ........................... 49 3.2.1 自动配置微调 .............................. 50 3.2.2 应用程序 Bean 的配置外置 ......... 55 3.2.3 使用 Profile 进行配置 .................. 59 3.3 定制应用程序错误页面 ........................... 62 3.4 小结 ......................................................... 64 第 4 章 测试 ............................................... 66 4.1 集成测试自动配置 .................................. 66 4.2 测试 Web 应用程序 ................................. 68 4.2.1 模拟 Spring MVC ........................ 69 4.2.2 测试 Web 安全 ............................. 72 4.3 测试运行中的应用程序 ........................... 74 4.3.1 用随机端口启动服务器 ............... 75 4.3.2 使用 Selenium 测试 HTML 页面 ............................................. 76 4.4 小结 ......................................................... 78 第 5 章 Groovy 与 Spring Boot CLI ......... 80 5.1 开发 Spring Boot CLI 应用程序 .............. 80 5.1.1 设置 CLI 项目 .............................. 81 5.1.2 通过 Groovy 消除代码噪声 ......... 81 5.1.3 发生了什么 .................................. 85 5.2 获取依赖 .................................................. 86 5.2.1 覆盖默认依赖版本 ....................... 87 5.2.2 添加依赖仓库 .............................. 88 5.3 用 CLI 运行测试 ...................................... 89 5.4 创建可部署的产物 .................................. 91 5.5 小结 ......................................................... 91 第 6 章 在 Spring Boot 中使用 Grails ...... 93 6.1 使用 GORM 进行数据持久化 ................. 93 2 目 录 6.2 使用 Groovy Server Pages 定义视图 ....... 98 6.3 结合 Spring Boot 与 Grails 3 ................. 100 6.3.1 创建新的 Grails 项目 ................. 100 6.3.2 定义领域模型 ............................ 103 6.3.3 开发 Grails 控制器 ..................... 104 6.3.4 创建视图 .................................... 105 6.4 小结 ....................................................... 107 第 7 章 深入 Actuator .............................. 108 7.1 揭秘 Actuator 的端点 ............................ 108 7.1.1 查看配置明细 ............................ 109 7.1.2 运行时度量 ................................ 115 7.1.3 关闭应用程序 ............................ 121 7.1.4 获取应用信息 ............................ 121 7.2 连接 Actuator 的远程 shell .................... 122 7.2.1 查看 autoconfig 报告 ........... 123 7.2.2 列出应用程序的 Bean ............... 124 7.2.3 查看应用程序的度量信息 ......... 124 7.2.4 调用 Actuator 端点 .................... 125 7.3 通过 JMX 监控应用程序 ....................... 126 7.4 定制 Actuator......................................... 128 7.4.1 修改端点 ID ............................... 128 7.4.2 启用和禁用端点 ........................ 129 7.4.3 添加自定义度量信息 ................. 129 7.4.4 创建自定义跟踪仓库 ................. 132 7.4.5 插入自定义健康指示器 ............. 134 7.5 保护 Actuator 端点 ................................ 136 7.6 小结 ....................................................... 138 第 8 章 部署 Spring Boot 应用程序 ........ 139 8.1 衡量多种部署方式 ................................ 139 8.2 部署到应用服务器 ................................ 140 8.2.1 构建 WAR 文件 ......................... 141 8.2.2 创建生产 Profile ........................ 142 8.2.3 开启数据库迁移 ........................ 145 8.3 推上云端 ............................................... 150 8.3.1 部署到 Cloud Foundry ............... 150 8.3.2 部署到 Heroku ........................... 153 8.4 小结 ....................................................... 155 附录 A Spring Boot 开发者工具.............. 157 附录 B Spring Boot 起步依赖 ................. 163 附录 C 配置属性 ...................................... 169 附录 D Spring Boot 依赖 ......................... 202
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值