Servlet--Servlet技术

4.1Servlet基础

servlet是使用Java Servlet 接口(API)运行在Web应用服务器上的Java程序。与普通java程序不同,它是位于Web服务器内部的服务器端的Java应用程序,可以对Web浏览器或其他HTTP客户端程序发送的请求进行处理。

Servlet与Servlet容器

Servlet对象与普通的Java对象不同,它可以处理Web浏览器或其他HTTP客户端程序发送的HTTP请求,但前提条件是把Servlet对象布置到Servlet容器之中,也就是说,其运行需要Servlet容器的支持。

通常情况下,Servlet容器也就是指Web容器,如Tomcat,Jboss,Resin,WebLogic等,它们对Servlet进行控制。当一个客户端发送HTTP请求时,由容器加载Servlet对其进行处理并作出响应。

Servlet与Web容器的关系非常密切,在Web容器中Servlet主要经历了4个阶段。这4个阶段实质是Servlet的生命周期,由容器进行管理。


  1. 在Web容器启动或者客户机第一次请求服务时,容器将加载Servlet类并将其放到Servlet实例池。
  2. 当Servlet实例化后,容器将调用Servlet对象的init()方法完成Servlet的初始化操作,主要是为了让Servlet在处理请求之前做一些初始化的工作。
  3. 容器通过Servlet的service()方法处理客户端请求。在service()方法中,Servlet实例根据不同的HTTP请求类型作出不同处理,并在处理之后作出相应的响应。
  4. 在Web容器关闭时,容器调用Servlet对象的destroy()方法对资源进行释放。在调用此方法后,Servlet对象将被垃圾回收器回收。

Servlet技术特点

  • 方便,实用的API方法。Servlet对象对Web应用进行封装,针对HTTP请求提供了丰富的API方法,它可以处理表单提交数据,会话跟踪,读取和设置HTTP头信息等,对HTTP请求数据的处理非常方便,只需要调用相应的API方法即可。
  • 高效的处理方式。Servlet的一个实例对象可以处理多个线程的请求。当多个客户端请求一个Servlet对象时,Servlet为每一个请求分配一个线程,而提供服务的Servlet对象只有一个,因此说Servlet的多线程处理方式是非常高效的。
  • 跨平台。Servlet采用Java语言编写,因此它继承了Java的跨平台性,对于已编好的Servlet对象,可以运行在多种平台之中。
  • 更加灵活,扩展。Servlet与java平台的密切关系,它可以访问java平台丰富的类库;同时由于它采用Java语言编写,支持封装,继承等面向对象的优点,使其更具有应用的灵活性。此外,在编写过程中,它还对API接口进行了适当扩展
  • 安全性。Servlet采用了java的安全框架,同时Servlet容器还为Servlet提供了额外的功能,其安全性是非常高的。

Servlet技术功能

  • Servlet与普通Java应用程序不同,它可以处理HTTP请求以获取HTTP头信息,通过HttpServletRequest接口与HttpServletResponse接口对请求进行处理及回应。
  • Servlet可以处理业务逻辑之后,将动态的内容通过返回并输出到HTML页面中,与用户请求进行交互。
  • Servlet提供了强大的过滤功能,可针对请求类型进行过滤设置,为Web开发提供灵活性与扩展性。
  • Servlet可与其他服务器资源进行通信。

Servlet与JSP区别

Servlet是一种运行在服务器的java应用程序,先于JSP产生的。JSP是一种在Servlet规范之上的动态网页技术,通过JSP页面中嵌入Java代码,可与产生动态网页,也可以将其理解为是在Servlet技术的扩展,在JSP文件第一次被请求时,它会被编译为Servlet文件,再通过容器调用Servlet进行处理。

JSP虽然是在Servlet的基础上产生的,但与Servlet也存在一定的区别。

  • Servlet承担客户请求与业务处理的中间角色,需要调用固定的方法,将动态内容混合到静态之中产生HTML;而JSP页面中,可直接使用HTML标签进行输出,要比Servlet更显示层的意义。
  • Servlet中需要调用Servlet API接口处理HTTP请求,而在JSP页面中,则直接提供了内置对象进行处理。
  • Servlet的使用需要进行一定的配置,而JSP文件通过.jsp扩展名部署在容器中,容器对其自动识别,直接编译成Servlet进行处理。

Servlet代码结构

在Java中,通常所说的Servlet是指HttpServlet对象,在声明一个对象为Servlet时,需要继承HttpServlet类。HttpServlet类是Servlet接口的一个实现类,继承此类后,可以重写HttpServlet类的方法对HTTP请求进行处理。

package com.jsoft.util;

import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class FirstServlet
 */
@WebServlet("/FirstServlet")
public class FirstServlet extends HttpServlet {//初始化方法
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FirstServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Servlet#init(ServletConfig)
	 */
         public void init(ServletConfig config) throws ServletException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see Servlet#destroy()
         *销毁方法
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)<pre name="code" class="java">         *处理HTTP Get请求
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
         *处理HTTP Post请求      
         */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPut(HttpServletRequest, HttpServletResponse)      <pre name="code" class="java">         *处理HTTP Post请求
 */protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// TODO Auto-generated method stub}}

 
 在一个Servlet对象中,最常用的方法是doGet()和doPost()方法,这两个方法分别用于处理HTTP的Get和Post请求。eg:如果<form>表单对象所声明的method属性为post,提交到Servlet对象处理时,Servlet将调用doPost()方法进行处理。 

简单的Servlet程序

在编写Servlet时,不必重写Servlet对象中的所有方法,只需重写请求所使用方法即可。

public class SimpleServlet extends HttpServlet{
         public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContextType("text/html");
                PrintWriter out = response.getWriter();//向页面中打印一句话
                Out.println("This is Servlet.");
        }
} 
4.2Servlet开发
Servlet创建

两种创建方法:

  • 创建一个普通的java类,使这个类继承HttpServlet类,再通过手工配置web.xml文件注册Servlet对象。方法繁琐,通常不被采纳。
  • 直接通过IDE集成开发工具创建,步骤如下:

创建一个动态Web项目,然后在src上new一个Servlet。





package com.jsoft.util;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class FirstServlet
 */
public class FirstServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public FirstServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
	}

}
Servlet配置的相关元素

要使用Servlet对象正常地运行,需要进行适当的配置,以告知Web容器哪一个请求调用哪一个Servlet对象处理,对Servlet起到一个注册作用。Servlet的配置包含在web.xml文件中,主要通过以下两步进行设置:

1)声明Servlet对象

在 web.xml文件中,通过<servlet>标签声明一个Servlet对象。在此标签下包含两个主要子元素,分别 是<servlet-name>和<servlet-class>。其中<servlet-name>元素用于指定 Servlet的名称,此名称可以为自定义的名称。<servlet-class>元素用于指定Servlet对象的完整位置,包含 Servlet对象的包名和类名。

<servlet>
       <servlet-name>SimpleServlet</servlet-name>
       <servlet-class>com.jsoft.SimpleServlet</servlet-class>
 </servlet>
2)映射Servlet

在web.xml文件中声明了Servlet对象后,需要映射访问Servlet的URL。此操作使用<servlet-mapping>标签进行配置。<servlet-mapping>标签包含了两个子元素。分别为<servlet-name>和<url-pattern>。其中<servlet-name>元素与<servlet>标签中的<servlet-name>元素相对应,不可以随意命名。<url-pattern>元素用于映射访问URL。

<servlet-mapping>
       <servlet-name>SimpleServlet</servlet-name>
       <url-pattern>/SimpleServlet</url-pattern>
 </servlet-mapping>
Servlet的创建及配置

public class MyServlet extends HttpServlet{
         public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContextType("text/html");
                response.setCharacterEncoding("GBK
                PrintWriter out = response.getWriter();//向页面中打印一句话
                Out.println("This is MyServlet.");
                Out.flush();
                Out.close();
             }
} 
在web.xml文件中进行配置,其中访问的URL是/servlet/MyServlet

<servlet>
       <servlet-name>MyServlet</servlet-name>
       <servlet-class>com.jsoft.MyServlet</servlet-class>
 </servlet>
<pre name="code" class="html" style="color: rgb(0, 0, 0); font-size: 14px; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: 21px; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><servlet-mapping>
       <servlet-name>MyServlet</servlet-name>
       <url-pattern>/servlet/MyServlet</url-pattern>
 </servlet-mapping>

 
4.3Servlet API编程常用的接口和类 

Servlet是运行在服务器端的java应用程序,由Servlet容器对其进行管理,当用户对容器发送HTTP请求时,容器将通知相应的Servlet对象进行处理,完成用户与程序之间的交互。

Servlet接口

Servlet的运行需要Servlet容器的支持,Servlet容器通过调用Servlet对象提供了标准的API接口,对请求进行处理。在Servlet开发中,任何一个Servlet对象都要直接或间接地实现javax.servlet.Servlet接口。

Servlet接口中的方法及说明
方法说明
public void init(ServletConfig config)Servlet实例化后,Servlet容器调用此方法来完成初始化工作
public void service(ServletRequest request,ServletResponse response)此方法用于处理客户端的请求
public void destroy()当Servlet对象应该从Servlet容器中移除时,容器调用此方法,以便释放容器。
public ServletConfig getServletConfig()此方法用于获取Servlet对象的配置信息,返回ServletConfig对象
public String getServletInfo()此方法返回有关Servlet的信息,它是纯文本格式的字符串,如作者,版本等。
ServletConfig接口

ServletConfig接口位于javax.servlet包中,它封装了Servlet的配置信息,在Servlet初始化期间被传递。每一个Servlet都有且只有一个ServletConfig对象。

ServletConfig接口中的方法及说明
方法说明
public String getInitParameter(String name)此方法返回String类型名称为name的初始化参数值
public Enumeration getInitParameterNames()获取所有初始化参数名的枚举集合
public ServletContext getServletContext()用于获取Servlet上下文对象
public String getServletName()返回Servlet对象的实例名
HttpServletRequest 接口

HttpServletRequest接口位于javax.servlet.http包中,继承了javax.servlet.ServletRequest接口,是Servlet总的重要对象。

HttpServletRequest接口的常用方法及说明
方法说明
public String getContextPath()返回请求的上下文路径,此路径以“/"开关
public Cookie[] getCookies()返回请求中发送的所有cookie对象,返回值为cookie数组
public String getMethod()返回请求所使用的HTTP类型,如get,post
public String getQueryString()返回请求中参数的字符串形式,如请求MyServlet?username=mr,则返回username=mr
public String getRequestURL()返回主机名到请求参数之间部分的字符串形式
public StringBuffer getRequestURL()返回请求的URL,此URL中不包含请求的参数。注意此方法返回的数据类型为StringBuffer
public String getServletPath()返回请求URI中的Servlet路径的字符串,不包含请求中的参数信息
public HttpSession getSession()返回与请求关联的HttpSession对象
HttpServletResponse接口

HttpServletResponse接口位于javax.servlet.http包中,继承了javax.servlet.ServletResponset接口,是Servlet总的重要对象。

HttpServletResponse接口的常用方法及说明
方法说明
public void addCookie(Cookie cookie)向客户端写入cookie信息
public void sendError(int sc)发送一个错误状态码为sc的错误响应到客户端
public void sendError(int sc,String msg)发送一个包含错误状态码及错误信息的响应到客户端,参数sc为错误状态码,参数msg为错误信息
public void sendRedirect(String location)使用客户端重定向到新的URL,参数location为新的地址

public class MyServlet extends HttpServlet{
         public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try{
                         throw new Exception("数据库连接失败");
                     }catch(Exception e){
                         response.sedError(500,e.getMessage());
                     }
               }
} 
GenericServlet类

在编写一个Servlet对象时,必须实现javax.servlet.Servlet接口,但在Servlet接口中包含5个方法,也就是说创建一个Servlet对象要实现这5个方法,这样操作非常不方便。javax.servlet.GenericServlet类简化了此操作,实现了Servlet接口

public abstract class GenericServlet 
                  extends Object
                  implements Servlet,ServletConfig,Serializable
GenericServlet类是一个抽象类,分别实现了Servlet接口与ServletConfig接口。

HttpServlet类

HttpServlet类继承了GenericServlet类,通过对GenericServlet类的扩展可以方便地对HTTP请求进行处理与响应。

GenericServlet类实现了javax.servlet.Servlet接口,为程序开发提供了方便,但在实际开发过程中,大多数的应用都是使用Servlet出来HTTP协议的请求,并对请求作出响应,所以通过继承GenericServlet类任然不是很方便。javax.servlet.http.HttpServlet类对GenericServlet类进行了扩展,为HTTP请求的处理提供了灵活的方法。

public abstract class HttpServlet
           extends GenericServlet 
           implements Serializabl
HttpServlet类仍然是一个抽象类,实现了service()方法,并针对HTTP1.1中定义的7种请求类型提供了相应的方法doGet(),doPost(),doPut(),doHead(),doTrace(),doOptions(),

doDelete()。在这7个方法中,除了对doTrace(),doOptions()方法进行简单实现外,HttpServlet类并没有对其他方法进行实现,需要根据实际开发进行重写。

4.4Servlet过滤器

过滤器是Web程序中的可重用组件,在Servlet2.3规范中被引入,应用广泛。

过滤器概述

Servlet过滤器是客户端与目标资源间的中间层组件,用于拦截客户端的请求与响应信息。

当web容器接收到一个客户端请求时,将判断此请求是否与过滤器对象相关联,如果相关联,则将这一请求交给过滤器进行处理。在处理过程中,过滤器可以对请求进行操作,如更改请求中的信息数据。在过滤器处理完成后,再将这一请求交给其他业务进行处理。当所有业务处理完成,需要对客户端进行响应时,容器又将响应交给过滤器处理,过滤器完成处理之后将响应发送到客户端。

在web程序开发过程中,可以放置多个过滤器,如字符编码过滤器,身份验证过滤器等。在多个过滤器的处理方式中,容器首先将客户端请求交给第一个过滤器处理,处理完后交给下一个过滤器处理,以此类推,直到最后一个过滤器。当需要对客户端回应时,将按照相反的方向对回应进行处理,直到交给第一个过滤器,最后发送到客户端回应。


Filter API

过滤器与Servlet非常相似,它的使用主要是通过3个核心接口(分别为Filter接口,FilterChain接口与FilterConfig接口)进行操作。

1.Filter接口

Filter接口位于javax,servlet包中,与Servlet接口相似,当定义一个过滤器对象时需要实现此接口。

Filter接口中的方法及说明
方法说明
public void init(FilterConfig filterConfig)过滤器的初始化方法,容器调用此方法完成过滤的初始化。对于每一个Filter实例,此方法只被调用一次。
public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)此方法与Servlet的service()方法类似,当请求及响应交给过滤器时,过滤器调用此方法进行过滤处理
public void destroy()在过滤器生命周期结束时调用此方法,用于释放过滤器所占用的资源
2.FilterChain接口

FilterChain接口位于javax.servlet包中,此接口由容器进行实现,在FilterChain接口只包含一个方法,其方法声明如下:

 void doFilter(ServletRequest request,ServletResponse response,FilterChain chain)
               throws IOException,ServletException
此方法主要用于将过滤器处理的请求或响应传递给下一个过滤器对象。在对个过滤器的Web应用中,可以通过此方法进行传递。

3.FilterConfig接口

FilterConfig接口位于javax.servlet包中,此接口由容器进行实现,用于获取过滤器初始化期间的参数信息。

FilterConfig接口中的方法及说明
方法说明
public String getFilterName()返回过滤器的名称
public String getInitParameter(String name)返回初始化名称为name的参数值
public Enumeration getInitParameterNames()返回所有初始化参数名的枚举集合
public ServletContext getServletContext()返回Servlet的上下文对象
通过实现Filter接口来创建一个过滤器对象代码:

public class MyFilter implements Filter{
      //初始化方法
     public void init(FilterConfig arg0) throws ServletException{
      }
     //过滤器处理方法
     public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
     //传递给下一个过滤器
     chain.doFilter(request,response);
     }
     //销毁方法
     public void destroy(){
      }
}
过滤器的配置
在创建一个过滤器对象之后,需要对其进行配置才可以使用。过滤器的配置方法与Servlet的配置方法类似,都是通过web.xml文件进行配置。、

步骤如下:

1.声明过滤器对象

在web.xml文件中,通过<filter>标签声明一个过滤器对象。在此标签下包含3个常用子元素,分别为<filter-name>,<filter-class>和<init-param>。其中,<filter-name>元素用于指定过滤器的名称,此名称可以是自定义的名称;<filter-class>元素用于指定过滤器对象的完整位置,包含过滤器对象的包名与类名;<init-param>元素用于设置过滤器的初始化参数。<init-param>元素包含两个常用的子元素<param-name>和<param-value>,<param-name>元素用于声明初始化参数的名称,<param-value>元素用于指定初始化参数的值。配置方法如下:

<filter>
         <filter-name>CharacterEncodingFilter</filter-name>
         <filter-class>com.jsoft.util.CharacterEncodingFilter</filter-class>
         <init-param>
                       <param-name>encoding</param-name>
                       <param-value>GBK</param-value>
        </init-param>
 </filter>
2.映射过滤器
在web.xml文件中声明了过滤器之后,需要映射访问过的过滤的对象。此操作使用<filter-mapping>标签进行设置。在<filter-mapping>标签中主要需要配置过滤器的名称,过滤器关联的URL样式,过滤器对应的请求方式等。配置方法如下:

<filter-mapping>
     <filter-name>CharacterEncodingFilter</filter-name>
     <url-pattern>/*</url-pattern>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-name>元素用于指定过滤器的名称,此名称与<filter>标签中的<filter-name>相对应

<url-pattern>元素用于指定过滤器相关联的URL样式,设置为"/*"表示关联所有URL

<dispatcher>元素用于指定过滤器对应的请求方式。

元素的可选值及说明
可选值说明
REQUEST当客户端直接请求时,通过过滤器进行处理
INCLUDE当客户端通过RequestDispatcher对象的include()方法请求时,通过过滤器进行处理
FORWARD当客户端通过RequestDispatcher对象的forward()方法请求时,通过过滤器进行处理
ERROR当声明式异常产生时,通过过滤器进行处理
过滤器典型应用 -字符编码过滤器

由于java程序可以在多种平台下运行,其内部使用Unicode字符集来表示字符,所以处理中文数据会产生乱码的情况,需要对其进行编码转换才可以正常显示。

1)创建过滤器类CharacterEncodingFilter,init()方法用于读取过滤器的初始化参数,这个参数encoding为本例中所用到的字符编码;在doFilter()方法中,分别将request对象及response对象中的编码格式设置为读取到的编码格式,最后再destroy()方法中将其属性设置为null,将被java垃圾回收器回收。

public class CharacterEncodingFilter implements Filter{
    //字符编码(初始化参数)
    protected String encoding=null;
    //FilterConfig对象
    protected FilterConfig filterConfig =null;
    //初始化方法
     public void init(FilterConfig arg0) throws ServletException{
     //对filterConfig赋值
     this.filterConfig=filterConfig;
     //对初始化参数赋值
     this.encoding=filterConfig.getInitParameter("encoding");  
    }
     //过滤器处理方法
     public void doFilter(ServletRequest request,ServletResponse response,FilterChain chain) throws IOException,ServletException{
     //判断字符编码是否有效
     if(encoding !=null){
     //设置request字符编码
     request.setCharacterEncoding(encoding);
     //设置response字符编码
     response.setContentType("text/html;charset="+encoding);
     }
    //传递给下一个过滤器
     chain.doFilter(request,response);
     }
     //销毁方法
     public void destroy(){
       //释放资源
       this.encoding=null;
       this.filerConfig=null;
    }
}
2)在web.xml文件中,对过滤器进行配置。

<!--声明字符编码过滤器--!>
<filter>
         <filter-name>CharacterEncodingFilter</filter-name>
         <filter-class>com.jsoft.util.CharacterEncodingFilter</filter-class>
         <init-param>
                       <param-name>encoding</param-name>
                       <param-value>GBK</param-value>
        </init-param>
 </filter>
<!--映射字符编码过滤器--!>
<pre name="code" class="html"><filter-mapping>
     <filter-name>CharacterEncodingFilter</filter-name>
     <!--与所有请求关联--!>
     <url-pattern>/*</url-pattern>
     <!--设置过滤器对应的请求方式--!>
     <dispatcher>REQUEST</dispatcher>
     <dispatcher>FORWARD</dispatcher>
</filter-mapping>

 3)通过请求对过滤器进行验证。本例中通过表单向Servlet发送中文信息进行测试。 

<form action="MyServlet" method="post">
       <p>
            请输入你的中文名字:
            <input type="text" name="name">
            <input type="submit" value="提交">
       </p>
</form>
这一请求由Servlet对象的MyServlet类处理,此类使用doPost()方法接收表单的请求,并将表单的name属性输出到页面中

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		PrintWriter out=response.getWriter();
                //获取表单参数
                String name =request.getParameter("name");
                if(name !=null && !name.isEmpty()){
                          out.print("你好"+name);
                          out.print(",<br>欢迎来到我的主页。");
                 }else{
                          out.print("<br><a href="index.jsp"></a>");
                 }
                 out.flush();
                 out.close();
 }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值