ssm配置socket_从本科知识开始Java、TCPIP、Socket、Servlet再到完整理解SSH、SSM等概念(一)...

简单地说:

原始是

JSP、Servlet

+?

+JDBC

SSH是

Struts

+Spring

+Hibernate

SSM是

SpringMVC

+Spring

+MyBatis

本科毕业完,大致从事某些工作,就得学一些框架了。我们看到招工的时候,企业会要求同学们会Spring、Struts啊hibernate之类的。具体的流程很复杂,我这里做一个知识背景假设:

1、学习过TCP/IP

2、懂得Socket编程(用c语言或者java语言实现过)

0、复习阶段————————————————(主要是TCP/IP和各种网络协议,可以跳过)

复习:我们知道2台拥有不同IP地址的机器(假设是电脑)相互连接,进行通讯,需要TCP/IP协议(先不管UDP),我们编程的时候,服务器会开启个端口,然后listen()。客户端会进行connect(),当服务器accept()完以后,就可以相互间用send()或者recv()方法进行发送和接收消息了。当然,这时候是没有规则的,发送什么、接收什么全凭程序自己,如何理解这些发送的数据以及接收的数据,也全凭程序自己,由编程者自己定义。

进阶复习:为了方便不同的功能,对于不同的服务,大家坐在一起(大部分是美国人自己)制定了一些协议。如HTTP协议,就规定了我向你传“这样”的消息的时候,是问你要一个网页,发送个表单,而不是别的:

GET / HTTP/1.0

User-Agent: Mozilla/5.0

(Macintosh; Intel Mac OS X 10_10_5)

Accept: */*

意味着里面采用TCP/IP的send()方法的时候()里面的内容是有些规则的,不是由用户任意制定的!好吧,其他的的协议也类似,如文件传输协议FTP,邮件协议等等。如果按照规则,你完全可以自己写一个程序实现个FTP服务器、HTTP服务器、邮件服务器……

———————————————————————————————————————————

好了让我们回到HTTP协议。由于里面的GET和POST,可以按照规则给服务器发送一些参数和要求,请求特定的页面。于是,玩法开始千变万化了!我们从最基本的开始。

1、从最简单的网页服务器说起

首先,要有光(大误)

首先,我们要有一个网站,于是我们得需要一个网站服务器。所谓网站服务器,就是open一个端口,然后对于客户端send过来的所有符合HTTP协议的消息(或者服务器recv得到的消息)都进行一个响应,返回给客户端一个页面、文本或是其他的东西。

好了,接下来我们开始造轮子:于是这个服务器得满足什么条件呢?首先得能处理多个不同的连接吧,于是得具有多线程技术。用java或者c写过多线程的应该懂得这是怎么回事儿吧?在学校我们可能用多线程写写并行计算,这里就是每当服务器accept一个连接,我们就给这个从客户端得到的socket一个线程,让线程来处理这个程序。

Thread thread =

new Thread(new Runnable() {

@Override

public void run() {

//编写需要处理的代码

//socket.send("HTTP页面");

}

});

上面就是自己用java编写的情况模拟。单纯的网页HTTP服务器很简单,可以根据传过来的地址,如“/apple.html”,把相应在服务器上的apple页面传回去就OK。所以我们可能需要建立一个类来分析客户端请求的地址,然后检索服务器上有没有这个文件,再把这个网页文件传回给客户端。

于是,我们造了一个单纯没有任何特殊功能的网页轮子(服务器)

2、开始实现动态的服务器(不再返回固定的页面,而是根据用户的特殊请求返回页面)

单纯服务器太单纯了,以至于一些特定的功能实现起来非常繁琐,甚至令人崩溃,无法实现。我想发博客咋办?用户得输入一些文章吧,还的上传图片吧。难道我绕过HTTP协议,用FTP协议?我要查每科的成绩咋办?给每个学生ABC都建立一个A.html、B.html、C.html?然后给每个学生的每科成绩建立一个页面Amath.html、

Aenglish.html、Achinese.html……?我要算平均成绩呢?也再单独建立一个页面?我要改学生成绩呢?是不是先关掉服务器,把新写好的网页上传上去,再重启服务器?显然不用,HTTP准备了POST和GET方法。我们在本科阶段学习的HTML里面,就有这样一些标签:

First name:

Last name:

你会发现编写完后,网页是出现了按钮输入框和各种东西了,但是按了submit后,这些东西发给谁?那个谁又是怎么处理的呢?我们发现最开始的form标签里面action属性会指示一个网页,所以很显然,是那个网页处理的……等等?真的是网页处理的吗?——于是好戏开始上演了

这样的标签,在点击submit以后,它会转跳到一个action里面制定的网页(或者地址),这跟我们通常在浏览器地址栏输入地址不同,它向服务器请求页面的时候,还会附带一些参数,这些参数就是我们在浏览form页面的时候,在里面输入的东西。怎么处理这些请求,就有很多门道了。还记得第1节里面提到的线程吗?一个Thread。当客户端使用POST或者GET方法的时候,服务器那recv的消息就不只是/apple.html那么简单,还会附带其他消息。注意,很多人以为网站就是一个文件夹,但这其实是错的。怎么定义url地址,完全是根据第1节里面的Thread中的处理方法来定的。传给thread的地址仅仅是字符串,怎么解析这个字符串,然后调动服务器上的资源,最终返回给客户端,还是依靠这个thread来定。

所以,你会看到千奇百怪的地址"/apple.jsp"、"/apple.php"、"/apple.asp"、"/apple.do"甚至"/apple"这种不带扩展名的。你会好奇,为什么返回的还是单纯的html界面?我用chrome的查看源码只看到了html、css和javascript标签,为啥?因为经过thread处理后,传回来的还是普通的网页。

这个传给客户端网页的过程,服务器是怎么处理客户端请求的呢?其实返回jsp,php还是asp或其他,完全由服务器而定。也就是我们用编程编写thread的时候,我们怎么编的。根据相应的需求,产生相应的页面,比如我们服务器上有个存储学生成绩的csv表格,那么当客户端请求/apple?require=score的时候,服务器里的thread可能就有这么一句话:

public void run() {

String

cmd=socket.recv();

String

require=GetRequire(cmd);

if(require=="score"){

String

html=FileCSV.averageScore(student.csv);

socket.send(html);

}

}

我们造了一个动态服务器,能根据客户端的请求,来返回相应的页面。

3、越造越大,忙不过来了,我需要轮子来支撑这个车也许你猜到了,SSH或  者SSM有可能就是这个车

网站小还好说,一个人维护得了。但已经遇到一个问题了,目前为止整个服务器都是java(或者其他语言编写的),需要编译,然后运行吧?运行就是我们常说的启动服务器。偶尔可能需要关机让电脑休息一下,就是所谓的服务器宕机(其实任何问题导致服务器不能用,都可以近似理解为宕机,无论是服务器死机,管理员关机还是其它的也好)。频繁的宕机是有问题的,尤其当需求越来越大的时候。而当自己更新网站内容更新不过来的时候,得找些合作者吧,合作者如何给你更新啊?跟你一起写服务器代码?(别小看码农,能理解你编写的服务器代码的,工资价格可不低)这时候就有进阶的东西。

首先,啥叫需求越来越大的时候?(慢慢地开始有大型企业服务器的概念了)

就是你做的网站太精彩啦,或者你这个网站的某些功能太好用啦,就叫需求越来越大(大误……)当用户喜欢上你的时候,就会要求越来越高

“诶,你能不能给我这些服务啊?我想查我的排名。”——于是你得新建一个elseif来处理require=rank的情况。

“诶,我晚上急着查我的分数啊!咋上不了网站了?”——于是你的服务器不能随便宕机。

所以,由于不能随便宕机,首先,你这服务器不能因为多加个elseif关机编译一遍再开机了。这里的技术就非常多样化和强大了,为了不出现“多个功能(行话叫“业务”)就得写elseif”的情况,你得把elseif给分离到程序外面,使得与这个程序无关。其次,为了不随便宕机,你的服务器要有很强的处理各种socket编程会出现的exception的能力。这些所有的一切,如果你绝顶聪明,可以自己真真正正从头写一个。稍微笨一点的,边写边发现bug,慢慢修上去,最终也能勉勉强强得一个服务器程序。但是很遗憾,生不逢时,现在市面上已经有许许多多成熟的服务器程序了。他们是怎么把elseif的情况分离的呢?

让我们从最原始的轮子说起。

企业级分离1.0——业务功能与Web服务器分离

4、从最原始的轮子说起——Servlet

我们实现服务器有很多方式。如java里的jsp服务器,微软的asp服务器,以及最近流行的php。但我们一点一点来,看看从最小的服务器到实现整个大型企业级服务器,它们其中的分工思想是怎么来的。我们从最简单的开始,刚才说的jsp服务器简单吗?其实编程起来相当复杂,比jsp更原始的是servlet服务器。

servlet服务器,简单地说,就是把3中else

if从服务器里分离开来,服务器会给servlet分配一个固定的url(比如我分配/apple给它),然后所有客户端对这个url产生的请求(比如/apple?require=score),都会由这个servlet来处理。servlet是啥,是一个程序,编译好的程序。服务器收到相关客户端请求的时候,根据注册的地址,把客户端分配到相应的Servlet,Servlet再根据客户端的请求参数,来执行一系列功能,生成最终的html代码,返回回去。

所以我们再也不用重新编译服务器了,服务器可以24小时开着了。

所以我们只需要编译Servlet程序,编译完后的文件拷贝到服务器里,就能识别相应的功能了。

市面上有这么一些服务器:

Tomcat ———————

免费的(个人用,小巧)—————————— 只支持JSP、Servlet

WildFly

———————

免费的(可商用,原来JBoss开源版)—————只支持EJB

JBoss EAP

——————商用的(企业级?)———————————— 只支持EJB?

WebSphere

————— IBM公司的(企业级)———————————

全支持JSP、Servlet、EJB

WebLogic ——————

BEA公司的(企业级)——————————— 全支持JSP、Servlet、EJB

我们看到有些支持Servlet,有些不支持。所以JSP和EJB到底是什么呢?我们后面慢慢说。

5、稍微高级点的轮子——JSP

用Servlet写功能,把功能的问题解决了,但又有个最大的问题在于html页面写得太纠结了。我每次都得println出来,把好生生的html标签硬塞到java格式的String里面,在字符串的形式下,遇到/斜杠,还的转换成双//,不然要是/后面跟一个n,保不准还会被java理解成回车!

于是JSP应运而生。简单地说,就是把原来Servlet里的功能判断,用类似html标签的格式,写到一个jsp文件里。这样的情况下,网页设计和服务器功能混合在一起,页面设计方便了(我想用彩色的表格,就在html标签里面把color属性加上,然后表格的内容是学生成绩,那么我就在内容里写jsp标签来抓取学生成绩)。但是有了jsp,页面是好写了,但是功能又难写了。我得从一堆与功能无关的html标签里面,找到jsp标签,然后还的新学一门jsp语言!背好多好多jsp的功能函数!天啊……

所以页面华丽、功能简单的用JSP写。

所以页面简单、功能复杂的用Servlet写。

记得第4节末尾提到的市面上服务器吗?免费开源的Tomcat还真就JSP和Servlet都支持,用吧!

然后jsp页面越来越多,Servlet程序也越来越多……其实还凑合不是?但我们发觉我们这是一个三轮车服务器,因为——我们读取成绩是从csv读取,我们是不是得自己写一个读取csv文件的函数?然后造一个数据结构存?然后约定怎么插入成绩,怎么提取成绩?怎么样提取效率才高啊?我是不是得考虑最优的算法呢?

让我们把三轮车变成四轮车。

6、补齐关键性的一个轮子——JDBC(我来读取数据库!)

小网站就是幸福啊,几个html页面,如果需要点功能,就上Jsp&Servlet服务器(或者ASP、PHP服务器,当然你就得学ASP或者PHP语言了),多写点servlet或者jsp页面就OK。但是功能越来越多的时候,就没那么简单了。我要给学校建一个网站服务器,尼玛一个年级2000个学生,4个年级外加研究生两三年加博士……这数据得爆炸,不能单独存一个csv吧,成绩与学生个人信息感觉得分开存,不然都一个表里也爆炸了。存N个CSV文件?学生的照片怎么办?那是图片啊,不是文本啊,存不了csv啊……我得做一个程序管理这些csv和照片吧。

于是,我们做了一个程序,管理好了。但我不能每次都打开这个程序来管理这些数据吧?我在家也想用怎么办?很好,我们造一个服务器吧。于是我们又运用本科学的socket编程技巧写了一个,好了,坐在家里我也可以拿这些数据了。按照之前2、3、4节的介绍,我们造了另一台车!

这就是——数据库服务器。

我们真NB啊,不但轮子都造了,还造车了!但其实要造出来真复杂。首先数据库服务器得支持N种不同类型的数据,然后你总不能随便来个人都能访问吧?成绩是我的个人隐私啊!所以你对登陆到服务器的client还得审核。为了审核你得制定一套规则,然后为了规范对方的查询,你又得制定一套规则……于是你还开发起“网络安全协议”“数据库协议”来着……

其实同样,市场上也有类似的东西来帮助我们处理数据问题,那就是数据库:

好了,数据库(车)给我们提供了数据服务,它们同样是基于网络的,同样有半标准和标准化的协议,一般这个协议或者约定俗成的东西叫SQL。我们客户端,连接数据库,send给服务器SQL查询语句,它就会返回查询结果,这就是数据库服务器功能。

要连接服务器,遵循某种约定,离不开协议。Java下的Http的类,在socket类的基础上封装了HTTP协议。同样,有个叫JDBC的东西,在socket类的基础上封装了SQL和数据库连接的协议。我们不用自己开个socket辛苦地写send和recv了,直接用JDBC里面提供的类,塞上数据库地址、用户名和密码等,就可以send上SQL语句等待接收查询结果了。

7、二车同轨!JSP、Servlet+JDBC(Web服务器与数据库相结合!)

说了这么多,Web服务器+数据库服务器,开始强强联手了。鉴于我们需求上升,我得查找学生的成绩,也要允许学生看自己的个人信息,但是返回的页面还要好看。于是我们到达企业级事务分离2.0!

企业级分离2.0——数据库、业务功能与Web服务器分离

在企业级分离1.0中,我们把功能写到JSP和Servlet里面了,这样服务器就不用重新编译了。在第6节里,我们介绍了数据库,让数据库来管理我们的各种资源。于是自然而然的,在整个流程当中,我们把数据库也与web服务器分离了。

操作数据库的Java类或者方法,在JDBC里面有。于是,在写Servlet的时候,直接调用这些方法,我们就能访问数据库了。简单吧,Servlet+JDBC就完成了。而在JSP中,可能我们得使用jsp语言本身提供的方法,然后再在里面写SQL语句。这个过程跟PHP,ASP估计是差不多的,也是实用相应的方法。

接下来,

我们的网站越来越NB了!越来越多人喜欢我们的网站。而且这也不是一个单纯的个人主页了,可以是一个博客,也可以是一个教务系统,也可以是一个交易网站。我们的功能,或者说业务也越来越多了。

8、金轮子,JSP与Servlet合并(MVC框架)

这样的情况不仅仅是纠结。回到第5节时候的问题:

“所以页面华丽、功能简单的用JSP写。”

“所以页面简单、功能复杂的用Servlet写。”

造成这种情况的原因在于,JSP里面包含了功能代码(if、while、for、读取数据、格式化数据),Servlet里面除了功能代码,还包含了页面显示输出(println("

《HTML》《HEAD》《BODY》……")等等这类)。这样的缺点在于:

如果是用JSP写的,我想加复杂的功能就非常难,得在一堆HTML标签里面找功能代码。

如果是用Servlet写的,我想把界面改得漂亮一点,就非常繁琐,得一个一个在字符串里面加。

这些原本没太大问题的东西,在我们的需求变得大起来以后,就成为束缚网站发展的限制了。我不是全能,我得找更专业的人来帮我写HTML页面,找更专业的人解决一些功能问题。我得干净地分离这些东西,才能做到写页面单纯写页面,写功能单纯写功能。同理,企业里,你不再是一个人编程,而是一个团队。本科时候学的不同专业也会分不同方向,每个人兴趣、能力侧重点不同。这就是为什么我们去应聘的时候,会有美工、会有前端、会有后端。

美工负责设计网页,然后自己或者找人编写网页(HTML、CSS)

前端可能要负责实现一些在用户那的功能(JavaScript)

后端负责服务器这边的应用层以及数据库层之间的功能(JSP、Servlet等等,或者ASP、PHP)

总之分工明确。但光分工不行,因为是个团队,大家得交流,一起才能做好一个网站(或是功能服务器、或是其他……)所以,得规定一个统一的流程来写,在这个规定(或者叫条条框框下),我们才能协作,才能确保不同的人负责的不同部分,它拼凑在一起是能用的。

这就是————框架(=分离+协作)!

回到之前说的JSP和Servlet,我想把功能代码分离,很好——其实Servlet这个java类就是把功能代码分离了。但是我想把页面设计单独出来,别写进java类里面,也没问题!我们看看JSP是怎么工作的,里面有jsp代码和html代码,当servlet读取这个jsp文件的时候,它根据预先语言的定义,把html原封不动,把jsp部分翻译成java的功能(进行数据库抓取、判断、合成等),然后执行完这部分java代码以后会返回要显示成html的部分(比如包含学生成绩的《table》标签),跟原来原封不动的html页面结合在一起,返回给服务器。

发现了吗?其实jsp页面还是得依赖servlet进行工作,servlet的工作就是翻译jsp成java。

这里“把jsp部分翻译成java的功能”就有可以改进的地方了。

我们为什么不能定义一个小巧的标签,单纯在html里面表示我要显示啥就完了呢?jsp翻译成java功能,何不从一开始就把功能写进java里?所以,当servlet读取一个页面(如jsp)的时候,在html标签之间标记个$score,servlet就把业务运算好的结果(学生成绩)生成字符串,替换掉相应的$score就好了。于是我们沿着这个思想,造了一个轮子。

这个轮子就是MVC框架。

市面上常用的Java的MVC框架有:

Struts

SpringMVC(这个注意,和Spring是不同的东西哦!)

9、给JDBC也造一个金轮子(Hibernate、Mybatis)

通过前面几节,我们把JSP和Servlet合并成了MVC框架。那么JDBC这个操作数据库的功能,能不能简化呢?

在纯数据库操作环境下,一切都是那么的和谐。但是这个数据库有这个的和谐环境,那个数据库有那个的和谐环境,我要是网站做着做着,想换个不同的数据库怎么办?原来写的数据库SQL语句,在新的数据库不支持了怎么办?我们是不是要把所有数据库之中,具有共性的东西统计下?然后编写个统一的方法呢?

这个当然是好的,于是我们催生了Hibernate。Hibernate把SQL语句封装成了面向对象(OOP)的操作形式,使得操作单个表格更加方便了……但是联合查询,似乎还得用到Hibernate自己的查询语句HQL,真是令人囧啊。不过统一的OOP操作,统一的HQL,能够适应不同的数据库,倒也不失为一种解决办法。

然而,另外一种思路是,我们只封装表头,然后让查询语句还是用原生SQL语句来实现。这样的话又是什么情况呢?于是我们有了MyBatis这种把SQL语句放在XML文件的框架。

所以,总结来说,这两个框架都是对Java持久层操作的封装。啥?持久?就是数据永久地保存起来了……别问我老外为什么起这么生硬的英文,然后中文又更生硬的直译了。持久就是你用户操作完后,不是立马把数据抛弃,而是保存在服务器上了。真是“持久”啊…………最终我们得到2个框架:

Hibernate

Mybatis

企业级分离2.1——数据库用框架分离、业务功能与Web服务器分离

10、轮轴Spring,把轮子都拼一起做个底盘

无论是SSH还是SSM,中间一定少不了一个东西,那就是Spring。Spring具体是什么,网上也众说纷纭。你到底有啥需求才会用到Spring?不用Spring单独在不行吗?单独用SpringMVC或Struts不行吗?事实证明当然是可以的。

Spring的本质其实是一个管理Class

Factory(类工厂)的程序。这个不恰当的比喻,我反倒觉得很好地解释了Spring的本质。我们都知道当项目和程序写大的时候,当每个服务都要用到一个擦屁股程序(后处理),或者某个程序要调用一堆程序的时候,我们都需要调参数、配置。用windows

XP的比喻,就是Spring建立了一个注册表,然后Spring这个管理者,根据注册表里面的信息来调用、生成这些服务。

我们写一个Interface,里面只有方法名,没有具体方法的实现。具体用哪一个实现呢?由Spring根据配置来完成。这样,我们在写业务逻辑(实际取数、或者进行某项任务)的时候,只需要:

ExampleInterface ei=(ExampleInterface) ctx.getbeans("Some

Require");

根据一些需求来得到具体实现的类。这个程序可以直接编译,甚至跑到服务器里,之后换服务的时候,不需要重新编译这个类,只需要更新一个实现并编译好,修改Spring里面的beans,把编译好的新需求实现丢到服务器里就好。

这也许就是原来吹得比较火热的——基于组件的编程。这个组件是单独分离的编译好的程序,可以自由拼装而不必担心整体程序宕机。虽然效率肯定没有完全编译好高,但是牺牲点效率,提高了整个企业大程序的灵活性。

上升到Spring框架,就是另外一层哲学了,至此完全不必拘泥于SSH和SSM,甚至你可以打造这样不同的组合,例如SpringMVC+Spring+Hibernate而不是SpringMVC+Spring+Mybatis。之前说EJB是为了解决应用层(就是存储各类应用程序的层——应用程序就是负责数据库取数、转换再展现的)只能在一个服务器运行的问题。组装成的EJB可以分发到几个应用服务器同时运行,但是对数据库取数操作还只能对单个数据库。懂了整个原理后,你完全可以造一个连接分布式数据库的应用层,当然这是后话了。

11、结语——整辆跑车

有了轮子和轮轴,外加发动机(硬件)和应用(软件),就是整辆跑车了。

所谓构架师就是这么回事儿,设计整个跑车,运用某个框架(比如在Java里,Spring)把其他有用的框架(如Java中的SpringMVC、Struts、Hibernate、Mybatis)合理地组装起来,跑在一个服务器上,减少宕机的同时,尽可能地提供“服务的可能性”,为在手下干活码代码的码农,提供一个安心的编程规范

与 合理的分工,然后负责并维持整个系统的稳定输出。

能做这个事情并非易事,每个框架都有自己大量的参数系统,不同的配置产生何种效果和效率,都要深刻理解框架自身。在这个过程中,本科的基础知识是否牢固,后续是否继续巩固,决定了理解的深度。多线程、大并发、算法、规范和软件工程,这些知识决定了你是用框架还是设计一个框架。

连续学了2周框架,力求每一个框架都用代码自己用一遍,而且追求独立地用,这样才能理解每个框架如何工作的,再进行一次2个框架(而不是3个)的整合,理解一下整合的过程中发生了什么。我感觉这才是彻底理解框架的提升之道。码农、码农,正是因为框架搭好了后,每一部分的分工都太细,创新的空间都太死,界面的负责界面、业务的负责业务、维护的负责维护、权限的负责权限,才导致有一种农民耕耘的感觉。其实说码农不恰当,我们更像是富士康流水线上的工人,每个人维护这个企业跑车的一小部分。

这大概是学完框架后的感慨吧。

附录(一些实现以及来源杂七杂八的吐槽):

所有Spring管理事务,我问十个人,有八个人说不出来为什么要用Spring来管理事务,他们的意思好像离开Spring,就无法管理事务。其实所谓的Spring管理事务,不过是使用AOP面向切面编程的概念,在对数据库进行若干sql后,自动提交事务,或者回滚。对数据库事务的管理,本来和Spring是没有任何关系的,离开了Spring,对数据库的操作照样进行得很顺利,Hibernate和IBatis(MyBatis)不是为了适应Spring才被设计出来的,离开Spring,直接使用Hibernate或者IBatis照样可以做到运行得很好。

那些唯Spring才可以管理Hibernate或IBatis的人,充其量只是程序流水线上的工人,从来没有考虑过程序架构,他们认为web本来就应该使用Spring来粘合各种框架,离开Spring他们会无能为力,于是我问网络上任何一个人"Spring有什么好处",到目前为止,他们都无法直接回答出来,其实我要的答案很简单,在一个最简单的Web功能中,比如一个用户登录的页面,Spring在其中起到了什么作用,使用Spring可以有哪些优点,不用Spring有什么不好?如果你可以把这几个问题回答出来,就足以说明你上升到架构师的水平了。

MyBatis

本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation

迁移到了google code,并且改名为MyBatis

。2013年11月迁移到Github。iBATIS一词来源于“internet”和“abatis”的组合,是一个基于Java的持久层框架。iBATIS提供的持久层框架包括SQL

Maps和Data Access Objects(DAO)————百度百科

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值