Spring boot(0)一JAVA Web发展史和spring boo发展史

1、CGI时代


CGI(Common Gateway Interface)公共网关接口,一种在web服务端使用的脚本技术,使用C或Perl语言编写,用于接收web用户请求并处理,最后动态产生响应给用户,但每次请求将产生一个进程,重量级。

CGI工作原理:CGI单独启动进程,一般由Http Server(如Apache,Lighttpd,nginx都支持CGI)唤起。并且每次调用都会重新启动进程。可以用任何语言编写,只要该语言支持标准输入、输出和环境变量。


CGI问题:

消耗资源多:每个请求都会启动一个CGI进行,进程消耗资源15M内存的话,同时到达100个请求的话,就会占用1.5G内存。如果请求更多,资源消耗是不可想象的。
性能慢:启动进程本身就慢。每次启动进程都需要重新初始化数据结构等,会变得更慢。

2、Servlet和容器出现(纯Servlet开发)


java 为了应对上述需求,就必然推出一种技术来支持动态需求,因此servlet技术诞生。使用Servlet技术,页面中的所有信息需要
通过输出语句来生成。Servlet是实现javax.servlet.Servlet接口的类。

servlet是一个Java接口,是JavaEE规范的一种,主要是为了扩展Java作为Web服务的功能。

Servlet容器:由于Servlet没有main方法,不能独立运行,它必须被部署到Servlet容器中,由Servlet容器来实例化和调用 Servlet的方法(如doGet()和doPost()),Servlet容器在Servlet的生命周期内包容和管理Servlet。

java web容器:管理和运行Servlet/JSP的容器也称为Web容器,web容器中包含servlet容器。常用的web容器有Tomcat 容器、 Resin 容器、JBoss 容器、 WebLogic 容器。

servlet处理http请求流程:servlet容器将请求封装为servlet中的HttpServletRequest对象,调用init(),service()等方法输出response,由容器包装为httpresponse返回给客户端的过程。

 

 

一般处理Web请求的Servlet还需要继承javax.servlet.http.HttpServlet

abstract class HttpServlet implements Servlet{
    void doGet();
    void doPost();
}

首先,我们得指定http://localhost:8080/TomcatTest/HelloForm这个URL由谁来处理。这个映射关系需要在web.xml中配置:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
  <servlet>
    <servlet-name>HelloWorld</servlet-name>
    <servlet-class>com.runoob.test.HelloWorld</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>HelloWorld</servlet-name>
    <url-pattern>/TomcatTest/HelloWorld</url-pattern>
  </servlet-mapping>
</web-app>


web.xml中配置的意思是:当URI为/TomcatTest/HelloWorld时,交给com.runoob.test.HelloForm处理。而HelloWorld正是个Servlet。因此,我们需要编写HelloForm这样一个Servlet,下面的代码生成的页面的内容就是“HelloWorld!”。

import java.io.IOException;
import java.io.PrintWriter;

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 HelloWorld
 */
@WebServlet("/HelloWorld")
public class HelloWorld extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("text/html;charset=gb2312");
		PrintWriter out = response.getWriter();
		out.println("<html>");
		out.println("<head><title>Hello World!</title></head>");
		out.println("<body>");
		out.println("<p>Hello World!</p>");
		out.println("</body></html>");
    }
    
    // 处理 POST 方法请求的方法
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

Servlet的缺点

html代码是写在Java代码中的。servlet编程很繁琐,这种形式非常非常难以开发和修改。
1)servlet代码有大量冗余代码,out输出就得写上百遍;
2)开发servlet必须精通网页前端和美工,你得非常不直观的在Servlet中写前端代码,这使得实现各种页面效果和风格非常困难。

 

3、JSP:Servle的升级版


JSP:JavaServer Pages  简单点说,就是可以在html中写Java代码。采用HTML语言直接生成界面,在界面中使用<% %>脚本标识嵌入Java代码:

<html>
   <head><title>测试</title></head>
   <body>
      第一阶段<% String str = “test” ; out.println(str); %>
    </body>
</html>

JSP将Java代码和特定变动内容嵌入到静态的页面中,实现以静态页面为模板,动态生成其中的部分内容。
JSP的工作原理:JSP模板引擎把JSP模板文件相应JSP元素改用println()语句,即转成Java代码,转化为servlet。本质上每个JSP都最终会变成对应的Servlet执行。

JSP的缺点

在HTML代码中写Java代码,当网站中需要进行大量的处理代码的时候,JSP文件将很难维护。因此单纯使用JSP,开发效率依旧不高。

在结合Servlet和JSP各自的优缺点后,诞生了Web开发中最常用和最重要的架构设计模式:MVC

 

4、MVC时代


MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller):

  • Controller——负责转发请求,对请求进行处理
  • View——负责界面显示
  • Model——业务功能编写(例如算法实现)、数据库设计以及数据存取操作实现

MVC思想的JSP+JavaBean+Servlet诞生
 JSP(V):JSP完成输入和输出,主要使用HTML标签和JSP标签
 Servlet(C):主要完成控制,接收请求,调用业务处理(JavaBean),根据调用的结果找到一个JSP页面对用户进行响应
 JavaBean(M):完成所有的处理过程


简而言之,请求发来后,会首先经过Controller层处理,需要返回的结果封装成对象传递给JSP,然后JSP负责取出数据展示就够了。这样,后端开发人员只负责编写Servlet,前端人员负责JSP,极大提升了开发效率。

@WebServlet("/userPosts")
public class UserPostController extends HttpServlet {

    private static final long serialVersionUID = -4208401453412759851L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String username = req.getParameter("username");
        User user = Data.getByUsername(username);
        List<Post> posts = Data.getPostByUser(user);

        req.setAttribute("posts", posts);
        req.setAttribute("user", user);
        RequestDispatcher dispatcher = req.getRequestDispatcher("/templates/userPost.jsp");
        dispatcher.forward(req, resp);
    }
}

像上面这段代码,UserPostController就是一个Servlet,负责逻辑处理。需要返回的数据封装到HttpServletRequest对象中,传递给jsp页面。而负责展示的就是/templates/userPost.jsp这个jsp文件。

 

5、 框架时代


有了Servlet和JSP,相当于有了武器。有了MVC,相当于有了战术。但是武器和战术之间还缺少一层,就是具体实施者。

实践证明,单纯使用Servlet、JSP和MVC开发,依然会面临诸多的问题。而程序员普遍存在一种特质,就是懒。因为懒,所以才想着能有更简单的解决办法。因为懒,针对一些通用问题,才会想出通用解决方法。可以说,因为懒,科技才有了进步。。。这时候,为了解放劳动力,一些开源框架营运而出。这些框架的目的只有一个:让开发简单,简单,更简单

倡导了MVC思想的jsp+javabean+servlet出现,也存在问题:1)jsp页面中嵌入了很多java代码,使得结构很乱;2)对于大型项目,servlet过多,转向频繁,流程,配置等不易集中管理,因而出现了struts.

5.1、Struts的出现

2001年6月,struts1.0出现,struts针对jsp推出了一套struts标签,从而使得jsp中没有了Java代码,结构清晰,功能强大。针对servlet,它提供了Action类来代替了servlet,这个Action类具有servlet的功能,并且能够进行一些请求过滤和自动转码的功能。

5.2、Spring的出现

原本已经开起来很完美了,但是又有一个问题,就是我们在Action调用DAO、Java bean等对象的时候都需要在自身代码中构建它们的对象来使用,这样增加了程序的耦合性,这与我们:“高内聚、松耦合”的思想不符合,那么怎么解决这个问题呢?因而出现了Spring框架。

自 2004 年 1.0 版本发布以来,Spring 框架迅速发展。Spring 2.0 于 2006 年 10 月发布,到那时,Spring的下载量超过了 100 万。Spring 2.0 具有可扩展的 XML 配置功能,用于简化 XML 配置,支持 Java 5,额外的 IoC 容器扩展点,支持动态语言。

Spring框架有两大功能:IOC(控制反转)和AOP(面向切面的编程),其中IOC就是说:当一个类中想要调用另外一个类的对象时,不需要再通过new 关键字来创建,而是由Spring框架来负责:创建、分配和管理,从而降低了程序中的耦合性。而AOP可以用来做一些日志的打印和输出,用于提示程序执行过程中的一些具体信息等。

5.3 、SpringMVC的出现

最后struts和Spring的整合,由于每一个bean都要在Spring中注册,每一个URL都要在struts配置文件中配置。当bean很多和URL对应的请求很多的时候,配置文件无疑会是很庞大的,这个就会使得配置起来很麻烦的费力。那么还有没有更好的办法使得能够结合Spring的功能和struts的功能,但是又可以使配置文件不会批量的增加?因而SpringMVC出现了

SpringMVC通过“基于注解”的方式代替了struts,并且通过Controller类来代替和实现了Action的功能。由于是基于注解的,所以很多的配置信息放在了Controller类中配置,从而降低了.xml文件的配置复杂度。

Springmvc的核心是一个DispatcherServlet,并且DispatcherServlet继承自 FrameworkServlet继承自HttpServletBean 继承自HttpServlet。 本质上是是servelt技术。

Springmvc实际上基于tomcat等这些web容器对我们的http请求能完成基础功能,如校验,拦截(AOP思想),后期渲染等等,好让我们专注于业务的开发。

 

6、 Spring boot(2016年更新此段落)


以往我们做Spring应用开发,要知道配置哪些类来让Hibernate和Spring一起工作,要知道如何配置view resolver来控制哪个模版进行视图层的展示。经常写了一大堆代码之后发现只是在处理Spring框架本身的配置,根本一行业务逻辑都没有写。

开发完成之后,我们还要考虑部署的问题,且不说部署到非常笨重的应用服务器,比如WebSphere, Weblogic或者JBoss,即使部署到Tomcat或者Jetty这种轻量级容器上面,我们要知道如何配置容器,如何修改配置文件等等。而且在多应用部署到同一个Tomcat的时候,经常会出现冲突。就算我们花了很大力气解决了这些问题,程序部署成功之后,我们很难去了解这个程序的运行状态。有可能我们要配置很多第三方工具来去知道这个应用程序运行状态如何,有哪些参数,环境变量是什么。尽管Spring帮我们解决了依赖注入的问题,简化了一些MVC的流程,但是Spring框架本身集成了越来越多东西,导致其越来越难配置,维护成本成直线上升。

但是现在 Spring Boot的出现让这一情况有了很大的改观。

Spring Boot 简单性使 java 开发人员能够快速大规模地采用该项目。Spring Boot 可以说是在 Java 中开发基于 REST 的微服务 Web 应用程序的最快方法之一。

【Spring Boot 核心功能】

1.独立运行的Spring 项目

Spring Boot 可以以jar 包的形式独立运行,运行一个Spring Boot 项目只需通过java –jarxx.jar 来运行。

2.内嵌Servlet 容器

Spring Boot 可选择内嵌Tomcat、Jetty 或者Undertow ,这样我们无须以war 包形式部署项目。

3.提供starter 简化Maven 配置

Spring 提供了一系列的starter pom 来简化Maven 的依赖加载,例如,当你使用了spring-boot-starter-web 时,会自动加入如下图所示的依赖包。

1.自动配置Spring

Spring Boot 会根据在类路径中的jar 包、类,为jar 包里的类自动配置Bean,这样会极大地减少我们要使用的配置。当然,Spring Boot 只是考虑了大多数的开发场景,并不是所有的场景,若在实际开发中我们需要自动配置Bean,而Spring Boot 没有提供支持,则可以自定义自动配置。

2.准生产的应用监控

Spring Boot 提供基于http、ssh、telnet 对运行时的项目进行监控。

3.无代码生成和xml 配置

Spring Boot 的神奇的不是借助于代码生成来实现的,而是通过条件注解来实现的,这是Spring 4.x 提供的新特性。

Spring 4.x 提倡使用Java 配置和注解配置组合,而Spring Boot 不需要任何xml 配置即可实现Spring 的所有配置。

SpringBoot 不仅让我们做Java开发变的简单有效,更重要的是SpringBoot彻底颠覆了我们对Java开发的认识,让我们第一次有了”原来Java开发可以这么做” 的感觉。

 

6、 Spring boot 发展史介绍(2019年转载)


 

1)Spring 框架的历史

起点

2002 年 10 月,Rod Johnson 撰写了一本名为 Expert One-on-One J2EE 设计和开发的书。本书由 Wrox出版,介绍了当时 Java 企业应用程序开发的情况,并指出了 Java EE 和 EJB 组件框架中的存在的一些主要缺陷。在这本书中,他提出了一个基于普通 Java 类和依赖注入的更简单的解决方案。

 

在书中,他展示了如何在不使用 EJB 的情况下构建高质量,可扩展的在线座位预留系统。为了构建应用程序,他编写了超过 30,000 行的基础结构代码。包含许多可重用的 Java 接口和类,如 ApplicationContext和BeanFactory。由于java接口是依赖注入的基本构建块,因此他将这些类的根包命名为com.interface21。

 

一对一的 J2EE 设计和开发一炮而红。本书免费提供的大部分基础架构代码都是高度可重用的。即使在 15 年后,本书及其原则仍然与构建高质量的 Java Web 应用程序相关。

Spring 诞生

在本书发布后不久,开发者 Juergen Hoeller 和 Yann Caroff 说服 Rod Johnson 创建一个基于基础结构代码的开源项目。Rod,Juergen 和 Yann 于 2003 年 2 月左右开始合作开发该项目 。Yann 为新框架创造了“Spring”的名字。据 Rod 介绍,Spring 是传统 J2EE 的新开始。

 

200 年 6 月,Spring 2.0 在 Apache 2.0 许可下发布。2004 年 3 月,1.0 版发布。有趣的是,在1.0发布之前,spring 就被开发人员广泛采用。2004 年 8 月,Rod Johnson,Juergen Hoeller,Keith Donald 和Colin Sampaleanu 共同创立了一家专注于 Spring 咨询,培训和支持的公司 interface21。

 

Yann Caroff 在早期离开了团队,Rod Johnson 在 2012 年离开,Juergen Hoeller 仍然是 Spring 开发团队的积极成员。

Spring 框架的快速增长

自 2004 年 1.0 版本发布以来,Spring 框架迅速发展。Spring 2.0 于 2006 年 10 月发布,到那时,Spring的下载量超过了 100 万。Spring 2.0 具有可扩展的 XML 配置功能,用于简化 XML 配置,支持 Java 5,额外的 IoC 容器扩展点,支持动态语言。

 

在 Rod 领导下管理 Interface21 项目于 2007 年 11 月更名为 SpringSource。同时发布了 Spring 2.5。Spring 2.5 中的主要新功能包括支持 Java 6 / Java EE 5,支持注释配置,classpath 中的组件自动检测和兼容 OSGi 的 bundle。

 

2007 年,SpringSource 从基准资本获得了 A 轮融资(1000万美元)。SpringSource 在此期间收购了多家公司,如Hyperic,G2One 等。2009年8月,SpringSource 以 4.2 亿美元被 VMWare 收购。SpringSource 在几周内收购了云代工厂,这是一家云 PaaS 提供商。2015 年,云代工厂转型成了非营利云代工厂。

 

2009 年 12 月,Spring 3.0 发布。Spring 3.0 具有许多重要特性,如重组模块系统,支持 Spring 表达式语言,基于 Java 的 bean 配置(JavaConfig),支持嵌入式数据库(如 HSQL,H2 和 Derby),模型验证/ REST 支持和对 Java EE 的支持。

 

2011 年和 2012 年发布了许多 3.x 系列的小版本。2012 年 7 月,Rod Johnson 离开了团队。2013 年 4月,VMware 和 EMC 通过 GE 投资创建了一家名为 Pivotal 的合资企业。所有的 Spring 应用项目都转移到了 Pivotal。

 

2013 年 12 月,Pivotal 宣布发布 Spring 框架 4.0。Spring 4.0 是 Spring 框架的一大进步,它包含了对Java 8 的全面支持,更高的第三方库依赖性(groovy 1.8+,ehcache 2.1+,hibernate 3.6+等),Java EE 7 支持,groovy DSL for bean 定义,对 websockets 的支持以及对泛型类型的支持作为注入 bean 的限定符。

 

2014 年至 2017 年期间发布了许多 Spring 框架 4.xx 系列版本。Spring 4.3.7 于 2017 年 3 月发布。Spring 4.3.8 于 2017 年 4 月发布,并成为 4.x 系列中的最后一个。Spring 框架的下一个延续的主要版本是在 5.0 版本展开。

 

2、Spring Boot 的历史

2012 年 10 月,Mike Youngstrom 在 Spring jira 中创建了一个功能请求 , 要求在 Spring 框架中支持无容器 Web 应用程序体系结构。他谈到了在主容器引导 spring 容器内配置 Web 容器服务。这是 jira 请求的摘录:

我认为 Spring 的 Web 应用体系结构可以大大简化,如果它提供了从上到下利用 Spring 组件和配置模型的工具和参考体系结构。在简单的 main()方法引导的 Spring 容器内嵌入和统一这些常用Web 容器服务的配置。

这一要求促使了 2013 年初开始的 Spring Boot 项目的研发。2014 年 4 月,Spring Boot 1.0.0 发布。从那以后,一些 Spring Boot 版本出来了:

1.Spring boot 1.1(2014 年 6 月) - 改进的模板支持,gemfire 支持,elasticsearch 和 apache solr 的自动配置。

2.Spring Boot 1.2(2015 年 3 月) - 升级到 servlet 3.1 / tomcat 8 / jetty 9,spring 4.1 升级,支持 banner / jms / SpringBootApplication 注解。

3.Spring Boot 1.3(2016 年 12 月) - Spring 4.2 升级,新的 spring-boot-devtools,用于缓存技术(ehcache,hazelcast,redis 和 infinispan)的自动配置以及完全可执行的 jar 支持。

4.Spring boot 1.4(2017年1月) - spring 4.3 升级,支持 couchbase / neo4j,分析启动失败和RestTemplateBuilder。

5.Spring boot 1.5(2017年2月) - 支持 kafka / ldap,第三方库升级,弃用 CRaSH 支持和执行器记录器端点以动态修改应用程序日志级别。

6.Spring boot 2.0(2018 年 03 月)-基于 Java 8,支持 Java 9,支持 Quartz ,调度程序大大简化了安全自动配置,支持嵌入式 Netty

Spring Boot 简单性使 java 开发人员能够快速大规模地采用该项目。Spring Boot 可以说是在 Java 中开发基于 REST 的微服务 Web 应用程序的最快方法之一。

Spring IO 和 Spring Boot

2014 年 6 月,Spring io 1.0.0 发布。Spring io 代表应用程序库之间的一组预定义的依赖关系。这意味着如果使用特定的 Spring IO 版本创建项目,则不再需要定义库的版本。即使是 Spring Boot 启动项目也是这个 Spring IO 的一部分。例如,如果你使用的是 spring io 1.0.0,则在添加启动器项目的依赖关系时,不需要指定 spring 启动版本。它会自动假定它是spring boot 1.1.1.RELEASE。

 

概念上,spring io 由模块的基础层和执行层域特定的运行时(DSR)组成。基础层代表核心弹簧模块和第三方依赖关系的策划清单。Spring Boot 是 Spring IO 提供的执行层 DSR 之一。因此,现在有两种主要的方法来构建应用程序:

1.使用或不使用 spring io 直接使用 Spring Boot。

2.使用所需 Spring 模块的 Spring IO。

请注意,通常每当发布新的 Spring 框架版本时,都会触发新的 Spring 启动版本。这将反过来引发新的Spring Boot 版本。

 

2015 年 11 月,Spring io 2.0.0 发布。这提供了一套更新的依赖项,包括 Spring Boot 1.3。2016 年 7月,Spring io 团队决定使用按字母顺序排版的方案。Spring IO 为此使用城市名称。在字母版本方案中,新名称表示依赖库的次要和主要升级。

 

2016 年 9 月,雅典发布了首个按字母顺序排列的城市命名的 Spring io 平台版本。它包含 Spring Boot 1.4 和其他第三方库升级。此后,雅典发布了多个服务版本(SR1,SR2,SR3和SR4)。

 

2017 年 3 月,最新的 Spring io平台(Brussels-SR1)发布。它使用最新的 Spring Boot 版本 1.5.2。下一个 Spring io 平台是开罗计划推出的 spring boot 2.0 和 spring framework 5.0。

 

Spring 时间线图表

有人说,Spring Boot的出现,让Java迎来了又一春,它是Java应用开发的颠覆者,彻底改变了Java应用开发的模式。

 

以往我们做Spring应用开发,要知道配置哪些类来让Hibernate和Spring一起工作,要知道如何配置view resolver来控制哪个模版进行视图层的展示。经常写了一大堆代码之后发现只是在处理Spring框架本身的配置,根本一行业务逻辑都没有写。

 

开发完成之后,我们还要考虑部署的问题,且不说部署到非常笨重的应用服务器,比如WebSphere, Weblogic或者JBoss,即使部署到Tomcat或者Jetty这种轻量级容器上面,我们要知道如何配置容器,如何修改配置文件等等。而且在多应用部署到同一个Tomcat的时候,经常会出现冲突。就算我们花了很大力气解决了这些问题,程序部署成功之后,我们很难去了解这个程序的运行状态。有可能我们要配置很多第三方工具来去知道这个应用程序运行状态如何,有哪些参数,环境变量是什么。尽管Spring帮我们解决了依赖注入的问题,简化了一些MVC的流程,但是Spring框架本身集成了越来越多东西,导致其越来越难配置,维护成本成直线上升。

 

很多时候,Python, Ruby或者JavaScript程序员敲几个命令安装一些库,然后简单的敲几行代码,引入一些框架比如flask,然后直接一个简单的API就可以跑起来了。Java程序员可能还在研究该使用Maven里面的哪个库,如何在代码里面进行配置。

但是现在 Spring Boot的出现让这一情况有了很大的改观。

它使用“习惯优于配置”(项目中存在大量的配置,此外还内置一个习惯性的配置,让你无须手动进行配置)的理念让你的项目快速运行起来。使用Spring Boot 很容易创建一个独立运行(运行jar,内嵌Servlet 容器)、准生产级别的基于Spring框架的项目,使用Spring Boot 你可以不用或者只需要很少的Spring 配置。

【Spring Boot 核心功能】

1.独立运行的Spring 项目

Spring Boot 可以以jar 包的形式独立运行,运行一个Spring Boot 项目只需通过java –jarxx.jar 来运行。

 

2.内嵌Servlet 容器

Spring Boot 可选择内嵌Tomcat、Jetty 或者Undertow ,这样我们无须以war 包形式部署项目。

 

3.提供starter 简化Maven 配置

Spring 提供了一系列的starter pom 来简化Maven 的依赖加载,例如,当你使用了spring-boot-starter-web 时,会自动加入如下图所示的依赖包。

 

1.自动配置Spring

Spring Boot 会根据在类路径中的jar 包、类,为jar 包里的类自动配置Bean,这样会极大地减少我们要使用的配置。当然,Spring Boot 只是考虑了大多数的开发场景,并不是所有的场景,若在实际开发中我们需要自动配置Bean,而Spring Boot 没有提供支持,则可以自定义自动配置。

 

2.准生产的应用监控

Spring Boot 提供基于http、ssh、telnet 对运行时的项目进行监控。

 

3.无代码生成和xml 配置

Spring Boot 的神奇的不是借助于代码生成来实现的,而是通过条件注解来实现的,这是Spring 4.x 提供的新特性。

 

Spring 4.x 提倡使用Java 配置和注解配置组合,而Spring Boot 不需要任何xml 配置即可实现Spring 的所有配置。

 

SpringBoot 不仅让我们做Java开发变的简单有效,更重要的是SpringBoot彻底颠覆了我们对Java开发的认识,让我们第一次有了”原来Java开发可以这么做” 的感觉。

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hguisu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值