SpringMVC(1)——SpringMVC介绍、SpringMVC入门、Maven工程

目录

SpringMVC介绍

MVC简介(了解)

​编辑​

SpringMVC介绍

SpringMVC的特点

SpringMVC入门

搭建Maven工程(后面还有弄很多次,要记忆)

(补充知识)Maven的依赖范围

依赖范围介绍

Maven项目添加web模块(archetype)

配置web.xml

默认配置方式

拓展配置方式

小结

创建请求控制器

编辑SpringMVC配置文件

访问指定页面

小结


SpringMVC介绍

MVC简介(了解)

认识SpringMVC先认识MVC,MVC是一种软件架构思想,把软件按照模型,视图,控制器来划分,其中框架是配置文件 + jar包

Model:模型层,指工程中的JavaBean,用来处理数据,其中JavaBean分为两类:

  1. 实体类Bean(POJO):普通的Java对象,其实就是简单的JavaBean实体类。对应数据库里的某一张表,pojo里的每一个属性都和该表中的字段一 一对应
  2. 业务处理Bean(VO):指Servlet或Dao对象,专门用来处理业务逻辑和数据访问。通俗来说,vo就是一个自定义的、多个表的属性或字段的集合

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

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

MVC流程:

  1. 用户通过视图层发送请求到服务器,在服务器被Controller接收
  2. Controller调用相应的Model层处理请求,Model层会和DB数据进行交互获取到最终结果返回给Controller层
  3. Controller层再根据处理的结果找到对应的View视图,渲染完数据后响应给浏览器

SpringMVC介绍

  • SpringMVC 是Spring的一个后续产品,是Spring的一个子项目,相当于有Spring和SpringMVC(看Maven添加的依赖就知道了)
  • SpringMVC Spring 为表述层开发提供的一整套完备的解决方案。在表述层框架历经 StrustWebWorkStrust2 等诸多产品的历代更迭之后,目前业界普遍选择了 SpringMVC 作为 Java EE 项目表述层开发的首选方案
  • 注:三层架构分为表述层(或表示层)、业务逻辑层、数据访问层,表述层表示前台页面和后台Servlet

SpringMVC的特点

  • Spring 家族原生产品,与 IOC 容器等基础设施无缝对接
  • 基于原生的Servlet,封装了一个处理请求过程的,具有功能强大的前端控制器DispatcherServlet,对请求和响应进行统一处理(后端请求参数接收:req.getParameter("username")、请求重定向、请求响应、请求转发等)
  • 表述层各细分领域需要解决的问题全方位覆盖,提供全面解决方案
  • 代码清新简洁,大幅度提升开发效率(不用使用复杂的Servlet,编写繁琐的代码)
  • 内部组件化程度高,可插拔式组件即插即用,想要什么功能配置相应组件即可(都由前端控制器来调用组件来解决请求)
  • 性能卓著,尤其适合现代大型、超大型互联网项目要求

SpringMVC入门

搭建Maven工程(后面还有弄很多次,要记忆)

1.创建springMVC项目,然后在创建Maven模块,模块结构如下

2.在Setting中配置Maven及其仓库,确保不报错,不适用默认的Maven版本及默认项目仓库路径(单个项目弄一次,注意是项目不是模块)


3.Maven工程配置文件pom.xml文件介绍

说明:需要联网

<?xml version="1.0" encoding="UTF-8"?>
<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>com.atguigu.mvc</groupId>
    <artifactId>springMVC-demo1</artifactId>
    <version>1.0-SNAPSHOT</version>
    <!--工程打包方式,默认是jar,如果这是一个web工程,打包方式为war
    当前是一个web工程,因此我们需要为这个Maven工程添加web模块,
    模块里面有webapp及webapp里面的web.xml-->
    <packaging>war</packaging>

    <!--添加依赖群,当导报成war包时,这些依赖都会被放到webapp目录的
    WEB-INF目录中的lib目录下-->
    <dependencies>
        <!--添加单个依赖SpringMVC,下面同理.由于 Maven 的传递性,
        我们不必将所有需要的包全部配置依赖,而是配置最顶端的依赖,其他靠传递性导入,
        意味着只要导入了这个SpringMVC依赖,那么
        SpringMVC依赖的依赖也会导入进来,其中就有spring的基础框架jar包:
        aop、beans、context、core、expression,还有自身web框架jar包
        传递性对于其他依赖同理-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.1</version>
        </dependency>
        <!-- 日志,用于日志输出 -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        <!-- ServletAPI,之前没导入是因为Tomcat自带了Servlet和JSP的jar包,
        因此只要配置了tomcat就能使用Servlet,java不自带Servlet的-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <!--依赖范围,表示我们什么地方可以使用这个jar包,
            这里设置成provided就是该依赖已被服务器提供,因此编译时
            这个依赖都会被放到webapp目录的WEB-INF目录中的lib目录下-->
            <scope>provided</scope>
        </dependency>
        <!-- Spring5和Thymeleaf整合包,是视图技术,控制页面显示内容 -->
        <dependency>
            <groupId>org.thymeleaf</groupId>
            <artifactId>thymeleaf-spring5</artifactId>
            <version>3.0.12.RELEASE</version>
        </dependency>
    </dependencies>
</project>

4.刷新Maven,将从互联网的远程仓库中下载所需要的jar包,确保Maven不显示红色波浪线(如果显示就手动清空库存然后进行从新刷新,确保网络通畅)

(补充知识)Maven的依赖范围

  • maven 项目设置单个依赖<dependency>不同的范围<scope>,引入到classpath中的依赖是不同的,例如,编译时,maven 会将与编译相关的依赖引入classpath中;测试时,maven会将测试相关的的依赖引入到classpath中;运行时,maven会将与运行相关的依赖引入classpath中。依赖范围就是用来控制依赖于这三种classpath的关系。
  • 一般写在依赖最下面,用<scope>标签围住,默认是compile,compile、test、provided、runtime、system、import

依赖范围介绍

  • compile:编译依赖范围(compile),该范围就是默认依赖范围,此依赖范围对于编译、测试、运行三种classpath都有效,举个简单的例子,假如项目中有spring-core的依赖,那么spring-core不管是在编译,测试,还是运行都会被用到,因此spring-core必须是编译范围(构件默认的是编译范围,所以依赖范围是编译范围的无须显示指定)
        <dependency>
             <groupId>org.springframework</groupId>
             <artifactId>spring-core</artifactId>
             <version>2.5</version>
             <scope>compile</scope> <!--默认为该依赖范围,无须显示指定--〉
        </dependency>
  • 测试依赖范围(test):顾名思义就是针对于测试的,使用此依赖范围的依赖,只对测试classpath有效,在编译主代码和项目运行时,都将无法使用该依赖,最典型的例子就是 Junit,构件在测试时才需要,所以它的依赖范围是测试,因此它的依赖范围需要显示指定为<scope>test</scope> ,当然不显示指定依赖范围也不会报错,但是该依赖会被加入到编译和运行的classpath中,造成不必要的浪费
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.7</version>
        <scope>test</scope>
    </dependency>
  • 已提供依赖范围(provided):使用该依赖范围的maven依赖,只对编译和测试的classpath有效,对运行的classpath无效,典型的例子就是servlet-api, 编译和测试该项目的时候需要该依赖,但是在运行时,web容器已经提供的该依赖,所以运行时就不再需要此依赖,如果不显示指定该依赖范围,并且容器依赖的版本和maven依赖的版本不一致的话,可能会引起版本冲突,造成不良影响
    <dependency>
        <groupId>javax-servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>
  • 运行时依赖范围(runtime):使用该依赖范围的maven依赖,只对测试和运行的classpath有效,对编译的classpath无效,典型例子就是JDBC的驱动实现,项目主代码编译的时候只需要JDK提供的JDBC接口,只有在测试和运行的时候才需要实现上述接口的具体JDBC驱动
  • 系统依赖范围(system):该依赖与classpath的关系与 provided依赖范围完全一致,但是系统依赖范围必须通过配置systemPath元素来显示指定依赖文件的路径,此类依赖不是由maven仓库解析的,而且往往与本机系统绑定,可能造成构件的不可移植,因此谨慎使用,systemPath元素可以引用环境变量
    <dependency>
        <groupId>javax.sql</groupId>
        <artifactId>jdbc-stext</artifactId>
        <version>2.0</version>
        <scope>system</scope>
        <systemPath>${java.home}/lib/rt.jar</systemPath> 
    </dependency>
  • 导入依赖范围(import),该依赖范围不会对三种classpath产生影响,该依赖范围只能与dependencyManagement元素配合使用,其功能为将目标pom文件中dependencyManagement的配置导入合并到当前pom的dependencyManagement中。有关dependencyManagement的功能请了解maven继承特性

Maven项目添加web模块(archetype)

说明:通过项目结构设置Project Structure,实现手动设置web资源目录(webapp)和web.xml。如果在创建Maven工程的时候选择了webapp模板,那么是不需要如下手动操作创建这些web资源目录和web.xml。在进行下面操作时先在mian目录下创建一个webapp目录,webapp目录下可以创建一个web.xml。然后通过项目结构设置web资源目录(webapp)、项目描述符(web.xml)的路径。保存即可,保存后的效果如下图

 

配置web.xml

说明:web.xml是我们的web入口配置文件,可以注册JavaWeb三大组件:Servlet、Filter(过滤器)、Listener(监听器,SpringMVC学习没用上)等。后面可以配置类加注解方式代替web.xml、spring配置文件、springMVC配置文件(这里代替了解即可,最后面一章会具体描述)

默认配置方式

说明:通过默认配置web.xml方式下,SpringMVC的核心配置文件路径会在WEB-INF目录下,名称是<servlet-name>标签设置的"值"+"-servlet.xml",如果参考下面的web.xml配置方式,就可以的值SpringMVC的配置文件路径会在WEB-INF目录下,并且SpringMVC的文件名为
“SpringMVC-servlet.xml”。但是我们学习SpringMVC,大部分配置文件应该统一放到/main/resources目录下,并且名称应该是可以自定义的,WEB-INF是放置服务器只能通过请求转发的访问的资源(例如后面要学习的视图渲染需要的页面),所以推荐使用后面介绍的的拓展配置方式

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置SpringMVC的前端控制器DispatcherServlet,对浏览器发送的请求统一进行处理 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <!--保持servlet和servlet-mapping的servlet名字一致,表示要注册的Servlet是DispatcherServlet-->
        <servlet-name>SpringMVC</servlet-name>
        <!--
        设置springMVC的核心的前端控制器所能处理的请求的请求路径,
        这里"/"所匹配的请求可以是表示该Servlet可以处理除了.jsp以外的请求,
        .jsp文件在Tomcat中有专门名为"jspServlet"去处理
        当我们设置了前端控制器的请求映射规则为"/"时,
        那么原有的Tomcat的默认Servlet就会被该前端控制器取代
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

拓展配置方式

1.在resources目录下创建springMVC配置文件,名为springMVC.xml

2.在web.xml中通过配置DispatcherServlet的初始参数contextConfigLocation来配置SpringMVC配置文件的(相对)路径,并设置DispathcerServlet的生命周期为随着服务器启动进行初始化,确保程序的性能

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置SpringMVC的前端控制器DispatcherServlet,对浏览器发送的请求统一进行处理 -->
    <servlet>
        <servlet-name>SpringMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!--通过初始化参数(属性)contextConfigLocation配置Spring配置文件的位置和名称,
        该属性随着DispatcherServlet初始化而初始化,
        是DispatcherServlet是DispatcherServlet定义好的-->
        <init-param>
            <!--属性名 = contextConfigLocation,如果忘了可以参考一下:
            http://t.csdn.cn/UuVZl这个文章-->
            <param-name>contextConfigLocation</param-name>
            <!--属性值 = 配置文件路径
            classpath:对应的是编译后的java目录和resources目录的路径-->
            <param-value>classpath:springMVC.xml</param-value>
        </init-param>
        <!--设置该Servlet的生命周期,该前端控制器需要在程序启动时启动,来确保程序的性能,
        而不是第一次访问该DispatcherServlet时候才初始化,
        因此设置成该servlet的参数load-on-startup值为1-->
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <!--保持servlet和servlet-mapping的servlet名字一致,表示要注册的Servlet是DispatcherServlet-->
        <servlet-name>SpringMVC</servlet-name>
        <!--
        设置springMVC的核心的前端控制器所能处理的请求的请求路径,
        这里"/"所匹配的请求可以是表示该Servlet可以处理除了.jsp以外的请求,
        .jsp文件在Tomcat中有专门名为"jspServlet"去处理
        当我们设置了前端控制器的请求映射规则为"/"时,
        那么原有的Tomcat的默认Servlet就会被该前端控制器取代
        -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>

小结

  1. 浏览器的请求除了.jsp的请求其余都会交给前端控制器DispathcerServlet进行处理
  2. 前端控制器是一个Servlet,全称为DispathcerServlet,他要在web.xml进行注册
  3. 设置初始化参数contextConfigLocation来配置SpringMVC的配置文件所在的路径
  4. 设置DispathcerServlet这个Servlet的生命周期为随着服务器启动进行初始化,确保程序的性能。不然第一次访问才进行初始化,影响程序性能
  5. 后面开始介绍通过设置请求控制器的方法来处理前端控制器接收的请求

创建请求控制器

说明:前端控制器是一个Servlet,由于前端控制器统一处理浏览器发送给服务器的大部分请求,但具体的请求需要有不同的处理过程,因此需要创建具体的类(参考下面的HelloController类)作为请求控制器,请求控制器中每一个处理请求的方法称为请求控制器的方法。SpringMVC的一个请求控制器由一个POJO(普通的java类)担当。通过@Controller注解将其标识为一个控制层组件,交给Spring的IoC容器管理,此时SpringMVC才能够识别控制器的存在

1.在 src\main\java\com\atguigu\mvc\controller\HelloController.java 创建一个类,操作描述如下

package com.atguigu.mvc.controller;

import org.springframework.stereotype.Controller;
/*
该注解标识该类为IOC容器的控制层组件,通过包扫描讲这个类变成Bean交给Spring IOC容器管理,
SpringMVC才知道这里面的方法是处理控制器接收的请求,并作出响应.此时该类就变成了一个请求控制器
*/

@Controller
public class HelloController {
}

编辑SpringMVC配置文件

说明:为了让SpringMVC生效,需要在SpringMVC配置文件 src\main\resources\springMVC.xml 添加组件扫描和视图解析器

1.编辑SpringMVC配置文件 src\main\resources\springMVC.xml,添加组件扫描(当添加组件扫扫描配置后,就会产生如下图绿色的球)、Thymelfeaf视图解析器

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <!--添加扫描组件,让spring注解生效-->
    <context:component-scan base-package="com.atguigu.mvc.controller"/>
    <!-- 配置Thymeleaf视图解析器,负责页面跳转 -->
    <bean id="viewResolver"
          class="org.thymeleaf.spring5.view.ThymeleafViewResolver">
        <!--设置视图解析器的优先级,视图解析器可以有多个-->
        <property name="order" value="1"/>
        <!--视图解析器使用的编码-->
        <property name="characterEncoding" value="UTF-8"/>
        <!--视图解析器的模板-->
        <property name="templateEngine">
            <!--内部Bean-->
            <bean class="org.thymeleaf.spring5.SpringTemplateEngine">
                <!--内部Bean中的内部Bean-->
                <property name="templateResolver">
                    <bean class="org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver">
                        <!-- 视图前缀 -->
                        <property name="prefix" value="/WEB-INF/templates/"/>
                        <!-- 视图后缀,设置好视图前缀和后缀,
                        当后端请求控制器的方法返回"index"字符串时,
                        访问的就是服务器src\main\webapp\WEB-INF\templates\index.html页面-->
                        <property name="suffix" value=".html"/>
                        <!--设置模板模型-->
                        <property name="templateMode" value="HTML5"/>
                        <!--页面编码-->
                        <property name="characterEncoding" value="UTF-8" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean>
</beans>


2.在 src\main\webapp\WEB-INF\templates\index.html 创建首页页面,添加Thymeleaf的命名空间(这个命名空间需要写很多次,建议记忆),然后该页面可以使用Thymeleaf的语法(暂时没用上该语法),并设置如下内容

<!DOCTYPE html>
<!--添加一个Thymeleaf的命名空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>

3.修改 src\main\java\com\atguigu\mvc\controller\HelloController.java 请求控制器,实现当浏览器访问"http://域名:端口/程序上下文路径"时,应该是访问服务器的
"src\main\webapp\WEB-INF\templates\index.html"页面

package com.atguigu.mvc.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/*
该注解标识该类为IOC容器的控制层组件,通过包扫描讲这个类变成Bean交给Spring IOC容器管理,
SpringMVC才知道这里面的方法是处理控制器接收的请求,并作出响应.此时该类就变成了一个请求控制器
*/
@Controller
public class HelloController {


    /**
     * 目的:当浏览器访问"http://域名:端口/程序上下文路径"时,
     * 应该是访问服务器的"src\main\webapp\WEB-INF\templates\index.html"页面
     * 方法名是无所谓的,因为是靠@RequestMapping这个注解来实现请求与请求控制器方法建立映射关系,
     * 业务逻辑还是靠该方法的方法体进行处理,RequestMapping是一个请求映射注解,
     * value参数成员的值是对应请求资源路径(只用一个参数成员value可以不写),
     * 二者结合用于匹配访问服务器资源路径仅带有"/"的请求与请求控制器对应的方法
     * @return 返回值返回的是视图名称,是请求控制器返回给前端控制器,
     * 告知前端控制器的视图解析器携带模型数据解析哪一个页面成为视图响应给浏览器
     */
    @RequestMapping(value = "/")
    public String index(){
        return "index";
    }

}

4.配置Tomcat服务器,通过Tomcat来访问web工程

5.使用DEBUG启动配置好的Tomcat服务器,然后浏览器访问http://localhost:8080/springMVC/,查看效果如下图,然后再查看控制台,发现之前添加的logback依赖jar包已经生效,日志中输出如下图内容,请求地址与请求控制器的方法进行映射。然后执行了请求控制器的方法,渲染指定页面成视图响应到浏览器中

访问指定页面

1.编辑请求控制器 src\main\java\com\atguigu\mvc\controller\HelloController.java ,实现当浏览器访问http://localhost:8080/springMVC/target时, *返回的是服务器的src\main\webapp\WEB-INF\templates\target.html页面,需要在请求控制器中添加如下方法

    /**
     * 目的:当浏览器访问http://localhost:8080/springMVC/target时,
     * 响应的是视图渲染器找到服务器的src\main\webapp\WEB-INF\templates\target.html页面进行渲染成的视图
     * @return
     */
    @RequestMapping(value = "/target")
    public String toTarget(){
        return "target";
    }

2.新建一个 src\main\webapp\WEB-INF\templates\target.html 页面,内容如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
HelloWorld
</body>
</html>

3.编辑首页 src\main\webapp\WEB-INF\templates\index.html ,通过Thymeleaf语法实现动态拼接上下文路径变成完整的超链接地址

<!DOCTYPE html>
<!--添加一个Thymeleaf的命名空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
<!--通过th修饰href属性,实现使用Thymeleaf语法设置一个超链接,这个路径是由浏览器解析的
@{}作用是:如果大括号内的是一个绝对路径(这里是由斜线开头,就是绝对路径),
就会自动添加服务器设置的上下文路径"/springMVC",当浏览器点击这个链接时,
访问的是:域名:端口/springMVC/target,解决了上下文路径经常变更问题-->
<a th:href="@{/target}">访问目标页面target.html</a>
</body>
</html>

4.启动Tomcat服务器,测试访问两个页面的效果

小结

  1. 浏览器发送请求,若请求地址符合前端控制器的url-pattern,该请求就会被前端控制器 DispatcherServlet处理。
  2. 前端控制器会读取SpringMVC的核心配置文件,通过扫描组件找到请求控制器, 将请求地址和请求控制器中被@RequestMapping注解+value属性值注释的方法进行匹配,若匹配成功,该注解所标识的请求控制器方法就是处理请求的方法。
  3. 处理请求的方法需要返回一个字符串类型的视图名称,该视图名称会被SpringMVC配置文件配置的视图解析器解析,加上前缀和后缀组成页面的路径,通过ThymeleafViewResolve视图对页面进行渲染成视图响应给浏览器
  4. 这个过程是通过请求转发实现的到视图所对应页面(相当于前端控制器Servlet将请求转发,转发到隐藏在服务器的页面,然后将数据渲染到页面中展示视图响应给用户)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值