深入学习(一)—— Servlet的运行流程和源码分析

R语言计算植物群落重要值:从基础概念到优势种判定 在植被生态学研究中,重要值是衡量物种在群落中地位的核心指标,它综合了相对多度、相对频度与相对显著度三个维度,能够客观反映物种的数量优势、分布广度与空间占据能力。理解重要值的生态学逻辑,是开展群落分类、优势种判定及多样性分析的基础。而R语言凭借其批量处理、可复现和与后续多元统计无缝衔接的优势,成为生态学研究者处理样方数据的高效工具。从野外记录的宽表到标准化长表,再到分组汇总计算相对指标,R语言能够显著提升数据处理效率与准确性。本文以实测群落数据为例,系统梳理重要值的两种算法口径、基于dplyr和tidyr的完 阅读详情

现在市面上的框架越来越多,从SSH到SSM,再到现在的SpringBoot,微服务,技术更新迭代的速度之快,让学习者都有点应接不暇,有点被技术鞭策着,去学习最新技术的感觉。很多人,在追逐框架技术的道路上会或多或少有些迷失,包括我自己,在追逐框架技术的道路上停不下来,刹不住车。该给自己降降温了,该回头把最基本,最重要的基础-JavaWeb重温一遍了。

学习了这么多框架,从SSH、SSM再到SpringBoot,学会了如何使用,学会了编写CRUD,但都不愿意去啃运行流程、运行源码这块硬骨头。然而,学的越多,越感觉有点底气不足,有点违背了万丈高楼平地起的道理。接下来,就总结一系列关于JavaWeb基础、SSH、SSM运行原理和源码分析的博文,来鞭策自己,让自己慢下来,静下心来。

Servlet

Servlet是JavaWeb里最重要的内容了,这一块所包含的知识点,也是非常的多的。Servlet为创建基于web的应用程序提供了基于组件、独立于平台的方法。

servlet实际上就是一个类,是基于Java服务端的java类,在servlet容器的基础上,servlet就可以在服务端进行运行。

以下是servlet-api.jar的目录结构,servlet-api.jar在tomcat安装目录下的lib文件夹中:

为了方便查看源码,这里直接在IDEA中查看源码。

让我们来看看HelloWorld类的Diagram图。

可以看到,HelloWorld这个Servlet的关系图有:

  • 两个顶级接口
    • Servlet
    • ServletConfig
  • 接口的实现类
    • GenericServlet
  • 基于HTTP协议的实现类
    • HttpServlet

 

 顶级接口:Servlet

package javax.servlet;
import java.io.IOException;

public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

 抽象类:GenericServlet

package javax.servlet;

import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;

public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {
    
    ...

    public GenericServlet() {
    }

    public void destroy() {
    }

    ...

    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    public void init() throws ServletException {
    }

    public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

}

 实现类:HttpServlet

package javax.servlet.http;
...

public abstract class HttpServlet extends GenericServlet {

    ...    

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(405, msg);
        } else {
            resp.sendError(400, msg);
        }

    }

    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getMethod();
        long lastModified;
        if (method.equals("GET")) {
            lastModified = this.getLastModified(req);
            if (lastModified == -1L) {
                this.doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader("If-Modified-Since");
                } catch (IllegalArgumentException var9) {
                    ifModifiedSince = -1L;
                }

                if (ifModifiedSince < lastModified / 1000L * 1000L) {
                    this.maybeSetLastModified(resp, lastModified);
                    this.doGet(req, resp);
                } else {
                    resp.setStatus(304);
                }
            }
        } else if (method.equals("HEAD")) {
            lastModified = this.getLastModified(req);
            this.maybeSetLastModified(resp, lastModified);
            this.doHead(req, resp);
        } else if (method.equals("POST")) {
            this.doPost(req, resp);
        } else if (method.equals("PUT")) {
            this.doPut(req, resp);
        } else if (method.equals("DELETE")) {
            this.doDelete(req, resp);
        } else if (method.equals("OPTIONS")) {
            this.doOptions(req, resp);
        } else if (method.equals("TRACE")) {
            this.doTrace(req, resp);
        } else {
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[]{method};
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(501, errMsg);
        }

    }

    /* 服务器先调用这个公共的service方法,然后进行request和response强转,然后再调用重载的service方法 */
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
        HttpServletRequest request;
        HttpServletResponse response;
        try {
            request = (HttpServletRequest)req;
            response = (HttpServletResponse)res;
        } catch (ClassCastException var6) {
            throw new ServletException("non-HTTP request or response");
        }

        this.service(request, response);
    }    

}

HelloWorld.java

package com.test;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

public class HelloWorld extends HttpServlet {
    private String msg;

    /**
     * 初始化过程
     * @throws ServletException
     */
    public void init() throws ServletException {
        msg = "Hello Servlet!";
    }

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //设置响应内容类型
        resp.setContentType("text/html");

        //业务逻辑
        PrintWriter out = resp.getWriter();
        out.print("<h1>" + msg + "</h1>");

    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

 

 

先简单的说一下本地运行的Servlet运行的流程:

① 在浏览器输入url,发送请求 ——> ② 请求发送给服务器 ——> ③ 服务器读取web.xml中的servlet,匹配请求url

——> ④ 进入servlet生命周期 ——> ⑤ 调用service()方法 ——> ⑥ 根据请求方式调用doGet或doPost方法

——> ⑦ 处理业务逻辑,返回json/html/xml

每步流程的粗略总结:

①~②:在浏览器中输入url,敲回车。浏览器发送请求,包括请求方法URI协议、版本,请求头,请求正文。然后请求发送至tomcat服务器,tomcat服务器收到请求后,会创建一个request对象,然后把收到的请求信息封装到request对象里面。

③:tomcat加载完web.xml后,会等待用户发送请求。当tomcat服务器收到用户发送的请求后,会调用一个mapper的internalMapWrapper方法,这方法是org.apache.tomcat.util.http.mapper.Mapper类中的一个方法。然后找到对应url-pattern的servlet。

④:进入servlet生命周期(servlet的init()方法早在servlet容器也就是tomcat启动的时候就调用了,并且只调用一次。)然后调用service()方法来处理客户端的请求。

⑤~⑥:调用service()方法,在该方法中,将ServletRequest和ServletResponse强转为HttpServletRequest和HttpServletResponse,然后重载service()方法。在重载service()方法里,会根据请求方式来判断是调用doGet()还是doPost()方法。

⑦:在对应的doGet()或doPost()方法里处理业务逻辑,返回json/html/xml作为响应。这个响应会返回给tomcat服务器,然后tomcat服务器再对这个响应进行包装、渲染,并以HTTP响应的形式发送给客户端。

如果tomcat服务器关闭或重启,servlet就被destroy,然后被垃圾回收器进行垃圾回收。

 

总结一下Servlet的三种实现方式:

  1. 实现顶级Servlet接口
  2. 继承抽象类GenericServlet
  3. 继承抽象类HttpServlet

需要注意的是,顶级Servlet和抽象类GenericServlet都只有service方法,所以当收到客户端发送过来的请求后,需要判断是POST还是GET请求。

 

Servlet容器

什么是Servlet容器呢?Servlet容器实际上就是tomcat。tomcat的一个重要作用就是作为Servlet容器,用于在发送的请求和响应之上提供网络服务,解码基于MIME的请求,格式化MIME的响应。Servlet必须部署到Servlet容器中,由容器来实例化Servlet和收到请求后调用Servlet的方法(例如doPost和doGet方法)。

以Servlet容器的角度来看看客户端发送请求,服务端响应的过程。

用户通过单击某个链接或者直接在浏览器的地址栏中输入URL来访问Servlet,Web服务器接收到该请求后,并不是将 请求直接交给Servlet,而是交给Servlet容器。Servlet容器实例化Servlet,调用Servlet的一个特定方法对请求进行处理, 并产生一个响应。这个响应由Servlet容器返回给Web服务器,Web服务器包装这个响应,以HTTP响应的形式发送给Web浏览器。

总结一下Servlet容器的作用:

提供作用作用内容
通信支持利用容器提供的方法,你能轻松的让servlet与web服务器对话,而不用自己建立serversocket、监听某个端口、创建流等 等。容器知道自己与web服务器之间的协议,所以你的servlet不用担心web服务器(如Apache)和你自己的web代码之间的API,只需要考 虑如何在servlet中实现业务逻辑(如处理一个订单)
生命周期管理servlet容器控制着servlet的生与死,它负责加载类、实例化和初始化servlet,调用servlet方法,以及使servlet实例被垃圾回收,有了servlet容器,你不需要太多的考虑资源管理。
多线程支持容器会自动为它所接收的每个servlet请求创建一个新的java线程。针对用户的请求,如果servlet已经运行完相应的http服务方法,这个线程就会结束。这并不是说你不需要考虑线程安全性,其实你还会遇到同步问题,不过这样能使你少做很多工作。
声明方式实现安全利用servlet容器,你可以使用xml部署描述文件来配置和修改安全性,而不必将其硬编码写到servlet类代码中。
JSP支持servlet容器负责将jsp代码翻译为真正的java代码。

 

 

Microchip Studio 7.0 从下载到项目调试:AVR开发者的完整入门指南(附常见问题解决) 本文为AVR开发者提供了Microchip Studio 7.0从下载安装到项目调试的完整入门指南。详细介绍了如何获取安装包、创建第一个AVR工程项目,并配置编译与调试环境。同时,文章重点解决了开发过程中常见的编译错误和仿真问题,帮助开发者快速上手并高效使用这一官方集成开发环境。 阅读详情

相关推荐

大疆C板使用C610电调驱动M2006电机(hal库)

大疆C板使用C610电调驱动M2006电机,以及遇到代码没问题,但是电机死活不转的处理

qq_46210601的博客 6012

JavaWeb开发基础Servlet生命周期与工作原理

总结,Servlet的生命周期包括初始化(init)、请求处理(service,调用doGet、doPost等)、和销毁(destroy)。工作原理是:客户端请求,服务器分发,创建请求和响应对象,调用service方法,生成并发送响应,删除请求和响应对象。当容器决定卸载Servlet(如容器关闭或Servlet被重新加载)时,它会调用Servlet的。方法根据请求的类型(如GET、POST等)调用相应的处理方法(如。方法根据请求的类型(如GET、POST等)调用相应的处理方法(如。

自动化代码美学 993

制作 img系统镜像的详细方法

      I.MX6开发板目前支持从TF卡和eMMC启动,启动时,由于各个不同的启动文件对路径有不同的要求,例如uboot文件要求位于启动设备的某个块,dtb文件要求在FAT分区上,文件系统要求在Linux分区上,基于此,我们目前采用将映像制作成img文件的方式,这样可以更简单完成对启动卡的制作。 关于如何制作img,方法如下:方法一  Windows下面利用Win32工具1.   准备我司提供...

armkits的博客 4万+

javaweb学习笔记:Servlet的运行过程详解

Servlet引擎按照下面的过程来调用一个Servlet程序: 1)、接收到访问某个Servlet的HTTP请求之后,Servlet引擎首先检查是否已经装载并创建了该Servlet的实例对象。如果已经装载并创建了该Servlet的实例对象,Servlet引擎则直接执行第4)步,否则,执行第2)步。   2)、装载并创建Servlet的一个实例对象   3)、调用Ser

hbjae28666的专栏 495

Dify插件实战:实时渲染AI生成的HTML/SVG/Canvas代码

在现代Web开发与AI应用集成中,前端渲染技术是实现动态内容展示的核心。其原理在于浏览器引擎解析HTML、CSS、JavaScript等代码,并将其转换为可视化的用户界面。这项技术的价值在于极大提升了开发效率与用户体验,允许开发者快速构建和迭代交互式应用。在AI应用开发领域,尤其是大语言模型(LLM)集成场景,如何将模型生成的**结构化代码**(如描述UI的HTML或数据图表的SVG)实时转化为可视化组件,成为一个关键需求。这直接关系到**Dify**等低代码AI平台能否提供流畅的、所见即所得的交互体验。本

weixin_42545664的博客 497

如何理解Fourier Neural Operator (FNO)

2022年Nvidia发表在arXiv上的的FourcastNet作为几乎是最早的一篇气象大模型的工作(之前Google Research的MetNet主要还是对于降水的预报)。除了Transformer的backbone之外,使用到了2021年发表在ICLR上的Fourier Neural Operator。为了更好的理解模型的理论基础,可以详细学习一下以及他的前期工作GNOFNO作者对这两篇文章的解析blog。

momo的博客 1万+

Servlet运行原理(Tomcat为例)

Servlet 一、首先servlet是一个java应用程序,运行在服务器端,用来处理客户端请求(http请求)并作出响应的程序。 二、http定义了与服务器交互的几种方式最基本常用的有:GET、POST、PUT、DELETE。使用频率最高的就是GET、还有POST 1.GET:从指定资源请求数据,该请求方式是通过Url直接请求数据的,数据信息可以直接在URL中看到,因为此种请求参数暴露在U...

a_helloworld_的博客 3210

GStreamer Plugin之Gst-nvdewarper

支持三种投影类型 NVDS_META_SURFACE_FISH_PUSHBROOM, NVDS_META_SURFACE_FISH_VERTCYL 和NVDS_META_SURFACE_PERSPECTIVE_PERSPECTIVE。关于每个平面的NvDewarperSurfaceMeta参数(projection_type, surface_index, and source_id)以及内存中有效的矫正平面(num_filled_surfaces)包含RGBA格式的一帧的缓存。矫正后的RGBA格式。

pvmsmfchcs的博客 366

Servlet运行过程和简单模拟

一.什么是Servlet Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,主要功能在于交互式地浏览和修改数据,生成动态Web内容,它工作在客户端请求与服务器响应的中间层,处理请求和发送响应的过程都是由Servlet的程序来完成的。   二.tomact和servlet的关系 Tomcat 是Web应用服...

逗逗大魔王的博客 889

Qt软件开发-Qt编译zlib完成文件压缩解压(win10)

在软件开发中进行有需求需要将生成的一些文件打包上传到服务器,或者从服务器下载压缩包下来内部解压。或者自己做一些打包工具,那么使用zlib开源就可以很方便的完成。接下来介绍在zlib在windows下如何利用Qt进行编译,调用,介绍mingw、msvc,32/64位编译办法,完成zip文件打包生成例子。可以单文件压缩打包,多文件压缩打包,目录压缩打包等等。

2214

软考高级信息系统项目管理师系列论文之:百篇软考高级信息系统项目管理师论文范文

软考高级信息系统项目管理师系列论文之:百篇软考高级信息系统项目管理师论文范文

zhengzaifeidelushang的博客 3578

servlet工作流程

如图所示即为Servlet的一般工作流程。 流程如下: 1)Web客户向Servlet容器(tomcat)发出Http请求; 2)Servlet容器解析Web客户的Http请求; 3)Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息; 4)Servlet容器创建一个HttpResponse对象; 5)Servlet容器调用HttpSer...

yuyibo95的博客 9116

华为od 面试八股文_JAVA语言_01_含答案

华为od 面试八股文_JAVA语言_01_含答案

MISAYAONE的博客 4295

SpringBoot2 | SpringBoot启动流程源码分析(一)

概述: 前阵子看到了SpringCloud社区的一个开源项目,主要是对服务发现增强的功能。研究项目的时候发现代码简练,优雅,最主要是spring ioc和aop特性应用的得心应手。若非对源码有深入研究,不可能写出这么优秀的开源项目。另外在现有的springboot专栏中,大多数博文旨在应用,对一些中间件的整合之类,源码分析的博客数量有限。鉴于以上两方面,该系列应运而生。 该系列主要还是Spri...

程序员阿康 13万+

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

JavaWeb——Servlet(全网最详细教程包括Servlet源码分析)

JavaWeb——Servlet Tomcat工作机制动画演示(点击动图可全屏观看) 什么是Servlet Servlet(Server Applet),全称Java Servlet,未有中文译文。是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据,生成动态Web...

扬俊的小屋 47万+

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

从源码分析tomcat如何调用Servlet的初始化

引言 上一篇博客我们将tomcat源码在本地成功运行了,所以在本篇博客中我们从源码层面分析,tomcat在启动的过程中,是如何初始化servlet容器的。我们平常都是将我们的服务部署到 tomcat中,然后修改一下配置文件,启动就可以对外提供 服务了,但是我们对于其中的一些流程并不是非常的了解,例如如何加载的web.xml等。这是我们分析servlet 和 sringMVC必不可少的过程。 一、代码启动tomcat 平常我们不论是Windows还是linux,我们都是通过脚本来启动tomcat,这对于

Jack 架构师之路 9万+

Tomcat和Servlet源码分析

1. Tomcat和Servlet源码分析 (1)写出Tomcat重要的类以及作用 答:Server:代表服务器,代表整个tomcat服务器,一个tomcat有一个server; Service:一个server可以有1个或多个service,service是逻辑功能层。用来接收请求,解析请求,完成相应的业务逻辑,然后把处理结果返回给客户端。提供两个服务start和stop,start用来打开so...

qq_43364293的博客 488

根据Servlet-API源码分析学习Servlet

Servlet 介于Servlet是Java Web开发的基础,因此好好看了一下Servlet3.0.1的源码,于是有了这篇记录。 Servlet架构图 Servlet和JSP是众多java EE定义的技术当中的两种,其他还有JMS,EJB等等,运行JEE程序需要一个JEE容器,如GlassFish、JBOSS、WebLogic等,Servlet\JSP也可以部署在JEE容器中,...

遐想 427

tomcat源码分析_百战卓越108天tomcat和servlet源码分析

训练大纲(第105天)大家如果想快速有效的学习,思想核心是“以建立知识体系为核心”,具体方法是“守破离”。确保老师课堂上做的操作,反复练习直到熟练。第209次(源码分析)学习主题:源码分析学习目标:对应视频: http://www.itbaizhan.cn/course/id/85.html对应文档:无对应作业 Tomcat和Servlet源码分析写出Tomcat重要的类以及作用写出Servlet...

weixin_39894914的博客 66

Servlet 和 Tomcat 底层源码分析

一、 Servlet 源码分析 1 Servlet 结构图 Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后 HttpServlet 继承了 GenericServlet 类.所以要实现一个 Servlet 直接就可以继承 HttpServlet 2 Servlet 接口 public interface Servlet { //负责初始化 Servlet 对象。容器一旦创建好 Servlet 对象后,就调用此方法来初始化 Se

LiLi的博客 616

index加载显示servlet数据_Tomcat,Servlet源码分析!!!

学习主题:源码分析对应作业1. Tomcat和Servlet源码分析(1) 写出Tomcat重要的类以及作用Tomcat架构图Server Server 服务器的意思,代表整个 tomcat 服务器,一个 tomcat 只有一个 Server Server 中包含至少一个 Service 组件,用于提供具体服务。这个在配置文件中也得到很 好的体现(port=“8005” shutdown="SH...

weixin_39945445的博客 141

Servlet和tomcat源码分析

前言 tomcat:一个web容器(servelt和jsp容器),用来进行前后端交互的一个中间商,解析客户端发送过来的数据解析成request和response对象,来进行一个请求与响应,tomcat解析服务端的response内容,在发送给客户端进行一个响应。 servlet:是service和applet的一个缩写,服务端小程序,处理从客户端拿到的数据,并作出响应。 1.Servlet 1.servlet结构图 HttpServelt继承了GenericServlet抽象类(

weixin_51435009的博客 1247

从tomcat源码分析它的启动流程是如何初始化servlet的

从tomcat源码分析它的启动流程是如何初始化servlet的

jiaohuizhuang6019的博客 1119

Servlet 源码分析

一、 Servlet 源码分析 1 Servlet 结构图 Servlet 和 ServletConfig 都是顶层接口,而 GenericServlet 实现了这两个顶层接口,然后HttpServlet 继承了 GenericServlet 类.所以要实现一个 Servlet 直接就可以继承 HttpServlet 2 Servlet 接口 public interface Servlet { //负责初始化 Servlet 对象。容器一旦创建好 Servlet 对象后,就...

奥迪的博客 679

Servlet规范系列 之 Servlet源码分析

欢迎大家关注本博,同时欢迎大家评论交流,可以给个赞哦!!!   Servlet接口是Java Servlet API的核心抽象。所有Servlet类必须直接或间接的实现该接口,或者更通常做法是通过继承一个实现了该接口的类从而复用许多共性功能。目前有GenericServlet和HttpServlet这两个类实现了Servlet接口。大多数情况下,开发者只需要继承HttpServlet去实现自己的Servlet即可。   生命周期:    · 加载和实例化。    · 初始化。    · 请求处理。   .

键盘上流淌的日子 3894

01、SpringBoot 源码分析 - SpringApplication启动流程一

之所以能那么强大,扩展性那么好,底层还是依赖spring,他的注解,他的处理器,他的监听器,可以有无数的扩展,废话不多说,当然还是老习惯,这次要分析Spring Boot 2.2.6.RELEASE版本的,要搞懂的原理,得先从他的初始化开始,然后层层深入,各个击破。

深入Java世界:探索编程之美与技术深度 853

java基础之servlet的讲解以及源码分析

一、创建项目 1.用idea创建maven项目的web项目,在这里我就不详细讲解了,网上教程一堆。 2.项目整体结构: 3.pom.xml <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId&...

码农小默 367
上一篇: 大型网站是怎样解决多用户高并发访问的
下一篇: 言简意赅 - spring ioc原理,超赞博文
CoderBruis
博客等级 码龄10年 4444粉丝 102原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值