jsp&el&jstl

el&jstl

第一章 Servlet3.0 注解开发

1.1 Servlet3.0

Tomcat版本Servlet版本JavaEE版本JDK版本
9.0.x4.08.08
8.5.x3.18.07
8.0.x3.17.07
7.0.x3.06.06 (1.6)
6.0.x2.55.05 (1.5)

Servlet 3.0 作为 Java EE 6 规范体系中一员,随着 Java EE 6 规范一起发布。该版本在前一版本(Servlet 2.5)的基础上提供了若干新特性用于简化 Web 应用的开发和部署。其中有几项特性的引入让开发者感到非常兴奋,同时也获得了 Java 社区的一片赞誉之声:

  1. 异步处理支持:有了该特性,Servlet 线程不再需要一直阻塞,直到业务处理完毕才能再输出响应,最后才结束该 Servlet 线程。在接收到请求之后,Servlet 线程可以将耗时的操作委派给另一个线程来完成,自己在不生成响应的情况下返回至容器。针对业务处理较耗时的情况,这将大大减少服务器资源的占用,并且提高并发处理速度。
  2. 新增的注解支持:该版本新增了若干注解,用于简化 Servlet、过滤器(Filter)和监听器(Listener)的声明,这使得 web.xml 部署描述文件从该版本开始不再是必选的了。
  3. 可插性支持:开发者可以通过插件的方式很方便的扩充已有 Web 应用的功能,而不需要修改原有的应用。

1.2 注解配置servlet演示

创建servlet,在@WebServlet注解中添加urlPatterns= "/hello",作为请求路径

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

//name = "HelloServlet":servlet名称,相当于web.xml中的<servlet-name>
//urlPatterns = "/hello":servlet的访问路径,相当于<url-pattern>
@WebServlet(name = "HelloServlet",urlPatterns = "/hello")
public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)  {
        System.out.println("get 请求执行");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("post 请求执行");
    }
}

配置tomcat服务器启动测试,浏览器地址栏输入:http://localhost:8080/day03/hello

第二章 域对象&请求转发&重定向

2.1 Request作为域对象存取数据

  • Request作为域对象的API:
方法返回值描述
setAttribute(String name, Object obj)void向Request域中保存数据
getAttribute(String name)Object从Request域中获取数据
removeAttribute(String name)void从Request域中移除数据
  • Request作为域对象作用范围:
    • Request对象其实就是从客户端浏览器向服务器发送的一次请求信息的封装。那么实质上向Request中所保存的数据有效期也是一次请求范围。
    • 所谓一次请求范围:指从客户端浏览器向服务器发送一次请求,服务器针对这次请求对浏览器作出响应。当服务器作出响应之后,请求对象就销毁了,保存在其中的数据就无效了。

2.2 请求转发和重定向完成页面的跳转

2.2.1 请求转发

  • 上图所示的请求转发的过程如下:
  1. 浏览器向Servlet1发出访问请求;

  2. Servlet1调用forward()方法,在服务器端将请求转发给Servlet2;

  3. 最终由Servlet2做出响应。

  • 请求转发的写法:
  1. 通过ServletRequest对象获得RequestDispatcher对象
方法返回值描述
getRequestDispatcher(String path)RequestDispatcher获得RequestDispatcher对象
  1. 再根据RequestDispatcher中的方法进行请求转发
方法返回值描述
forward(ServletRequest request, ServletResponse response)void进行请求转发
  • 请求转发的代码实现:
/**
 * 页面跳转前的Servlet
 */
@WebServlet(name = "ServletDemo1", urlPatterns = "/demo1")
public class ServletDemo1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 向request域保存数据:
        request.setAttribute("name", "张三");

        // 请求转发的方式:
		/*
		RequestDispatcher dispatcher = request.getRequestDispatcher("/demo2");
		dispatcher.forward(request, response);
		*/
        request.getRequestDispatcher("/demo2").forward(request, response);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

/**
 * 页面跳转后的Servlet
 */
@WebServlet(name = "ServletDemo2",urlPatterns = "/demo2")
public class ServletDemo2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 从request域获取数据:
        Object name = request.getAttribute("name");

        response.setContentType("text/html;charset=UTF-8");

        response.getWriter().print("<h1>跳转后的页面</h1>");
        response.getWriter().print(name);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

2.2.2 重定向

  • 上图所示的间接转发请求的过程如下:
  1. 浏览器向Servlet1发出访问请求;
  2. Servlet1调用sendRedirect()方法,将浏览器重定向到Servlet2;
  3. 浏览器向servlet2发出请求;
  4. 最终由Servlet2做出响应。
  • 重定向的写法:

通过HttpServletResponse对象中的以下方法实现重定向

方法返回值描述
sendRedirect(String location)void重定向
  • 重定向的代码实现:
/**
 * 页面跳转前的Servlet
 */
@WebServlet(name = "ServletDemo1", urlPatterns = "/demo1")
public class ServletDemo1 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 向request域保存数据:
        request.setAttribute("name", "张三");

        // 重定向的方式:
		response.sendRedirect("/day03/demo2");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

/**
 * 页面跳转后的Servlet
 */
@WebServlet(name = "ServletDemo2",urlPatterns = "/demo2")
public class ServletDemo2 extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 从request域获取数据:
        Object name = request.getAttribute("name");

        response.setContentType("text/html;charset=UTF-8");

        response.getWriter().print("<h1>跳转后的页面</h1>");
        response.getWriter().print(name);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

2.3 请求转发和重定向的区别

请求转发和重定向原理

区别总结

  • 请求转发是一次请求一次响应,而重定向是两次请求两次响应。
  • 请求转发地址栏不会变化的,重定向地址栏发生变化。
  • 请求转发路径不带工程名,重定向需要带工程名路径。
  • 请求转发只能在本网站内部,重定向可以定向到任何网站。

注意:

如果需要使用request进行值传递,需要通过请求转发完成。

如果页面需要跳转到其他网站上必须使用重定向。

第三章 jsp的基本入门

3.1 jsp简介

3.1.1 jsp的概念

JSP全名是Java Server Pages,它是建立在Servlet规范之上的动态网页开发技术。在JSP文件中,HTML代码与Java代码共同存在,其中,HTML代码用来实现网页中静态内容的显示,Java代码用来实现网页中动态内容的显示。为了与传统HTML有所区别,JSP文件的扩展名为.jsp。

3.1.2 体验jsp

  • 创建JSP文件,复制以下代码到jsp文件中,启动tomcat,在地址栏输入jsp文件名称进行访问。
<html>
<head>
  <title>测试jsp</title>
</head>
<body>
   <%
     Date date = new Date();
     SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:dd");
     String curTime = dateFormat.format(date);
     request.setAttribute("curTime",curTime);
    %>

    当前系统时间:<span style="color: red"><%=request.getAttribute("curTime") %></span>
</body>
</html>

在地址栏输入jsp文件名称访问即可。

3.2 jsp的执行原理

通过上述的体验jsp之后,我们发现jsp真的非常厉害,既可以编写java代码也可以直接编写html代码,相对servlet更加方便,那么jsp为什么可以直接使用reqeust 与直接编写html代码呢

依据上图的流程,这时用everything软件搜索本机上的_1_jsp.java文件, 可以找到如下内容的文件:找到了生成的java文件,其中一部分内容如下图:

我们可以看到当前的jsp文件被翻译成了一个类,这个类继承HttpJspBase类,那么这个HttpJspBase类又是什么?

注意jsp的翻译有服务器完成,HttpJspBase类一定也是tomcat服务器的内容,顺着org.apache.jasper.runtime.HttpJspBase这个类全名,我们找到这个类的源码:

通过观察源码,我们发现JSP其实底层就是一个servlet。通过观察源码,我们发现我们刚刚编写的所有代码都在该Servlet里面的service方法内部。

总结:

  1. jsp之所以可以编写html代码,其实本质上也是类似我们使用Servlet直接输出的。

  2. jsp之所以直接使用 直接使用request对象,是因为我们自己编写的代码全部都落入到了service方法内部,在service方法内部一开始就已经声明了request等对象了。

3.3 jsp的基本语法

3.3.1 jsp注释

JSP注释格式
<%-- jsp注释  --%>
JSP注释的使用
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>注释</title>
  </head>
  <body>
      <!---这个是html注释-->
      <%-- 这个是jsp的注释--%>
  </body>
</html>

访问页面测试:没有任何内容显示,那么也就说html与jsp注释都生效, 但是点击查看源码的时候我们发现我们只能查看到html的注释,jsp的注释根本就看不到。

总结

1. jsp的注释不会显示在源码上,更加安全。

2. 如果在jstl标签体内使用html的注释将会失效,所以在jsp页面中推荐使用jsp的注释。

3.3.2 jsp书写java代码的三种方式

在之前的演示中,我的jsp已经可以向页面输出一个html内容,但是这个还不够,jsp应该还要有像servlet一样可以通过代码,动态生成网页的功能。servlet是使用java代码生成动态网页的,因此,接下来,我们要学习如何在jsp页面使用java代码。

3.3.2.1 方式一:脚本片段
脚本片段格式:

格式:

<%  Java代码片段  %>

jsp代码演示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>书写java代码的三种方式</title>
</head>
<body>
    <%-- 脚本片段 --%>
    <% int x = 10; %>
</body>
</html>

翻译成java文件:

  • 在脚本片段中写的<% int x = 10; %>Java代码,会翻译到java文件中的_jspService方法中。
脚本片段作用
  • 在jsp翻译后的_jspService方法中,可以嵌入java代码
脚本片段使用注意事项
  • 脚本片段可以分开书写,最终是组合在一起的,示例:

jsp代码演示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>书写java代码的三种方式</title>
    </head>
    <body>
        <%-- 脚本片段 --%>
        <% for(int j = 0 ; j < 5 ;j++){%>
        	Hello World!!!<br>
        <%}%>
    </body>
</html>

3.3.2.2 方式二:脚本声明

脚本片段虽然可以嵌入java代码,但是如果,我们要给当前的jsp中定义一些方法或者成员变量,就需要一个新的技术——脚本声明。

脚本声明格式
<%!  书写Java代码  %>

jsp代码演示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>书写java代码的三种方式</title>
</head>
<body>
    <%! int i = 0 ;%>
</body>
</html>

翻译成java文件:

  • 脚本声明书写的<%! int i = 0 ;%>java代码,会翻译在类的成员位置上。
脚本声明作用
  • 在类的成员位置上声明方法和变量
脚本声明使用注意事项
  • 声明方法的时候,不要声明与jsp翻译的java文件中默认的一些方法或者变量同名的方法或者变量。
3.3.2.3 方式三:脚本表达式

虽然脚本声明和脚本片段已经可以书写Java代码了,但是如果我们要使用java代码向页面输出一些内容,还是需要使用原来的response对象,比较繁琐,因此,我们需要一个更加简便的方式,可以代替response向页面输出内容——这个就是脚本表达式。

脚本表达式格式
<%= 表达式 %>

jsp代码演示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>书写java代码的三种方式</title>
</head>
<body>
    
    <%-- 脚本表达式 --%>
    <%= "公司名称" %>
</body>
</html>

翻译成java文件:在_jspService方法中,找到了我们书写的内容

  • 脚本表达式书写的<%= "传智播客" %>java代码,会翻译到java文件中的_jspService方法内,被out.print输出到页面。

out对象的类型是JspWriter,通过查阅JAVAEE文档发现其父类是java.io.Writer,是一个Writer 字符流。

脚本表达式作用
  • 代替response向页面输出内容
脚本表达式使用注意事项
  • 使用表达式向页面输出内容的时候,不要同时使用response对象向页面输出内容,会出现页面内容输出顺序和代码顺序不一致。

第四章 EL表达式

4.1 EL表达式的基本概述

EL(Express Lanuage)表达式可以嵌入在jsp页面内部,减少jsp脚本的编写,EL 出现的目的是要替代jsp页面中输出脚本的编写。

4.2 EL表达式的格式和作用

EL表达式的格式:

${EL表达式内容}

EL表达式的作用:

  1. 从域对象中查找指定的数据。
  2. 内置对象使用
  3. 执行运算符

4.3 EL表达式的基本使用

4.3.1 EL表达式作用一:从域中取出数据

  • EL从四个域中获得某个值: ${key}
    • 同样是依次从pageContext域,request域,session域,application域中 获取属性,在某个域中获取后将不在向后寻找
    • 其中,若只想获得request域中的值:${requestScope.key}
    • 其中,若只想获得session域中的值:${sessionScope.key}
    • 其中,若只想获得application域中的值:${applicatioScope.key}
1. 通过EL表达式,获得普通数据

格式:

${key}

代码演示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%-- 存储普通数据 --%>
    <%
        //向request域中存储数据
        request.setAttribute("name","zhangsan");
        //向session域中存储数据
        request.getSession().setAttribute("name","lisi");
        //向servletContext域中存储数据
        getServletContext().setAttribute("name","wangwu");
    %>

    <h1>取出request域中的数据</h1>
    ${requestScope.name}
    <h1>取出session域中的数据</h1>
    ${sessionScope.name}
    <h1>取出servletContext域中的数据</h1>
    ${applicationScope.name}

    <h1>按照域的从小到大依次搜索域数据</h1>
    ${name}

</body>
</html>
2. EL获得javaBean对象的值

格式:

${对象.成员变量}

代码演示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%-- 存储User实体数据 --%>
    <%
        User user = new User("tom",18);
        request.setAttribute("user",user);
    %>

    <h1>取出User的数据</h1>
    ${user.username}==${user.age}

</body>
</html>
public class User {
    private String username;
    private int age;
    
    //省略构造方法、get、set方法
}
3. EL获得List<String>的值

格式:

${List集合对象[角标]}

代码演示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%-- 存储List<String>数据 --%>
    <%
        List<String> strList = new ArrayList<String>();
        strList.add("aaa");
        strList.add("bbb");
        strList.add("ccc");
        request.setAttribute("strList",strList);
    %>

    <h1>取出strList的数据</h1>
    ${strList[0]}==${strList[1]}

</body>
</html>
4. EL获得List<User>的值

格式:

${List集合对象[角标].成员变量}

代码演示

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%-- 存储List<User>数据 --%>
    <%
        List<User> userList = new ArrayList<User>();
        User user2 = new User("lucy",20);
        userList.add(user);
        userList.add(user2);
        request.setAttribute("userList",userList);
    %>

    <h1>取出userList的数据</h1>
	${userList[0].username}==${userList[0].age}<br/>
	${userList[1].username}==${userList[1].age}<br/>

</body>
</html>
5. EL获得Map<String,User>的值

格式:

${Map集合对象.key.成员变量}
或
${Map集合对象[key].成员变量}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%-- 存储Map<String,User> --%>
    <%
        Map<String,User> userMap = new HashMap<>();
        userMap.put("user1",user);
        userMap.put("user2",user2);
        request.setAttribute("userMap",userMap);
    %>

        <h1>取出userMap的数据</h1>
        ${userMap.user1.username}==${userMap.user1.age}<br/>
        ${userMap.user2.username}==${userMap.user2.age}<br/>
        ${userMap['user1'].username}==${userMap['user1'].age}<br/>
        ${userMap['user2'].username}==${userMap['user2'].age}<br/>

</body>
</html>

4.3.2 EL的内置对象

pageContext - WEB开发中的pageContext.

作用:可以获取JSP中域中的数据(pageScope,requestScope,sessionScope,applicationScope)

  • 例如,在Servlet中,想获得web应用的名称:request.getContextPath();
  • 那么,在jsp页面上,想获得web应用的名称:${pageContext.request.contextPath}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>获得web应用的名称</title>
</head>
<body>
        <h1>获得web应用的名称</h1>
        ${pageContext.request.contextPath}
        
</body>
</html>

4.3.3 EL执行运算符

  1. 算数运算符 + - * / %
  2. 逻辑运算符 && || !
  3. 比较运算符 > < >= <=
  4. Null运算符 empty
  5. 三元运算符

代码演示:

<%--再当前jsp导入ArrayList--%>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>el表达式可以执行运算符<</title>
    </head>
    <body>
        ${3==3}<br>
        ${3>=4}<br>
        ${3<5}<br>
        ${3!=3}<br>
        ${3+4}<br>
        ${3==3&&3<4}<br>
        ${3==5||3>4}<br>
        
        <%
        request.setAttribute("str",null);
        request.setAttribute("list",new ArrayList<>());
        %>
        ${empty str}<br>
        ${empty list}<br>
        ${str == null? "数据为空":str}<br>
    </body>
</html>

第五章 JSTL的核心标签库使用

5.1 jstl标签的基本概述

JSTL(JSP Standard Tag Library),JSP标准标签库,可以嵌入在jsp页面中使用标签的形式完成业务逻辑等功能。jstl出现的目的同el一样也是要提到jsp页面中的脚本代码。JSTL标准标准标签库有5个子库,但随着发展,目前常使用的是他的核心库

标签库标签库的URI前缀
Corehttp://java.sun.com/jsp/jstl/corec
I18Nhttp://java.sun.com/jsp/jstl/fmtfmt
SQLhttp://java.sun.com/jsp/jstl/sqlsql
XMLhttp://java.sun.com/jsp/jstl/xmlx
Functionshttp://java.sun.com/jsp/jstl/functionsfn

5.2 jstl标签的安装

导入jar包

javax.servlet.jsp.jstl.jar
jstl-impl.jar

使用taglib指令在jsp页面导入要使用的jstl标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

在jsp书写"<c:",看到如下提示,说明安装成功:

5.3 常用的jstl标签

jstl的核心标签内容有很多,现在目前还常用的标签只有if、foreach标签。

5.3.1 <c:if>标签

if标签作用

起到java代码的判断的作用

if标签属性介绍
  • test:判断是否执行标签内的内容(true——执行标签中的内容,false,不执行)。

  • var:用来保存test属性的结果(使用var属性给他取个名字),这个结果可以保存到指定的容器中。

  • scope:指定保存数据的容器。

if标签演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

    <c:if test="${num>5}">
        num大于5
    </c:if>
    <c:if test="${num<=5}">
        num小于等于5
    </c:if>

    <%--将if判断的结果存储到指定的域中--%>
    <c:if test="${num==100}" var="res" scope="request"></c:if>

    <h1>取出结果</h1>
    ${res}

</body>
</html>

5.3.2 forEach标签

forEach标签作用

起到java代码的for循环作用

forEach标签属性介绍
  • var:在不循环对象的时候,保存的是控制循环的变量;在循环对象的时候,保存的是被循环对象中的元素
  • items:指定要循环的对象
  • varStatus:保存了当前循环过程中的信息(循环的开始、结束、步长、次数等)
  • begin:设置循环的开始
  • end:设置循环的结束
  • step:设置步长——间隔几次循环,执行一次循环体中的内容
foreach演示
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
	<h1>模拟增强for循环</h1>
    <c:forEach items="${userList}" var="user">
        ${user.username}==${user.age}
    </c:forEach>

    <h1>模拟普通for循环</h1>
    <c:forEach begin="0" end="${num}" var="i" step="10">
        ${i}<br>
    </c:forEach>

</body>
</html>

第六章 三层架构和MVC模式

6.1 JSP开发模式

当SUN公司推出JSP后,同时也提供相应的开发模式,JavaWeb经历了JSP Model1 第一代,JSPModel1第二代,JSP Model 2 三个时期。

JSP Model1 第一代

JSP Model1是JavaWeb早期的模型,它适合小型Web项目,开发成本低!Model1第一代时期,服务器端只有JSP页面,所有的操作都在JSP页面中,连访问数据库的API也在JSP页面中完成。也就是说,所有的东西都在一起,对后期的维护和扩展极为不利。

JSP Model1 第二代

JSP Model1第二代有所改进,把业务逻辑的内容放到了JavaBean中,而JSP页面负责显示以及请求调度的工作。虽然第二代比第一代好了些,但还让JSP做了过多的工作,JSP中把视图工作和请求调度(控制器)的工作耦合在一起了。

JSP Model 2

Model2使用到的技术有:Servlet、JSP、JavaBean。Model2 是MVC设计模式在Java语言的具体体现。

  • JSP:视图层,用来与用户打交道。负责接收用来的数据,以及显示数据给用户;

  • Servlet:控制层,负责找到合适的模型对象来处理业务逻辑,转发到合适的视图;

  • JavaBean:模型层,完成具体的业务工作,例如:转账等。

6.1.3 三层架构

JSP模式是理论基础,但实际开发中,我们常将服务器端程序,根据逻辑进行分层。一般比较常见的是分三层,我们称为:经典三层体系架构。三层分别是:表示层、业务逻辑层、数据访问层。

  • 表示层:又称为 web层,与浏览器进行数据交互的。
  • 业务逻辑层:又称为service层,专门用于处理业务数据的。
  • 数据访问层:又称为dao层,与数据库进行数据交换的。将数据库的一条记录与JavaBean进行对应。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值