JavaWeb——JSP详解(3)

一、什么是 JSP ?

  • java server page,它是一种页面,它会被容器进行转换和编译,当请求到达 jsp 时,容器就会调用 jsp 进行执行,把执行的结果响应给客户端。
  • jsp 的构成比较复杂,相对于 HTML 来看,html 是静态资源,jsp 属于动态资源。jsp 可以包含的内容比 html 可以包含的内容要多很多,从设计的复杂度来看,比 html 也要复杂。

二、JSP 的基本要求

  1. 必须包含 <@page language=“java”> 页指令。
  2. 文件名必须以 .jsp 为扩展名
  • 满足以上两种要求的页面就是 jsp 页面。

三、JSP 的创建和应用

  1. jsp 页面中可以包含 java 代码,也可以放置 java 的表达式,还可以声明 java 的方法。

    • java 脚本片段,可以把 java 的代码放在页面中的任何位置,对于一段完整的代码,可以支离破碎的存在于页面中。它由 <% java的代码 %> 标签来生成。可以在脚本片段中接收请求参数。

      <%
          out.print("这是脚本片段的输出");
      %>
      
      <select>
          <% for (int i = 0; i < 10; i++) { %>
          <option><%=i%></option>
          <%}%>
      
      </select>
      
    • 脚本表达式,可以在页面的任何地方放置一个 java 的表达式,该表达式需要返回一个值。它由 <%=表达式%> 标签来生成,它的主要作用是取值。以上所说的表达式可以是直接量、变量、合法 java 表达式,方法调用的返回值。

      <%=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime())%>
      
    • 脚本声明,它也可以出现在任何位置,作用是声明可以由本页面调用的方法。它由 <%! 方法声明 %> 组成。

      <%!
          public String getName(){
              return "JSP";
          }
      %>
      
      <%=getName()%>
      
  2. 在页面中包含与 java 代码相关的以上的三个部分,是设计 jsp 的最基本的技术,在 jsp 技术的初期,都是这样设计页面从而生成各种动态资源。java 代码可以完成的大部分功能,都可以在 jsp 页面中来完成。对于一个基础项目,甚至可以只用 jsp 页面完成。

四、jsp 的执行过程及内部实现

  1. jsp 页面必须交给容器进行转换,转换成符合 Servlet 基本结构的一个 java 类。

    • 当请求发给 jsp 页面时,该请求会被 org.apache.jasper.servlet.JspServlet 处理,它处理 jsp 的基本步骤如下:

    (1)如果当前请求是发向 jsp 的第一次请求(与容器的开关无关),以上 JspServlet 会得到 jsp 页面的源内容。

    (2)把 jsp 页面的源内容转换为 java 的类。

    (3)把以上的 java 类进行编译,生成字节码文件。

    (4)加载字节码并实例化,然后执行其内部的 _spServlet(请求,响应)方法,该方法来完成 jsp 应该完成的任务,并向客户端响应结果。

    (5)以上 jsp 字节码的对象,从本质上来看也是一个 Servlet,它也具有 Servlet 的生命周期,也可以使用 Servlet 中可以使用的一些对象。

    (6)如果当前请求不是第一次请求,直接从第(4)步开始。

  2. JSP 的 java 源码告诉我们

    (1)页面上的脚本片段和脚本表达式会出现在 _ jspService() 方法中;
    (2)脚本声明的方法就是 jsp 的 java 源码的方法;
    (3)在 java 源码的 _ jspService() 方法中有九个局部变量,它们称为 jsp 的九大内置对象。这些对象可以直接在页面上使用,它们大多是由容器创建的。

    • request,response,application,session,config,Exception,page,pageContext,out。

五、利用 servlet + jsp 实现数据的 CRUD,同时加上权限检查。

  • <context-param>
        <param-name>username</param-name>
        <param-value>admin,manager</param-value>
    </context-param>
    
    <context-param>
        <param-name>pass</param-name>
        <param-value>123,456</param-value>
    </context-param>
    
  • <%--
      Created by IntelliJ IDEA.
      User: 华韵流风
      Date: 2021/4/23
      Time: 14:51
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>用户登录</title>
    </head>
    <body>
    <form action="loginSvl" method="post">
        <p>用户名:<input type="text" name="username"></p>
        <p>密码:<input type="password" name="pass"></p>
        <input type="submit"/>
        <div>
            <%
                String errinfo = (String)request.getAttribute("errinfo");
                if(errinfo != null){
                    out.print(errinfo);
                }
            %>
        </div>
    </form>
    
    </body>
    </html>
    
  • package dataApp;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Arrays;
    
    /**
     * @author 华韵流风
     * @ClassName ${NAME}
     * @Description TODO
     * @Date 2021/4/23 14:54
     */
    @WebServlet(name = "Login", urlPatterns = "/loginSvl")
    public class Login extends HttpServlet {
    
        private String username = null;
        private String pass = null;
    
        @Override
        public void init() throws ServletException {
            //通过 ServletContest 对象得到全局对象。
            username = getServletContext().getInitParameter("username");
            pass = getServletContext().getInitParameter("pass");
        }
    
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String username = request.getParameter("username");
            String pass = request.getParameter("pass");
    
            if (username.trim().length() == 0 || pass.trim().length() == 0) {
                //数据校验
                request.setAttribute("errinfo", "用户名或密码未通过校验");
                request.getRequestDispatcher("login.jsp").forward(request,response);
    
            } else {
                //检查用户名和密码是否匹配
                String[] usernames = this.username.split(",");
                String[] passs = this.pass.split(",");
                for (int i = 0; i < usernames.length; i++) {
                    if (usernames[i].equals(username)) {
                        if (pass.equals(passs[i])) {
                            //检查通过,如果有重定向,后面就不可以转发了
                            request.getSession().setAttribute("user",username);
                            response.sendRedirect("list.jsp");
                            //request.getRequestDispatcher("list.jsp").forward(request,response);
                            return;
                        }
                    }
                }
                //不通过
                request.setAttribute("errinfo", "用户名或密码错误");
                request.getRequestDispatcher("login.jsp").forward(request,response);
            }
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    }
    
  • <%@ page import="com.zhong.Person" %>
    <%@ page import="java.text.SimpleDateFormat" %>
    <%@ page import="java.util.Map" %>
    <%--
      Created by IntelliJ IDEA.
      User: 华韵流风
      Date: 2021/4/23
      Time: 15:08
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>主页面</title>
        <script>
            function remove(id) {
                let con= confirm("确认删除吗?");
                if (con) {
                    location.href = "remove?id=" + id;
                }
            }
        </script>
        <style>
            table tr td{
                text-align: center;
            }
        </style>
    </head>
    <body>
    <%
        String user = (String) session.getAttribute("user");
        if (user == null) {
            //用户未登录
            response.sendRedirect("login.jsp");
        }
    %>
    
    <%--从application中取出数据--%>
    <%
        Map<Integer, Person> data = (Map<Integer, Person>) application.getAttribute("data");
    %>
    
    <p>欢迎您!<%=session.getAttribute("user")%></p>
    <button onclick="location.href = 'add.jsp'">添加</button>
    <button onclick="location.reload()">刷新</button>
    <table border="1" width="800" cellspacing="0" cellpadding="0">
        <tr>
            <td>id</td>
            <td>name</td>
            <td>date</td>
            <td>goods</td>
            <td>操作</td>
        </tr>
    
        <%
            if (data != null) {%>
        <%
            for (Map.Entry<Integer, Person> entry : data.entrySet()) {
                Person person = entry.getValue();%>
        <tr>
            <td><%=person.getId()%>
            </td>
            <td><%=person.getName()%>
            </td>
            <td><%=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(person.getDate())%>
            </td>
            <td><%
                for (String good : person.getGoods()) {
                    out.write(good + " ");
                }
            %>
            </td>
            <td><a href="javascript:remove(<%=person.getId()%>);">删除</a>
            </td>
        </tr>
        <%}%>
        <%}%>
    </table>
    </body>
    </html>
    
  • package dataApp;
    
    import com.zhong.Person;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.Map;
    
    /**
     * @author 华韵流风
     * @ClassName ${NAME}
     * @Description TODO
     * @Date 2021/4/23 16:28
     */
    @WebServlet(name = "Remove", urlPatterns = "/remove")
    public class Remove extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
            String id = request.getParameter("id");
            Map<Integer, Person> data = (Map<Integer, Person>) getServletContext().getAttribute("data");
            data.remove(Integer.valueOf(id));
            response.sendRedirect("list.jsp");
    
    
        }
    }
    
  • <%--
      Created by IntelliJ IDEA.
      User: 华韵流风
      Date: 2021/4/16
      Time: 20:37
      To change this template use File | Settings | File Templates.
    --%>
    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>添加数据</title>
    </head>
    <body>
    <form action="add" method="post">
        <label for="id">id:<input type="number" id="id" name="id"/></label><br/>
        <label for="name">name:</label><input type="text" id="name" name="name"/><br/>
        <label for="date">date:</label><input type="date" id="date" name="date"/><br/>
        爱好:
        <input type="checkbox" name="goods"value="g1"/>
        <input type="checkbox" name="goods"value="g2"/>
        <input type="checkbox" name="goods"value="g3"/>
        <input type="submit" value="提交"/>
    </form>
    
    </body>
    </html>
    
  • package dataApp;
    
    import com.zhong.BeanUtil;
    import com.zhong.Person;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @author 华韵流风
     * @ClassName ${NAME}
     * @Description TODO
     * @Date 2021/4/23 16:04
     */
    @WebServlet(name = "Add",urlPatterns = "/add")
    public class Add extends HttpServlet {
        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            Person person = BeanUtil.toBean(request.getParameterMap(), Person.class);
            //把数据保存到应用上下文对象中
            Map<Integer,Person> data = (Map<Integer,Person>)getServletContext().getAttribute("data");
            if(data == null){
                data = new HashMap<Integer, Person>();
            }
            data.put(person.getId(), person);
            getServletContext().setAttribute("data", data);
            //重定向到list.jsp
            response.sendRedirect("list.jsp");
        }
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    }
    

六、jsp 的指令

  1. page 指令

    • jsp 页面必须具有 page 指令,包含了多种属性,对本页面的工作内容和方式会产生影响。

    (1)language=“java” 表示当前使用的是 java 语言,必须这样写;

    (2)contentType=“text/html;charset=UTF-8” 通过响应对象发向客户端的内容类型(mime)及字符编码;

    (3)import,相当于类中的 import,用来引包;

    (4)session 如果为 true,表示可以直接在页面中使用会话对象,默认就是 true ,不需要修改;

    (5)buffer,它是为 out 对象设置缓冲区的,默认大小是 8 k;

    (6)autoFlush,设置输出缓冲区是否具有自动刷新的功能,默认也是 true;

    (7)isThreadSafe,布尔值,本页面是否线程安全,默认不安全;

    (8)pageEncoding,指定本页面中的内容使用的编码;

    (9)errorPage,指定本页面是否是错误异常,其他的 jsp 页面执行中抛出异常,可以用错误页面来显示异常。默认 false,鸡肋。

  2. include 指令

    • <% @include file="list.jsp" %><%--包含指令,可以把其他的页面与本页面进行合并,生成一个 Servlet,属于静态的包含。--%>
      
  3. 标签指令

    • <% @taglib prefix=""%><%--引用外部的标签库。--%>
      

七、jsp 九大内置对象的作用

  • request,response,page,pageContext,application,session,Exception,confige,out。
  • 这些内置对象直接在页面上使用,因为它都会在 jsp 创建时由容器生成。
  • request,application,session,pageContext 这四个是域对象。
  1. out 对象,页面中用来向客户端输出信息的输出流对象,它的类型是 JspWriter,它内部组合了 Servlet 中通过 Response 得到的输出流。
  2. confige,配置对象,ServletConfig 类型,在配置文件中可以针对 jsp 设置初始化参数。
  3. Exception 对象,异常对象, jsp 页面在执行过程中产生的异常用该对象来捕获,包含了异常的具体信息,不用。
  4. page 页对象,就是引用本页面,可以提供给外部的页面来操作本页面。
  5. pageContext,它的作用范围就是本页面,作用一:用作域对象来保存一些数据;作用二:可以通过它得到其他的内置对象,比如 application,request,session 等。它称为页面上下文对象。

八、jsp 页面的错误处理

  1. 页面中与 jsp 相关的语法出现错误,编译不成功,错误信息会出现在页面上,报告错误类型及错误的位置。
  2. 页面中的 java 的语法出现错误,编译不成功,错误信息会出现在页面上,报告错误类型及错误的位置。
  3. 页面在执行过程中抛出运行时异常,它会写日志,页面也会出现异常的位置。

九、jsp 的动作标签

  • 在 jsp 页面中提供了一些标签可以直接在页面上使用,这些动作标签都有自己的功能。
  • 基本语法:<jsp: 标签名 属性名=值……/>
  1. <jsp:forward page=""/><%--转发标签,作用类似于requestDispatch对象的 forward 方法--%>
    
  2. <jsp:useBean id="person" class="com.zhong.Person" scope="page">
      <jsp:setProperty property="id" value="5" name="person"/>
      <jsp:setProperty property="name" value="abc" name="person"/>
    </jsp:useBean>
    <%--可以创建JavaBean对象,默认作用范围在页面内,scope="page",页面中使用直接用id来引用--%>
    <%
      out.print(person.getId());
    %>
    
  3. <jsp:include page="list.jsp"/>
    <%--在本位置包含另一个文件的内容,属于动态的,编译后会生成两个servlet,把被包含的servlet的转出合并到包含内容的servlet 的输出--%>
    

十、EL 表达式

  • 称为表达式语言,在很多方面都在使用。它能够以一种简洁的方式,在页面中完成取值和运算等操作。所以它能够替换页面中的脚本表达式。
  • 现在的页面设计,不会再使用 java 代码,转而去使用 EL 表达式和 jstl 的标签以及 jsp 的动作标签去替换所有的 java 代码。
  1. 语法:${表达式},在表达式中可以使用 ‘.‘,也可以使用 [ ]。

  2. 取值的范围:

    (1)jsp 中有四个域对象(request,session,application,pageContext),凡是存在于域对象中的属性值都可以取出来。

    (2)pageContext 中包含了一些隐式对象,比如以上的四个域对象,那么可以通过 pageContext 得到以上四个域对象中的 Map,它们分别是 requestScope,applicationScope,sessionScope,pageScope。EL 表达式可以从以上的 Map 中把对象取出来。

    (3)pageContext 中还包含了 param 隐式对象,param 内部也有一个 Map,就是通过 request.getParameterMap() 的结果。EL 表达式可以取出所有请求参数。

    (4)pageContext 中还包含了 cookie 隐式对象,实际就是包含了一个表示 Cookie 的键值对的 Map,EL 表达式可以取出 Cookie 中的值。

  3. 可取值的内容:

    • EL 表达式只能取出引用类型的数据,
    • 如果是一个对象,要取出对象中的属性值,要求类中必须提供属性值的 get 和 set 方法。
    • 如果取的值是一个单一值,比如 String,比如八大类型的包装类型,只用通过数据所在域的属性名去取。
    • 如果取的值是一个对象,就会取成 对象.对象.值。
    • 如果取的值是一个 Map 对象,依据 key 来取,属性名.key。
    • 对于 List 或 Array(数组),取值用[ ],属性名.对象名.数组名[索引]。
  4. 用 EL 表达式来取值

    • @Override
      protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
          request.setAttribute("str", "域中的字符串");
          request.setAttribute("num",15);
          Person person = new Person(10, "张三", new Date(), new String[]{"aaa", "bbb", "ccc"});
          HashMap<String,String> map = new HashMap<>();
          map.put("li", "好朋友");
          map.put("wang", "狗朋友");
          person.setFriends(map);
          request.setAttribute("map", map);
          request.setAttribute("person", person);
          request.getRequestDispatcher("el.jsp").forward(request, response);
      }
      
    • <%--
        Created by IntelliJ IDEA.
        User: 华韵流风
        Date: 2021/4/24
        Time: 15:08
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <html>
      <head>
          <title>Title</title>
      </head>
      <body>
      取普通字符串:${str}
      <br/>
      取数字:${num}
      <br/>
      取对象中的name:${person.name}
      <br/>
      取对象中的日期:${person.date}
      <br/>
      取对象中的数组:${person.goods[0]}
      <br/>
      取map的值:${map.li}
      <br/>
      取对象中map的值:${person.friends.wang}
      </body>
      </html>
      
  5. 四个域对象取值的优先级

    • 如果四个域中有同名的属性,在取值时并未指定从哪个域中取,就会按照域的优先顺序来取:pageContext,request,session,application(范围越小越优先)
    • 如果出现这种情况,要带上范围前缀,例如:${pageScope.str}
    • 何时使用 [ ]:一般情况下,用.和 [ ] 都可以取值,但是如果名称中出现特殊字符,比如 . - 等,只能用 [ ]。
  6. 在表达式中使用运算符

    • EL 表达式支持使用算数表达式,条件表达式,逻辑表达式。

    (1)算数运算符:+,-,*,/,%,字符串连接使用 concat() 方法。

    (2)条件运算符:!= == or eq >or gt <or lt >= <=

    (3)逻辑运算符:&& or and || or or ! or not

    (4)判断为空 empty

    (5)三元运算符:条件表达式 ? true :false

十一、jstl 标签库

  • jsp standard tag lib,jsp 自己并没有此标签,外部提供了可以在 jsp 页面中使用的标签。
  1. 引用标签库的 jar 包:uri=“http://java.sun.com/jsp/jstl/core”(核心标签库)

  2. jstl 包括多个标签库,比如核心标签库,sql 标签库,格式化标签库,输入输出标签库。主要使用核心标签库。

  3. 核心标签库中的主要标签

    (1)<c:if test=""> 标签内容 </c:if>:单分支条件判断,替换 if 语句,条件满足就执行标签内的内容,标签内的内容可以是任何内容。test 是条件表达式,必须使用 EL 表达式作为条件表达式,else 标签没有提供。

    (2)多条件选择标签,替换 if else if else 这样的语句,条件表达式是任意的。

    <c:choose>
        <c:when test="${num eq 20}">num == 20</c:when>
        <c:when test="${num eq 30}">num == 30</c:when>
        <c:otherwise>num not 20 and 30</c:otherwise>
    </c:choose>
    

    (3)循环标签库,替代 for i 循环,第二种对数组和 List 的遍历,index 表示元素下标,count 表示元素的位置(从1开始),last 表示是否最后一个,first 表示是否第一个。

    <%--遍历数组--%>
    <c:forEach begin="0" end="2" var="index" step="1">
        ${ary[index]}
    </c:forEach>
    
    <c:forEach items="${ary}" var="ele" varStatus="vs">
        ${ele} ${vs.index} ${vs.current} ${vs.first} ${vs.last} ${vs.step} ${vs.end} ${vs.count}<br/>
    </c:forEach>
    

    (4)请求重定向

    <c:redirect url="el.jsp"/>//替换response.sendRedirect()方法。
    

    (5)<a href="<c:url value=‘https://www.baidu.com’/>">百度</a>

    • 使用EL 表示和 jstl 标签替换作业中所有的java代码。

      <%--
        Created by IntelliJ IDEA.
        User: 华韵流风
        Date: 2021/4/23
        Time: 14:51
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java"  %>
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <html>
      <head>
          <title>用户登录</title>
      </head>
      <body>
      <form action="loginSvl" method="post">
          <p>用户名:<input type="text" name="username"></p>
          <p>密码:<input type="password" name="pass"></p>
          <input type="submit"/>
          <div>
              <c:if test="${requestScope.errinfo != null}">
                  ${requestScope.errinfo}
              </c:if>
          </div>
      </form>
      
      </body>
      </html>
      
      <%@ page import="com.zhong.Person" %>
      <%@ page import="java.text.SimpleDateFormat" %>
      <%@ page import="java.util.Map" %>
      <%--
        Created by IntelliJ IDEA.
        User: 华韵流风
        Date: 2021/4/23
        Time: 15:08
        To change this template use File | Settings | File Templates.
      --%>
      <%@ page contentType="text/html;charset=UTF-8" language="java" %>
      <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
      <%@ taglib prefix="f" uri="http://java.sun.com/jsp/jstl/fmt" %>
      <html>
      <head>
          <title>主页面</title>
          <script>
              function remove(id) {
                  let con= confirm("确认删除吗?");
                  if (con) {
                      location.href = "remove?id=" + id;
                  }
              }
          </script>
          <style>
              table tr td{
                  text-align: center;
              }
          </style>
      </head>
      <body>
      
      <c:if test="${sessionScope.user == null}">
          <c:redirect url="login.jsp"/>
      </c:if>
          
      <p>欢迎您!${sessionScope.user}</p>
      <button onclick="location.href = 'add.jsp'">添加</button>
      <button onclick="location.reload()">刷新</button>
      <table border="1" width="800" cellspacing="0" cellpadding="0">
          <tr>
              <td>id</td>
              <td>name</td>
              <td>date</td>
              <td>goods</td>
              <td>操作</td>
          </tr>
          <c:if test="${sessionScope.data != null}">
              <c:forEach items="${sessionScope.data.values()}" var="e1">
                  <tr>
                      <td>${e1.id}</td>
                      <td>${e1.name}</td>
                      <td><f:formatDate value="${e1.date}" pattern="yyyy-MM-dd"/></td>
                      <td><c:forEach items="${e1.goods}" var="e2">
                          ${e2}
                      </c:forEach></td>
                      <td><a href="javascript:remove(${e1.id})">删除</a></td>
                  </tr>
              </c:forEach>
          </c:if>
      </table>
      </body>
      </html>
      
    • 注意本次修改将数据由 application 放到了 session 里,其余不用修改。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Æ_华韵流风

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值