spring 总结
1.定義:Spring是一個輕量級,開源的,非侵入式的控制反轉(zhuǎn)(IoC)和面向切面(AOP)的容器框架。?
2.特點:
◆輕量——從大小與開銷兩方面而言Spring都是輕量的。完整的Spring框架可以在一個大小只有1MB多的JAR文件里發(fā)布。并 且Spring所需的處理開銷也是微不足道的。此外,Spring是非侵入式的:典型地,Spring應(yīng)用中的對象不依賴于Spring的特定類。?
◆控制反轉(zhuǎn)——Spring通過一種稱作控制反轉(zhuǎn)(IOC)的技術(shù)促進(jìn)了松耦合。當(dāng)應(yīng)用了IOC,一個對象依賴的其它對象會通過被動的方式傳遞進(jìn)來,而不是這個對象自己創(chuàng)建或者查找依賴對象。你可以認(rèn)為IOC與JNDI相反——不 是對象從容器中查找依賴,而是容器在對象初始化時不等對象請求就主動將依賴傳遞給它。?
◆面向切面——Spring提供了面向切面編程的豐富支持,允許通過分離應(yīng)用的業(yè)務(wù)邏輯與系統(tǒng)級服務(wù)(例如審計(auditing)和事務(wù)()管理)進(jìn)行內(nèi)聚性的開發(fā)。應(yīng)用對象只實現(xiàn)它們應(yīng)該做的——完成業(yè)務(wù)邏輯——僅此而已。它們 并不負(fù)責(zé)(甚至是意識)其它的系統(tǒng)級關(guān)注點,例如日志或事務(wù)支持。?
◆容器——Spring包含并管理應(yīng)用對象的配置和生命周期,在這個意義上它是 一種容器,你可以配置你的每個bean如何被創(chuàng)建——基于一個可配置原型(prototype),你的bean可以創(chuàng)建一個單獨(dú)的實例或者每次需要時都生 成一個新的實例——以及它們是如何相互關(guān)聯(lián)的。然而,Spring不應(yīng)該被混同于傳統(tǒng)的重量級的EJB容器,它們經(jīng)常是龐大與笨重的,難以使用。?
◆框架——Spring可以將簡單的組件配置、組合成為復(fù)雜的應(yīng)用。在Spring中,應(yīng)用對象被聲明式地組合,典型地是在一個XML文件里。Spring也提供了很多基礎(chǔ)功能(事務(wù)管理、持久化框架集成等等),將應(yīng)用邏輯的開發(fā)留給了你。
3.Spring有如下優(yōu)點:?
◆降低了組件之間的耦合性,實現(xiàn)了軟件各層之間的解耦;
◆可以容易使用眾多的服務(wù),如事務(wù)管理等;
◆容器提供了單例模式支持,如spring bean的作用域;
◆容器提供了眾多的輔助類,能加快應(yīng)用的開發(fā);
◆容器提供了AOP技術(shù),利用它容易實現(xiàn)如權(quán)限攔截,運(yùn)行期監(jiān)控等功能;
◆Spring的DI機(jī)制降低了業(yè)務(wù)對象替換的復(fù)雜性?
◆可以無縫的和其他框架融合在一起,充當(dāng)粘合劑;因為它提供了很多不同的框架的支持類,如struts,hibernate等;
◆低侵入式設(shè)計,代碼污染極低?
◆獨(dú)立于各種應(yīng)用服務(wù)器,
?
代理模式
1.定義:是為其他對象提供一種代理,以控制對這個對象的訪問;
代理類負(fù)責(zé)為委托類預(yù)處理消息,過濾消息并轉(zhuǎn)發(fā)消息,以及進(jìn)行消息被委托類執(zhí)行后的后續(xù)處理。
2.優(yōu)點:
(1)職責(zé)清晰:真實的角色就是實現(xiàn)實際業(yè)務(wù)邏輯,不關(guān)心其他非本職責(zé)的事務(wù),通過后期的代理完成一件事務(wù),附帶的結(jié)果就是編程簡潔清晰。
(2)高擴(kuò)展性:具體主題角色是隨時都會發(fā)生變化的,只要它實現(xiàn)了接口,代理類完全就可以在不做任何修改的情況下使用
(3)智能化;
3.靜態(tài)代理和動態(tài)代理的區(qū)別:
靜態(tài)代理的代理類是在程序運(yùn)行前創(chuàng)建的,其代理類和委托類的關(guān)系在運(yùn)行前確定的;
而動態(tài)代理的代理類是程序在運(yùn)行期由JVM根據(jù)反射機(jī)制動態(tài)生成,其代理類和委托類的關(guān)系在運(yùn)行時確定的;
4.Spring中的兩種動態(tài)代理模式的區(qū)別:
CGLib創(chuàng)建的動態(tài)代理對象性能比JDK創(chuàng)建的動態(tài)代理對象的性能高不少,但是CGLib在創(chuàng)建代理對象時所花費(fèi)的時間卻比JDK多得多,所以對于單例的對象,因為無需頻繁創(chuàng)建對象,用CGLib合適,反之,使用JDK方式要更為合適一些。同時,由于CGLib由于是采用動態(tài)創(chuàng)建子類的方法,對于final方法,無法進(jìn)行代理
(-)、靜態(tài)代理?
1.定義:在程序運(yùn)行前就已存在代理類的字節(jié)碼文件,代理類和委托類的關(guān)系在運(yùn)行前就確定了。
2.優(yōu)缺點:
優(yōu)點:業(yè)務(wù)類只需要關(guān)注業(yè)務(wù)邏輯本身,保證了業(yè)務(wù)類的重用性。這是代理的共有優(yōu)點。?
缺點:
a.代理對象的一個接口只服務(wù)于一種類型的對象,如果要代理的方法很多,勢必要為每一種方法都進(jìn)行代理,
靜態(tài)代理在程序規(guī)模稍大時就無法勝任了。?
b.如果接口增加一個方法,除了所有實現(xiàn)類需要實現(xiàn)這個方法外,所有代理類也需要實現(xiàn)此方法。增加了代碼維護(hù)的復(fù)雜度。
(二).動態(tài)代理
1.定義:在程序運(yùn)行期間由JVM根據(jù)反射等機(jī)制動態(tài)的生成,代理類和委托類的關(guān)系是在程序運(yùn)行時確定。AOP的核心是動態(tài)代理機(jī)制;
2優(yōu)缺點:
優(yōu)點:動態(tài)代理與靜態(tài)代理相比較,最大的好處是接口中聲明的所有方法都被轉(zhuǎn)移到調(diào)用處理器一個集中的方法中處理(InvocationHandler.invoke).
這樣,在接口方法數(shù)量比較多的時候,我們可以進(jìn)行靈活處理,而不需要像靜態(tài)代理那樣每一個方法進(jìn)行中轉(zhuǎn)。
3.動態(tài)代理實現(xiàn)步驟:
a. 實現(xiàn)InvocationHandler接口創(chuàng)建自己的調(diào)用處理器?
b. 給Proxy類提供ClassLoader 和 代理接口類型數(shù)組(接口的數(shù)組)創(chuàng)建動態(tài)代理類?
c. 以調(diào)用處理器類型為參數(shù),利用反射機(jī)制得到動態(tài)代理類的構(gòu)造函數(shù)?
d. 以調(diào)用處理器對象為參數(shù),利用動態(tài)代理類的構(gòu)造函數(shù)創(chuàng)建動態(tài)代理類對象?
(根據(jù)動態(tài)代理類的構(gòu)造函數(shù)獲得動態(tài)代理類的實例);
// InvocationHandlerImpl 實現(xiàn)了 InvocationHandler 接口,并能實現(xiàn)方法調(diào)用從代理類到委托類的分派轉(zhuǎn)發(fā)?
InvocationHandler handler = new InvocationHandlerImpl(..);?
// 通過 Proxy 為包括 Interface 接口在內(nèi)的一組接口動態(tài)創(chuàng)建代理類的類對象?
Class clazz = Proxy.getProxyClass(classLoader, new Class[] { Interface.class, ... });?
// 通過反射從生成的類對象獲得構(gòu)造函數(shù)對象?
Constructor constructor = clazz.getConstructor(new Class[] { InvocationHandler.class });?
// 通過構(gòu)造函數(shù)對象創(chuàng)建動態(tài)代理類實例?
Interface Proxy = (Interface)constructor.newInstance(new Object[] { handler });
(三).Cglib 動態(tài)代理
Cglib動態(tài)代理:JDk動態(tài)代理的首要條件是:被代理類必須實現(xiàn)一個接口;如果沒有實現(xiàn)接口,則使用Cglib代理;
CGLib采用了非常底層的字節(jié)碼技術(shù),其原理是通過字節(jié)碼技術(shù)為一個類創(chuàng)建子類,并在子類中采用方法攔截的技術(shù)攔截所有父類方法的調(diào)用,順勢織入橫切邏輯。JDK動態(tài)代理與CGLib動態(tài)代理均是實現(xiàn)Spring AOP的基礎(chǔ)。
沒有接口的話,會強(qiáng)制使用cglib代理,前提得有jar,需要強(qiáng)制使用cglib的時候
設(shè)置<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
?
IOC容器
1.定義:IOC:(Inversion of control)控制反轉(zhuǎn)又稱依賴注入,指的是一個對象容器,將對象的依賴關(guān)系交由ioc容器來管理;
控制器中的javaBean 對象有指定的配置文件映射生成,可以配置javaBean的依賴關(guān)系需要的對象有ioc提供。
2.方式:set方法注入,接口注入,構(gòu)造方法注入;
3.作用:Spring中IOC 最大的好處是便于替換對象,只要用 JavaBean 屬性和配置文件加入依賴性(協(xié)作對象),
然后可以很容易地在需要時替換具有類似接口的協(xié)作對象。?
4.作用域:默認(rèn)的情況下是singleton;
singleton : 在每個Spring ioc容器中一個bean定義對應(yīng)一個對象實例;
prototype : 在每個Spring ioc容器中一個bean定義對應(yīng)多個對象實例;
request : 在一次HTTP請求中,一個bean定義對應(yīng)一個對象實例;該作用域僅基于web的Spring ApplicationContext 情形下才有用;
session : 在一個HTTP Session 中,一個bean定義對應(yīng)一個對象實例;該作用域僅基于web的Spring ApplicationContext 情形下才有用;
global session : 全局的HTTP Session 中,在每個Spring ioc容器中一個bean定義對應(yīng)一個對象實例;
該作用域僅基于web的Spring ApplicationContext 情形下才有用;
AOP框架
1.定義:AOP(面向切面) 是將應(yīng)用程序中的非業(yè)務(wù)邏輯代碼提取出來,封裝成切面。
從而實現(xiàn)了切面的復(fù)用,并降低了非業(yè)務(wù)邏輯代碼和業(yè)務(wù)代碼的耦合性。在不改變代碼結(jié)構(gòu)的情況下增強(qiáng)或控制了這個對象的行為。
spring中采用AOP進(jìn)行事務(wù)管理。
2.怎么理解AOP?
AOP是面向切面編程,是面向?qū)ο蟮难a(bǔ)充;
使用AOP,降低了代碼的耦合度,提高了代碼的重用;
Spring中的切面對關(guān)注點進(jìn)行模塊化,例如橫切多個類型和對象的事務(wù)管理?
所以,可以把Spring AOP看作是對Spring的一種增強(qiáng);
3.切入點:指切面應(yīng)用到的位置,具體切入到哪些類,哪些方法;
4.連接點:指切面代碼可以被切入到目標(biāo)對象的位置(屬性,方法)。
5.通知定義: 特定連接點所采取的動作;
6.通知有四種:
MethodBeforeAdvice(前置通知)
AfterReturningAdvice(后置通知)
ThrowsAdvice(異常通知)
MethodInterceptor(環(huán)繞通知)
spring的事務(wù)管理
1.定義:Spring 的事務(wù)管理:它保證了一系列操作可以作為一個工作單元,所有的操作被執(zhí)行的機(jī)制。
執(zhí)行后只有兩種結(jié)果,要么全部成功,要么全部失敗。
防止出現(xiàn)臟數(shù)據(jù),防止數(shù)據(jù)庫數(shù)據(jù)出現(xiàn)問題。
2.Spring提供的事務(wù)管理可以分為兩類:編程式的和聲明式的。
編程式事務(wù),比較靈活,但是代碼量大,存在重復(fù)的代碼比較多;
聲明式則比編程式更靈活;在使用Spring的聲明式事務(wù)時不需要編寫任何代碼,它通過AOP實現(xiàn)事務(wù)管理。
3.spring是怎么實現(xiàn)事務(wù)管理:在配置文件中聲明事務(wù)管理器,然后配置事務(wù)屬性,定義事務(wù)切入點,最后通過AOP實現(xiàn)事務(wù)管理;
4.事務(wù)有七種傳播性,四種隔離級別;
請你談?wù)凷SH整合:?
SSH: (MVC)
Action Service Dao
Struts(表示層)+Spring(業(yè)務(wù)層)+Hibernate(持久層)?
Struts:?
Struts是一個表示層框架,主要作用是界面展示,接收請求,分發(fā)請求。?
在MVC框架中,Struts屬于VC層次,負(fù)責(zé)界面表現(xiàn),負(fù)責(zé)MVC關(guān)系的分發(fā)。(View:沿用JSP,HTTP,Form,Tag,Resourse ;Controller:ActionServlet,struts-config.xml,Action)?
Hibernate:?
Hibernate是一個持久層框架,它只負(fù)責(zé)與關(guān)系數(shù)據(jù)庫的操作。 Hiberate屬于M層次;
Spring:?
Spring是一個業(yè)務(wù)層框架,是一個整合的框架,能夠很好地黏合表示層與持久層。Spring 屬于C層次;
struts2
1.struts2的流程。
(1)啟動web服務(wù)器時,解析web.xml,初始化servlet;
(2)接收jsp頁面.action的請求;
(3)請求會提交到一系列Filter過濾器;
(4)請求到達(dá)FilterDispatch(核心類)后,核心類會詢問ActionMapper是否調(diào)用某個Action來處理請求;
(每次發(fā)送一個Request,FilterDispatcher都會調(diào)用doFilter方法,doFilter方法中將struts.xml被解析成ActionMapper)
(5)如果ActionMapper 決定調(diào)用某個Action,核心類會將請求提交到ActionProxy, 由其進(jìn)行處理;
(6)ActionProxy通過Configuration Manager()詢問框架的Configuration (Struts.xml)配置文件,找到需要調(diào)用的Action類(Action被調(diào)用者);
(7)ActionProxy創(chuàng)建一個ActionInvocation(Action的調(diào)用者)實例,而ActionInvocation通過代理模式調(diào)用Action類;
在調(diào)用Action前ActionInvocation會根據(jù)配置加載Action 的所有攔截器;
(8)Action執(zhí)行完畢后,返回一個result字符串,此時再按相反的順序通過Interceptor攔截器。
(9)最后通過struts.xml中的配置找到對應(yīng)的result;
(10)響應(yīng)的返回是通過我們在web.xml中配置的過濾器
?
2.OGNL 定義:
OGNL是Object-Graph Navigation Language 的縮寫,全稱是對象圖導(dǎo)航語言,可以任意獲取對象的屬性或者調(diào)用對象的方法,
能夠遍歷整個對象的結(jié)構(gòu)圖,實現(xiàn)對象屬性類型的轉(zhuǎn)換等功能。
OGNL上下文實際上就是一個Map對象,它里面放了很多javaBeand對象,它有一上下文根對象(ValueStack)。
3.Struts與Spring是如何整合的?
需要的jar文件為:Spring和Struts2框架本身需要的jar文件以及他們所依賴的jar文件,比如commons-logging.jar等等,
另外還需要Struts2發(fā)布包中的struts2-spring-plugin-x.xx.jar。
注:Struts與Spring結(jié)合使用的體現(xiàn):
struts2中攔截是AOP的一種實現(xiàn)策略。
struts2中獲取對象是使用了IOC的模式。
(Struts2處理Action過程中調(diào)用的方法(“execute”方法)是不帶參數(shù)的。
那如何獲取所需要的對象呢?答案是使用IoC的模式)
4.模型驅(qū)動和屬性驅(qū)動區(qū)別:
屬性驅(qū)動:Action 的JSP頁面中的每一個Form的name都在Action中有一個屬性與之對應(yīng);
(用Action的屬性直接封裝請求屬性);
模型驅(qū)動:Struts2的模型驅(qū)動其實和Struts1中的ActionForm有點類似,在Struts1中每一個Action都必須有一個ActionForm(bean類)與之對應(yīng),
而Struts2.0中,每一個Action同樣需要提供一個POJO對象,用來封裝表單屬性。
(使用JavaBean來封裝來回請求的參數(shù));
區(qū)別:
(1)模型驅(qū)動的Action必須實現(xiàn)ModelDriven接口,而且要提供相應(yīng)的泛型,這里當(dāng)然就是具體使用的Java Bean了。
(2)實現(xiàn)ModelDriven的getModel方法,其實就是簡單的返回泛型的一個對象。
(3)在Action提供一個泛型的私有對象,這里就是定義一個User的user對象,并提供相應(yīng)的getter。
好了,上面的三件事做完之后,Action就會去自動調(diào)用User的setter將表單中的name屬性的值賦給User中的屬性。
而Action的后續(xù)處理的Jsp頁面后者是Servlet就可以使用user對象了。
5.struts2有哪些優(yōu)點?
1)Struts2的應(yīng)用可以不依賴于Servlet?API。?Struts2的這種設(shè)計屬于無侵入式設(shè)計;??
2)struts2提供了攔截器,實現(xiàn)如參數(shù)攔截注入等功能;??
3)struts2使用OGNL進(jìn)行類型轉(zhuǎn)換,可以把特殊的請求參數(shù)轉(zhuǎn)換成需要的類型;??
4)Struts2的輸入校驗可以對指定某個方法進(jìn)行校驗;?
5)多種表現(xiàn)層技術(shù),如:JSP、freeMarker、Velocity等;??
6)提供了全局范圍、包范圍和Action范圍的國際化資源文件管理實現(xiàn)?
6.struts1與struts2的區(qū)別。
a.接口和抽象類的對比
Struts1 要求Action類繼承一個抽象基類(DispatchAction類),使用抽象類編程而不是接口。
Struts2 Action類可以實現(xiàn)一個Action接口,也可以實現(xiàn)其他接口,使可選和定制的服務(wù)成為可能。
b.線程安全的對比
Struts1 Action是單例模式并且必須是線程安全的,因為僅有Action的一個實例來處理所有的請求。
Struts2 Action對象為每一個請求產(chǎn)生一個實例,因此沒有線程安全問題。
c.封裝請求參數(shù)的對比
Struts1 使用ActionForm對象封裝用戶的請求參數(shù),所有的ActionForm必須繼承一個基類:DispatchAction。
Struts2 直接使用Action屬性來封裝用戶請求屬性.
d.類型轉(zhuǎn)換的對比
Struts1 ActionForm 屬性通常都是String類型。使用Commons-Beanutils進(jìn)行類型轉(zhuǎn)換,每個類一個轉(zhuǎn)換器,轉(zhuǎn)換器是不可配置的;
Struts2 使用OGNL進(jìn)行類型轉(zhuǎn)換,支持基本數(shù)據(jù)類型和常用對象之間的轉(zhuǎn)換。
e.依賴方面的對比
Struts1 Action依賴于Servlet API,因為Struts 1 Action的execute方法中有HttpServletRequest和HttpServletResponse方法。
struts2 允許Action脫離
運(yùn)行,從而降低了測試Action的難度(ognl 中的ActionContext)。
f.可測試性的對比
Struts1 Action的execute方法依賴于Servlet API,這使得Action的測試要依賴于Web容器;
如果要脫離web容器,則要通過第三方擴(kuò)展:Struts TestCase;
Struts2 Action可以通過初始化、設(shè)置屬性、調(diào)用方法來測試。?
g.校驗方面的對比
struts1 支持ActionForm重寫validate方法的手動校驗,通過整合Commonsalidator框架來完成數(shù)據(jù)校驗。?
strust2 支持重寫validate方法進(jìn)行校驗,也支持整合XWork校驗框架進(jìn)行校驗
注:
struts2中攔截是AOP的一種實現(xiàn)策略。
struts2中獲取對象是使用了IOC的模式。
Spring MVC
Spring MVC框架:
Spring MVC屬于SpringFrameWork的后續(xù)產(chǎn)品,已經(jīng)融合在Spring Web Flow里面。Spring 框架提供了構(gòu)建 Web 應(yīng)用程序的全功能 MVC 模塊。使用 Spring 可插入的 MVC 架構(gòu),可以選擇是使用內(nèi)置的 Spring Web 框架還可以是 Struts 這樣的 Web 框架。通過策略接口,Spring 框架是高度可配置的,而且包含多種視圖技術(shù),例如 JavaServer Pages(JSP)技術(shù)、Velocity、Tiles、iText 和POI。Spring MVC 框架并不知道使用的視圖,所以不會強(qiáng)迫您只使用 JSP 技術(shù)。Spring MVC 分離了控制器、模型對象、分派器以及處理程序?qū)ο蟮慕巧?#xff0c;這種分離讓它們更容易進(jìn)行定制。
spring mvc 獲取request對象:
(1). RequestAttributes ra = RequestContextHolder.getRequestAttributes();?
HttpServletRequest request = ((ServletRequestAttributes)ra).getRequest();?
(2). 用注解的形式將request對象以參數(shù)的形式傳人進(jìn)來。(跟傳人bean一樣的)
關(guān)于Spring MVC Controller 層的單元測試,測試準(zhǔn)備工作:
1、搭建測試Web環(huán)境
@RunWith(UnitilsJUnit4TestClassRunner.class)
@SpringApplicationContext({"classpath:*.xml","file:src/main/webapp/WEB-INF/spring-configuration/*.xml","file:src/main/webapp/WEB-INF/*.xml" })
2、注入Controller 類
@SpringBeanByType
BeanController controller;
3、編寫測試數(shù)據(jù)
測試數(shù)據(jù)的文件名一定要與測試類的文件名相同,比如測試數(shù)據(jù)BeanControllerTest.xml ,測試類 BeanControllerTest。
4、注入測試數(shù)據(jù)
@Test
@DataSet
public void testBean(){}
Spring MVC的注解:
1.@Controller注解標(biāo)識一個控制器,
2.@RequestMapping注解標(biāo)記一個訪問的路徑(/index.jsp),return "index"標(biāo)記返回視圖(index.jsp);
(注:如果@RequestMapping注解在類級別上,則表示一相對路徑(命名空間);在方法級別上,則標(biāo)記訪問的路徑;)
3.使用@PathVariable 獲取傳入?yún)?shù)
4.使用@RequestParam 注解獲取GET請求或POST請求提交的參數(shù);
5.使用@CookieValue :獲取Cookie的值:
6.獲取PrintWriter:可以直接在Controller的方法中傳入PrintWriter對象,就可以在方法中使用:
7.ModelAttribute:
8.Resource;
可以傳入方法的參數(shù)類型:
將HttpServletRequest、HttpServletResponse、HttpSession作為入?yún)ⅰ5?#xff0c;如果第一次訪問頁面,HttpSession沒被創(chuàng)建,可能會出錯;
?
Spring MVC 重要組件?
1.spring mvc請所有的請求都提交給DispatcherServlet,它會委托應(yīng)用系
統(tǒng)的其他模塊負(fù)責(zé)負(fù)責(zé)對請求進(jìn)行真正的處理工作。?
2.DispatcherServlet查詢一個或多個HandlerMapping,找到處理請求的Controller.?
3.DispatcherServlet將請求提交到目標(biāo)Controller?
4.Controller進(jìn)行業(yè)務(wù)邏輯處理后,會返回一個ModelAndView
5.Dispathcher查詢一個或多個ViewResolver視圖解析器,找到
ModelAndView對象指定的視圖對象
6.視圖對象負(fù)責(zé)渲染返回給客戶端
?
在web.xml配置DispatcherServlet,
<servlet><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet>
在Dispatcher_servlet中的配置:
<!-- 啟動的時候,你要到這個包下面去掃描所有類的注解,將類生成實例放到ioc容器 -->
<context:component-scan base-package="com.lsit.controller" />
<!-- DefaultAnnotationHandlerMapping 通過注解,把一個URL映射到Controller類上 -->
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />?
<!-- 視圖解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/app/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
總結(jié)
- 上一篇: j2ee servlet 和 threa
- 下一篇: Form表单标签的Enctype属性的编