43、Java Web开发:Servlet与JSP的综合运用

Java Web开发:Servlet与JSP的综合运用

1. 页面背景颜色修改

若要更改页面背景颜色,可在“Choose a new color”文本框中输入新的颜色值,然后点击“Change Color”按钮。颜色以“#”开头,后面跟随三个两位十六进制数,例如在某些示例中可能是“AA”、“FF”和“AA”。这些数字分别代表颜色中红、绿、蓝的含量,取值范围从最小值“00”到最大值“FF”。

若你对十六进制颜色不太熟悉,在测试Servlet时可尝试以下颜色:
| 颜色代码 | 颜色名称 |
| ---- | ---- |
| #FF0000 | 亮红色 |
| #00FF00 | 亮绿色 |
| #0000FF | 亮蓝色 |
| #FFAAAA | 浅红色 |
| #AAFFAA | 浅绿色 |
| #AAAAFF | 浅蓝色 |
| #FFCC66 | 奶油糖果色 |

2. Java Servlet概述

javax.servlet和javax.servlet.http包中的类主要用于与Web服务器交换信息。Java Servlet是通用网关接口(Common Gateway Interface)的替代方案,是编程语言在Web上检索和呈现数据的常用方式。

Servlet可以利用Java语言的所有特性(图形用户界面除外),因此可用于创建复杂的Web应用程序。如今,Servlet被广泛应用于运行电子商务店面,接收用户订单,连接产品数据库,并在用户购买时收集账单信息。此外,它还用于运行讨论板、内容管理系统和许多其他类型的动态生成的网站。

2.1 Java Applet与Servlet通信

若要使Java Applet与Servlet通信,若希望Applet在与Servlet通信后继续运行,Servlet必须与包含Applet的Web页面位于同一台机器上。出于安全原因,Applet不能与托管它的机器以外的任何机器建立网络连接。

若要让Applet在Web浏览器中加载Servlet,可调用Applet的getAppletContext()方法获取一个AppletContext对象,然后调用该对象的showDocument(URL)方法,并将Servlet的URL作为参数传入。

2.2 小测验

以下是几个问题,用于复习相关知识:
1. 如果一个Servlet同时被五个Web用户运行,Servlet的init()方法会被调用多少次?
a. 5
b. 1
c. 0 - 1
2. 以下哪种技术不属于Tomcat的一部分?
a. Java Servlet
b. JavaServer Pages
c. Java API for XML Processing
3. 当从Web页面上的表单提交数据,并且数据作为URL的一部分显示在浏览器的地址栏中时,使用的是哪种请求?
a. GET请求
b. POST请求
c. HEAD请求

答案如下:
1. c. init()方法在Web服务器首次加载Servlet时被调用。这可能在这五个用户请求Servlet之前就已经发生,因此它可能调用init()一次,也可能根本不调用。
2. c. Java API for XML Processing
3. a. GET请求将表单字段编码到URL中,然后将该URL作为请求提交给Web浏览器。

2.3 认证练习

以下是一个可能在Java编程认证测试中遇到的问题,请在不查看相关材料或使用Java编译器测试代码的情况下回答。

public class CharCase {
    public static void main(String[] arguments) {
        float x = 9;
        float y = 5;
        char c = '1';
        switch (c) {
            case 1:
                x = x + 2;
            case 2:
                x = x + 3;
            default:
                x = x + 1;
        }
        System.out.println("Value of x: " + x);
    }
}

当x被显示时,它的值是多少?
a. 9.0
b. 10.0
c. 11.0
d. 程序将无法编译

答案可在相关网站查询。

2.4 练习

为扩展你对所学主题的了解,可尝试以下练习:
- 创建SetColor Servlet的修改版本,使其还能让你选择页面上文本的不同颜色。
- 创建一个Servlet,将表单中输入的数据存储在文件中。

部分练习的解决方案可在相关网站获取。

3. JavaServer Pages(JSP)介绍

Java Servlet便于动态生成HTML文本,生成随用户输入和数据变化的页面。然而,Servlet在生成不变的HTML文本时较为困难,因为使用Java语句输出HTML既繁琐又乏味。而且,每次需要更改HTML时,都需要Java程序员进行编辑、重新编译并部署到Web上,很少有组织愿意让非程序员承担这项任务。

JavaServer Pages(JSP)是解决这一问题的方案,它允许创建将静态HTML与Servlet输出以及Java语言元素(如表达式和Java语句)混合的文档。

3.1 JSP概述

JSP是Sun Microsystems和Apache Software Foundation的Tomcat规范的一部分,它是Servlet的补充,而非替代。JSP便于分离两种Web内容:
- 静态内容:Web页面中不变的部分,如在线商店对每个产品的描述。
- 动态内容:Web页面中由Servlet生成的部分,如商店中每个产品的定价和可用性数据,这些数据会随商品售罄而变化。

3.2 创建JSP

创建JSP的方式与创建HTML文档类似,可使用文本编辑器或Web发布程序(如Microsoft FrontPage 2002或Macromedia Dreamweaver)。保存页面时,使用.jsp文件扩展名来表明该文件是JSP而非HTML文档。然后,该页面可以像HTML文档一样发布在Web服务器上(前提是服务器支持Tomcat)。

当用户首次请求JSP时,Web服务器会编译一个新的Servlet来呈现该页面。此过程会导致页面加载缓慢,但后续请求不会再出现这种情况,因为服务器会保留这个Servlet以供后续使用。

3.3 JSP的组成元素

JSP由三种元素组成,每种元素都有类似于HTML的特殊标记:
- Scriptlets:页面加载时执行的Java语句,每个语句都被<%和%>标记包围。
- Expressions:被求值的Java表达式,其输出会显示在页面上,这些表达式被<%=和%>标记包围。
- Declarations:用于创建实例变量和处理页面编译成Servlet时所需的其他设置任务的语句,这些语句被<%!和%>标记包围。

3.4 使用表达式

以下是一个包含表达式的JSP示例,该表达式调用了java.util.Date()构造函数,用于显示当前时间和日期。

<!-- time.jsp -->
<html>
<head>
    <title>Clock</title>
</head>
<body>
    <h1 align="Center">
        <%= new java.util.Date() %>
    </h1>
</body>
</html>

将该文件保存后,上传到Web服务器上存储其他Web页面的文件夹中。与Java Servlet不同,JSP可以放在Web上可访问的任何文件夹中。

当首次加载该页面的URL时,Web服务器会将JSP编译成Servlet。此后,服务器会保留这个Servlet,后续请求将不再进行编译。

在JSP的表达式和其他元素中,可以引用以下几个Servlet变量:
- application:用于与Web服务器通信的Servlet上下文。
- config:用于查看Servlet初始化方式的Servlet配置对象。
- out:Servlet输出流。
- request:HTTP Servlet请求。
- response:HTTP Servlet响应。
- session:当前的HTTP会话。

以下是另一个示例,展示了如何在页面上使用request变量:

<!-- environment.jsp -->
<html>
<head>
    <title>Environment Variables</title>
</head>
<body>
    <ul>
        <li>Accept: <%= request.getHeader("Accept") %>
        <li>Accept-Encoding: <%= request.getHeader("Accept-Encoding") %>
        <li>Connection: <%= request.getHeader("Connection") %>
        <li>Content-Length: <%= request.getHeader("Content-Length") %>
        <li>Content-Type: <%= request.getHeader("Content-Type") %>
        <li>Cookie: <%= request.getHeader("Cookie") %>
        <li>Host: <%= request.getHeader("Host") %>
        <li>Referer: <%= request.getHeader("Referer") %>
        <li>User-Agent: <%= request.getHeader("User-Agent") %>
    </ul>
</body>
</html>

在该页面的第7 - 15行,每行都包含一个对getHeader()方法的调用,用于检索不同的HTTP请求头。输出的值取决于Web服务器和所使用的Web浏览器。

3.5 使用Scriptlets

在JSP中还可以使用Java语句(如调用方法、为变量赋值、创建条件语句等),这些语句以<%标记开始,以%>标记结束,多个语句可以包含在这些标记内。

以下是一个名为shopforbooks.jsp的Web页面示例,它显示了一个书籍列表,并提供了指向每本书在在线书店页面的超链接。

<!-- shopforbooks.jsp -->
<html>
<head>
    <title>Shop for Books</title>
</head>
<body>
    <h2 align="Left">Favorite Books</h2>
    <%
        String[] bookTitle = { "Catch-22", "Something Happened", "Good as Gold" };
        String[] isbn = { "0684833395", "0684841215", "0684839741" };
        String amazonLink = "http://www.amazon.com/exec/obidos/ASIN/";
        String bnLink = "http://shop.bn.com/booksearch/isbnInquiry.asp?isbn=";
        String store = request.getParameter("store");
        if (store == null) {
            store = "Amazon";
        }
        for (int i = 0; i < bookTitle.length; i++) {
            if (store.equals("Amazon"))
                out.println("<li><a href=\"" + amazonLink + isbn[i] + "\">" + bookTitle[i] + "</a>");
            else
                out.println("<li><a href=\"" + bnLink + isbn[i] + "\">" + bookTitle[i] + "</a>");
        }
    %>
    <p>Preferred Bookstore:
    <form action="shopforbooks.jsp" method="POST">
        <p><input type="radio" value="Amazon" <%= (store.equals("Amazon") ? " checked" : "") %> name="store"> Amazon.Com
        <p><input type="radio" value="BN" <%= (store.equals("BN") ? " checked" : "") %> name="store"> Barnes & Noble
        <p><input type="submit" value="Change Store">
    </form>
</body>
</html>

该JSP页面底部包含一个表单,允许用户选择他们喜欢的在线书店。在第28行,表单提交到该JSP页面的URL,因为JSP实际上也是Servlet,所以它们也可以接收通过POST或GET发送的表单数据。

3.6 使用Declarations

JSP中可以插入的最后一种元素是声明,它是在页面编译成Servlet时定义变量或方法的语句。声明通常与表达式和Servlet结合使用,被<%!和%>标记包围。

以下是一个使用声明来显示页面访问计数器的JSP示例:

<!-- counter.jsp -->
<%@ page import="counter.*" %>
<html>
<head>
    <title>Counter Example</title>
</head>
<body>
    <h1>JSP Stats</h1>
    <%! Counter visits; %>
    <%! int count; %>
    <%
        visits = new Counter(application.getRealPath("counter.dat"));
        count = visits.getCount() + 1;
    %>
    <p>This page has been loaded <%= count %> times. 
    <% visits.setCount(count); %>
</body>
</html>

在尝试这个页面之前,需要创建一个辅助类Counter,其代码如下:

// Counter.java
package counter;

import java.io.*;
import java.util.*;

public class Counter {
    private int count;
    private String filepath;

    public Counter(String inFilepath) {
        count = 0;
        filepath = inFilepath;
    }

    public int getCount() {
        try {
            File countFile = new File(filepath);
            FileReader file = new FileReader(countFile);
            BufferedReader buff = new BufferedReader(file);
            String current = buff.readLine();
            count = Integer.parseInt(current);
            buff.close();
        } catch (IOException e) {
            // do nothing
        } catch (NumberFormatException nfe) {
            // do nothing
        }
        return count;
    }

    public void setCount(int newCount) {
        count = newCount;
        try {
            File countFile = new File(filepath);
            FileWriter file = new FileWriter(countFile);
            BufferedWriter buff = new BufferedWriter(file);
            String output = "" + newCount;
            buff.write(output, 0, output.length());
            buff.close();
        } catch (IOException e) {
            // do nothing
        }
    }
}

成功编译该类后,将其存储在Web服务器上与之前创建的Java Servlet相同的文件夹中。虽然Counter类不是Servlet,但Tomcat会在该文件夹中查找JSP页面引用的类。

3.7 创建Web应用程序

通过结合Java类、Servlet和JSP,可以创建交互式Web应用程序,这些应用程序能够根据用户输入以复杂、连贯的方式动态生成内容。

为了展示Java技术的多个方面如何在Web上协同工作,下面将创建一个名为Guestbook的Web应用程序,该应用程序允许访问者为网站创建者留下消息。

Guestbook项目由以下三部分组成:
- guestbook.jsp:一个JSP页面,用于显示Web服务器上文本文件中的留言簿条目,并提供一个表单,让访问者可以添加条目。
- guestbookpost.jsp:一个JSP页面,用于将新的留言簿条目保存到文本文件中。
- Guestbook.java:一个Java类,用于在将留言簿条目保存之前过滤掉一些字符。

3.7.1 guestbook.jsp代码
<!-- guestbook.jsp -->
<%@ page import="java.util.*,java.io.*" %>
<html>
<head>
    <title>Visitors Who Signed our Guestbook</title>
</head>
<body>
    <h3>Visitors Who Signed our Guestbook</h3>
    <%
        String id = request.getParameter("id");
        boolean noSignatures = true;
        try {
            String filename = application.getRealPath(id + ".gbf");
            FileReader file = new FileReader(filename);
            BufferedReader buff = new BufferedReader(file);
            boolean eof = false;
            while (!eof) {
                String entry = buff.readLine();
                if (entry == null)
                    eof = true;
                else {
                    StringTokenizer entryData = new StringTokenizer(entry, "^");
                    String name = (String) entryData.nextElement();
                    String email = (String) entryData.nextElement();
                    String url = (String) entryData.nextElement();
                    String entryDate = (String) entryData.nextElement();
                    String ip = (String) entryData.nextElement();
                    String comments = (String) entryData.nextElement();
                    out.print("<p>From: " + name);
                    if (!email.equals("None"))
                        out.println(" <" + email + "><br>");
                    else
                        out.println("<br>");
                    if (!url.equals("None"))
                        out.println("Home Page: <a href=\"" + url + "\">" + url + "</a><br>");
                    out.println("Date: " + entryDate + "<br>");
                    out.println("IP: " + ip);
                    out.println("<blockquote>");
                    out.println("<p>" + comments);
                    out.println("</blockquote>");
                    noSignatures = false;
                }
            }
            buff.close();
        } catch (IOException e) {
            out.println("<p>This guestbook could not be read because of an error.");
            log("Guestbook Error: " + e.toString());
        }
        if (noSignatures)
            out.println("<p>No one has signed our guestbook yet.");
    %>
    <h3>Sign Our Guestbook</h3>
    <form method="POST" action="guestbookpost.jsp">
        <table border="0" cellpadding="5" cellspacing="0" width="100%">
            <tr>
                <td width="15%" valign="top" align="right">Your Name:</td>
                <td width="50%"><input type="text" name="name" size="40"></td>
            </tr>
            <tr>
                <td width="15%" valign="top" align="right">Your E-mail Address:</td>
                <td width="50%"><input type="text" name="email" size="40"></td>
            </tr>
            <tr>
                <td width="15%" valign="top" align="right">Your Home Page:</td>
                <td width="50%"><input type="text" name="url" size="40"></td>
            </tr>
            <tr>
                <td width="15%" valign="top" align="right">Your Comments:</td>
                <td width="50%"><textarea rows="6" name="comments" cols="40"></textarea></td>
            </tr>
        </table>
        <p align="center"><input type="submit" value="Submit" name="B1">
        <input type="reset" value="Reset" name="Reset"></p>
        <input type="hidden" name="id" value="<%= id %>">
    </form>
</body>
</html>

保存该页面后,将其存储在支持Tomcat的Web服务器上任何可以存储页面的文件夹中。只要有一个空的留言簿文件,就可以在项目的其他部分完成之前进行测试。创建该文件的方法是在系统上保存一个空的文本文件,并将其命名为cinema.gbf,然后将其存储在与guestbook.jsp相同的Web文件夹中。

当加载该JSP页面时,必须包含一个参数来指定要加载的留言簿的ID,例如:http://www.java21pro.com/guestbook.jsp?id=cinema

3.7.2 guestbookpost.jsp代码
<!-- guestbookpost.jsp -->
<%@ page import="java.util.*,java.io.*,guestbook.*" %>
<html>
<head>
    <title>Thank You For Signing Our Guestbook</title>
</head>
<body>
    <h3>Thank You For Signing Our Guestbook</h3>
    <%
        String id = request.getParameter("id");
        String[] entryFields = { "name", "email", "url", "comments" };
        String[] entry = new String[4];
        for (int i = 0; i < entryFields.length; i++) {
            entry[i] = Guestbook.filterString(request.getParameter(entryFields[i]));
        }
        Date now = new Date();
        String entryDate = now.toString();
        String ip = request.getRemoteAddr();
    %>
    <p>Your entry looks like this:
    <p>From: <%= entry[0] %><%= (!entry[1].equals("None") ? "<"+entry[1]+">" : "") %><br>
    <% if (!entry[2].equals("None")) { %>
    Home Page: <a href="<%= entry[2] %>"><%= entry[2] %></a><br>
    <% } %>
    Date: <%= entryDate %><br>
    IP: <%= ip %>
    <blockquote>
        <p><%= entry[3] %>
    </blockquote>
    <%
        try {
            boolean append = true;
            String filename = application.getRealPath(id + ".gbf");
            FileWriter fw = new FileWriter(filename, append);
            BufferedWriter fileOut = new BufferedWriter(fw);
            String newEntry = entry[0] + "^" + entry[1] + "^" + entry[2] + "^" + entryDate + "^" + ip + "^" + entry[3];
            fileOut.write(newEntry, 0, newEntry.length());
            fileOut.newLine();
            fileOut.close();
        } catch (IOException e) {
            out.println("<p>This guestbook could not be updated because of an error.");
            log("Guestbook Error: " + e.toString());
        }
    %>
    <p><a href="guestbook.jsp?id=<%= id %>">View the Guestbook</a>
</body>
</html>

guestbookpost.jsp页面用于收集Web表单中的数据,去除不能放入留言簿的字符,并将结果存储在文本文件中。每个留言簿都有自己的文件,文件名以留言簿的ID参数开头,以.gbf文件扩展名结尾。

3.7.3 Guestbook.java代码

在尝试Guestbook应用程序之前,需要创建一个Java类Guestbook,用于在留言簿条目发布之前过滤掉一些不需要的文本。由于留言簿条目在文件中的存储方式,有三个字符不能包含在留言簿中:
- 插入符号(^)
- 回车符(Java中整数值为13)
- 换行符(Java中整数值为10)

以下是Guestbook类的代码:

// Guestbook.java
package guestbook;

public class Guestbook {
    public static String filterString(String input) {
        input = replaceText(input, '^', ' ');
        input = replaceText(input, (char)13, ' ');
        input = replaceText(input, (char)10, ' ');
        return input;        
    }

    private static String replaceText(String inString, char oldChar, char newChar) {
        while (inString.indexOf(oldChar) != -1) {
            int oldPosition = inString.indexOf(oldChar);
            StringBuffer data = new StringBuffer(inString);
            data.setCharAt(oldPosition, newChar);
            inString = data.toString();
        }
        return inString;
    }
}

通过以上内容,我们详细介绍了Java Servlet和JSP的相关知识,包括页面背景颜色修改、Servlet的基本概念、Applet与Servlet的通信、JSP的组成元素及使用方法,以及如何创建一个完整的Web应用程序Guestbook。希望这些内容能帮助你更好地理解和应用Java Web开发技术。

4. 总结与展望

4.1 技术总结

在Java Web开发领域,Servlet和JSP是两个至关重要的技术。Servlet主要负责与Web服务器进行信息交换,能够利用Java语言的强大功能(除图形用户界面外)创建复杂的Web应用程序。它广泛应用于电子商务、讨论板、内容管理系统等众多动态网站中。

而JSP则是Servlet的有力补充,它允许开发者将静态HTML与动态的Servlet输出以及Java语言元素相结合,极大地提高了开发效率。JSP由Scriptlets、Expressions和Declarations三种元素组成,每种元素都有其独特的用途和标记方式。通过这些元素,开发者可以在页面中灵活地使用Java语句、表达式和声明变量,实现动态内容的生成。

4.2 开发流程回顾

下面通过一个mermaid流程图来回顾一下使用Servlet和JSP开发Web应用程序的基本流程:

graph LR
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A(需求分析):::process --> B(设计架构):::process
    B --> C(创建Servlet):::process
    B --> D(创建JSP页面):::process
    C --> E(部署到Web服务器):::process
    D --> E
    E --> F(测试与调试):::process
    F --> G(上线发布):::process

从流程图可以看出,开发一个完整的Web应用程序需要经过需求分析、架构设计、Servlet和JSP的创建、部署、测试以及最终的上线发布等步骤。每个步骤都紧密相连,缺一不可。

4.3 未来发展趋势

随着互联网技术的不断发展,Java Web开发也在不断演进。未来,Servlet和JSP可能会与更多的新技术相结合,如微服务架构、容器化技术(如Docker)和云计算平台(如AWS、阿里云等)。这些新技术将进一步提高Web应用程序的性能、可扩展性和可靠性。

同时,随着前端技术的飞速发展,前后端分离的开发模式也越来越受到青睐。在这种模式下,Servlet和JSP可能更多地负责后端的业务逻辑处理,而前端则使用更专业的前端框架(如Vue.js、React.js等)来实现页面的展示和交互。

4.4 学习建议

对于想要深入学习Java Web开发的开发者来说,除了掌握Servlet和JSP的基础知识外,还应该不断学习和实践。可以通过阅读相关的技术书籍、参加线上线下的培训课程、参与开源项目等方式来提升自己的技能。

此外,多做项目实践也是非常重要的。可以从一些简单的项目开始,逐步积累经验,然后尝试开发一些复杂的Web应用程序。在实践过程中,要善于总结问题和解决问题,不断优化自己的代码和开发流程。

5. 常见问题解答

5.1 Servlet相关问题

5.1.1 Servlet的init()方法调用次数问题

在实际开发中,经常会遇到Servlet的init()方法调用次数的疑问。当多个Web用户同时请求一个Servlet时,init()方法的调用次数取决于Web服务器加载Servlet的时机。如果Web服务器在所有用户请求之前就已经加载了Servlet,那么init()方法只会被调用一次;如果在用户请求时Servlet还未加载,那么init()方法会在首次加载时被调用。所以,init()方法可能被调用一次,也可能不被调用。

5.1.2 Servlet与Applet通信问题

若要实现Java Applet与Servlet的通信,需要注意安全限制。由于安全原因,Applet只能与托管它的机器上的Servlet进行通信。如果要让Applet在Web浏览器中加载Servlet,可以通过调用Applet的getAppletContext()方法获取AppletContext对象,然后调用该对象的showDocument(URL)方法,并将Servlet的URL作为参数传入。

5.2 JSP相关问题

5.2.1 JSP编译问题

当用户首次请求JSP页面时,Web服务器会将其编译成Servlet。这个过程可能会导致页面加载缓慢,但后续请求不会再出现这种情况,因为服务器会保留编译后的Servlet。如果在编译过程中出现问题,可能是由于代码语法错误、服务器配置问题或缺少相关的依赖库等原因导致的。需要仔细检查代码和服务器配置,确保一切正常。

5.2.2 JSP中变量引用问题

在JSP的表达式和其他元素中,可以引用一些Servlet变量,如application、config、out、request、response和session等。这些变量在Servlet开发中也经常使用,需要熟悉它们的用途和方法。例如,request变量可以用于获取HTTP请求的相关信息,response变量可以用于发送HTTP响应。

5.3 综合问题

5.3.1 如何优化Web应用程序性能

要优化Web应用程序的性能,可以从多个方面入手。首先,要合理设计数据库,优化数据库查询语句,减少不必要的数据库访问。其次,对于静态资源(如图片、CSS、JavaScript等),可以进行压缩和缓存,减少网络传输时间。此外,还可以使用负载均衡技术来分担服务器的压力,提高系统的并发处理能力。

5.3.2 如何确保Web应用程序的安全性

Web应用程序的安全性至关重要。为了确保安全性,需要对用户输入进行严格的验证和过滤,防止SQL注入、XSS攻击等安全漏洞。同时,要对敏感数据进行加密处理,如用户密码、支付信息等。此外,还可以使用HTTPS协议来加密数据传输,防止数据在传输过程中被窃取。

6. 结语

通过本文的介绍,我们全面了解了Java Web开发中Servlet和JSP的相关知识,包括页面背景颜色修改、Servlet的基本概念、Applet与Servlet的通信、JSP的组成元素及使用方法,以及如何创建一个完整的Web应用程序Guestbook。同时,我们还对开发流程进行了回顾,探讨了未来的发展趋势,并解答了一些常见的问题。

希望本文能够帮助你更好地掌握Java Web开发技术,在实际项目中能够灵活运用Servlet和JSP,开发出高效、稳定、安全的Web应用程序。在未来的学习和实践中,不断探索和创新,将Java Web开发技术推向新的高度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值