![Spring MVC入門(mén)學(xué)習(xí)指南_第1頁(yè)](http://file4.renrendoc.com/view14/M00/21/09/wKhkGWdXSb-AEUTQAABcRpNwFHU376.jpg)
![Spring MVC入門(mén)學(xué)習(xí)指南_第2頁(yè)](http://file4.renrendoc.com/view14/M00/21/09/wKhkGWdXSb-AEUTQAABcRpNwFHU3762.jpg)
![Spring MVC入門(mén)學(xué)習(xí)指南_第3頁(yè)](http://file4.renrendoc.com/view14/M00/21/09/wKhkGWdXSb-AEUTQAABcRpNwFHU3763.jpg)
![Spring MVC入門(mén)學(xué)習(xí)指南_第4頁(yè)](http://file4.renrendoc.com/view14/M00/21/09/wKhkGWdXSb-AEUTQAABcRpNwFHU3764.jpg)
![Spring MVC入門(mén)學(xué)習(xí)指南_第5頁(yè)](http://file4.renrendoc.com/view14/M00/21/09/wKhkGWdXSb-AEUTQAABcRpNwFHU3765.jpg)
版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
SpringMVC入門(mén)學(xué)習(xí)指南目錄\h第1章Spring框架\h1.1XML配置文件\h1.2Spring控制反轉(zhuǎn)容器的使用\h1.2.1通過(guò)構(gòu)造器創(chuàng)建一個(gè)bean實(shí)例\h1.2.2通過(guò)工廠方法創(chuàng)建一個(gè)bean實(shí)例\h1.2.3DestroyMethod的使用\h1.2.4向構(gòu)造器傳遞參數(shù)\h1.2.5Setter方式依賴注入\h1.2.6構(gòu)造器方式依賴注入\h1.3小結(jié)\h第2章模型2和MVC模式\h2.1模型1介紹\h2.2模型2介紹\h2.3模型2之Servlet控制器\h2.3.1Product類\h2.3.2ProductForm類\h2.3.3ControllerServlet類\h2.3.4視圖\h2.3.5測(cè)試應(yīng)用\h2.4解耦控制器代碼\h2.5校驗(yàn)器\h2.6后端\h2.7小結(jié)\h第3章SpringMVC介紹\h3.1采用SpringMVC的好處\h3.2SpringMVC的DispatcherServlet\h3.3Controller接口\h3.4第一個(gè)SpringMVC應(yīng)用\h3.4.1目錄結(jié)構(gòu)\h3.4.2部署描述符文件和SpringMVC配置文件\h3.4.3Controller\h3.4.4View\h3.4.5測(cè)試應(yīng)用\h3.5ViewResolver\h3.6小結(jié)\h第4章基于注解的控制器\h4.1SpringMVC注解類型\h4.1.1Controller注解類型\h4.1.2RequestMapping注解類型\h4.2編寫(xiě)請(qǐng)求處理方法\h4.3應(yīng)用基于注解的控制器\h4.3.1目錄結(jié)構(gòu)\h4.3.2配置文件\h4.3.3Controller類\h4.3.4View\h4.3.5測(cè)試應(yīng)用\h4.4應(yīng)用@Autowired和@Service進(jìn)行依賴注入\h4.5重定向和Flash屬性\h4.6請(qǐng)求參數(shù)和路徑變量\h4.7@ModelAttribute\h4.8小結(jié)\h第5章數(shù)據(jù)綁定和表單標(biāo)簽庫(kù)\h5.1數(shù)據(jù)綁定概覽\h5.2表單標(biāo)簽庫(kù)\h5.2.1表單標(biāo)簽\h5.2.2input標(biāo)簽\h5.2.3password標(biāo)簽\h5.2.4hidden標(biāo)簽\h5.2.5textarea標(biāo)簽\h5.2.6checkbox標(biāo)簽\h5.2.7radiobutton標(biāo)簽\h5.2.8checkboxes標(biāo)簽\h5.2.9radiobuttons標(biāo)簽\h5.2.10select標(biāo)簽\h5.2.11option標(biāo)簽\h5.2.12options標(biāo)簽\h5.2.13errors標(biāo)簽\h5.3數(shù)據(jù)綁定范例\h5.3.1目錄結(jié)構(gòu)\h5.3.2Domain類\h5.3.3Controller類\h5.3.4Service類\h5.3.5配置文件\h5.3.6視圖\h5.3.7測(cè)試應(yīng)用\h5.4小結(jié)\h第6章轉(zhuǎn)換器和格式化\h6.1Converter\h6.2Formatter\h6.3用Registrar注冊(cè)Formatter\h6.4選擇Converter,還是Formatter\h6.5小結(jié)\h第7章驗(yàn)證器\h7.1驗(yàn)證概覽\h7.2Spring驗(yàn)證器\h7.3ValidationUtils類\h7.4Spring的Validator范例\h7.5源文件\h7.6Controller類\h7.7測(cè)試驗(yàn)證器\h7.8JSR303驗(yàn)證\h7.9JSR303Validator范例\h7.10小結(jié)\h第8章表達(dá)式語(yǔ)言\h8.1表達(dá)式語(yǔ)言的語(yǔ)法\h8.1.1關(guān)鍵字\h8.1.2[]和.運(yùn)算符\h8.1.3取值規(guī)則\h8.2訪問(wèn)JavaBean\h8.3EL隱式對(duì)象\h8.3.1pageContext\h8.3.2initParam\h8.3.3param\h8.3.4paramValues\h8.3.5header\h8.3.6cookie\h8.3.7applicationScope,sessionScope,requestScope和pageScope\h8.4使用其他EL運(yùn)算符\h8.4.1算術(shù)運(yùn)算符\h8.4.2邏輯運(yùn)算符\h8.4.3關(guān)系運(yùn)算符\h8.4.4empty運(yùn)算符\h8.5如何在JSP2.0及其更高版本中配置EL\h8.5.1實(shí)現(xiàn)免腳本的JSP頁(yè)面\h8.5.2禁用EL計(jì)算\h8.6小結(jié)\h第9章JSTL\h9.1下載JSTL\h9.2JSTL庫(kù)\h9.3一般行為\h9.3.1out標(biāo)簽\h9.3.2set標(biāo)簽\h9.3.3remove標(biāo)簽\h9.4條件行為\h9.4.1if標(biāo)簽\h9.4.2choose、when和otherwise標(biāo)簽\h9.5遍歷行為\h9.5.1forEach標(biāo)簽\h9.5.2forTokens標(biāo)簽\h9.6與URL相關(guān)的行為\h9.6.1url標(biāo)簽\h9.6.2redirect標(biāo)簽\h9.7格式化行為\h9.7.1formatNumber標(biāo)簽\h9.7.2formatDate標(biāo)簽\h9.7.3timeZone標(biāo)簽\h9.7.4setTimeZone標(biāo)簽\h9.7.5parseNumber標(biāo)簽\h9.7.6parseDate標(biāo)簽\h9.8函數(shù)\h9.8.1contains函數(shù)\h9.8.2containsIgnoreCase函數(shù)\h9.8.3endsWith函數(shù)\h9.8.4escapeXml函數(shù)\h9.8.5indexOf函數(shù)\h9.8.6join函數(shù)\h9.8.7length函數(shù)\h9.8.8replace函數(shù)\h9.8.9split函數(shù)\h9.8.10startsWith函數(shù)\h9.8.11substring函數(shù)\h9.8.12substringAfter函數(shù)\h9.8.13substringBefore函數(shù)\h9.8.14toLowerCase函數(shù)\h9.8.15toUpperCase函數(shù)\h9.8.16trim函數(shù)\h9.9小結(jié)\h第10章國(guó)際化\h10.1語(yǔ)言區(qū)域\h10.2國(guó)際化SpringMVC應(yīng)用程序\h10.2.1將文本元件隔離成屬性文件\h10.2.2選擇和讀取正確的屬性文件\h10.3告訴SpringMVC使用哪個(gè)語(yǔ)言區(qū)域\h10.4使用message標(biāo)簽\h10.5范例\h10.6小結(jié)\h第11章上傳文件\h11.1客戶端編程\h11.2MultipartFile接口\h11.3用CommonsFileUpload上傳文件\h11.4Domain類\h11.5控制器\h11.6配置文件\h11.7JSP頁(yè)面\h11.8應(yīng)用程序的測(cè)試\h11.9用Servlet3及其更高版本上傳文件\h11.10客戶端上傳\h11.11小結(jié)\h第12章下載文件\h12.1文件下載概覽\h12.2范例1:隱藏資源\h12.3范例2:防止交叉引用\h12.4小結(jié)\h附錄ATomcat\hA.1下載和配置Tomcat\hA.2啟動(dòng)和終止Tomcat\hA.3定義上下文\hA.4定義資源\hA.5安裝SSL證書(shū)\h附錄BServlet\hB.1ServletAPI概覽\hB.2Servlet\hB.3編寫(xiě)基礎(chǔ)的Servlet應(yīng)用程序\hB.3.1編寫(xiě)和編譯Servlet類\hB.3.2應(yīng)用程序目錄結(jié)構(gòu)\hB.3.3調(diào)用Servlet\hB.4ServletRequest\hB.5ServletResponse\hB.6ServletConfig\hB.7ServletContext\hB.8GenericServlet\hB.9HttpServlets\hB.9.1HttpServlet\hB.9.2HttpServletResponse\hB.10處理HTML表單\hB.11使用部署描述符\h附錄CJavaServerPages\hC.1JSP概述\hC.2注釋\hC.3隱式對(duì)象\hC.4指令\hC.4.1page指令\hC.4.2include指令\hC.5腳本元素\hC.5.1表達(dá)式\hC.5.2聲明\hC.5.3禁用腳本元素\hC.6動(dòng)作\hC.6.1useBean\hC.6.2setProperty和getProperty\hC.6.3include\hC.6.4forward\hC.7錯(cuò)誤處理\hC.8小結(jié)\h附錄D部署描述符\hD.1概述\hD.1.1核心元素\hD.1.2context-param\hD.1.3distributable\hD.1.4error\hD.1.5filter\hD.1.6filter-mapping\hD.1.7listener\hD.1.8locale-encoding-mapping-list和locale-encoding-mapping\hD.1.9login-config\hD.1.10mime-mapping\hD.1.11security-constraint\hD.1.12security-role\hD.1.13Servlet\hD.1.14servlet-mapping\hD.1.15session-config\hD.1.16welcome-file-list\hD.1.17JSP-SpecificElements\hD.1.18taglib\hD.1.19jsp-property-group\hD.2部署\hD.3webfragment\hD.4小結(jié)第1章Spring框架Spring框架是一個(gè)開(kāi)源的企業(yè)應(yīng)用開(kāi)發(fā)框架,作為一個(gè)輕量級(jí)的解決方案,其包含20多個(gè)不同的模塊。本書(shū)主要關(guān)注Core和Bean,以及SpringMVC模塊。SpringMVC是Spring的一個(gè)子框架,也是本書(shū)的主題。本章主要介紹Core和Bean兩個(gè)模塊,以及它們?nèi)绾翁峁┮蕾囎⑷虢鉀Q方案。為方便初學(xué)者,本書(shū)會(huì)深入討論依賴注入概念的細(xì)節(jié)。后續(xù)介紹開(kāi)發(fā)MVC應(yīng)用的章節(jié)將會(huì)使用到本章介紹的技能。在過(guò)去數(shù)年間,依賴注入技術(shù)作為代碼可測(cè)試性的一個(gè)解決方案已經(jīng)被廣泛應(yīng)用。實(shí)際上,Spring、谷歌Guice等偉大框架都采用了依賴注入技術(shù)。那么,什么是依賴注入技術(shù)?很多人在使用中并不區(qū)分依賴注入和控制反轉(zhuǎn)(IoC),盡管MartinFowler在其文章中已分析了二者的不同。
/articles/injection.html
簡(jiǎn)單來(lái)說(shuō),依賴注入的情況如下。有兩個(gè)組件A和B,A依賴于B。假定A是一個(gè)類,且A有一個(gè)方法importantMethod使用到了B,如下:
publicclassA{
publicvoidimportantMethod(){
Bb=...//getaninstanceofB
b.usefulMethod();
...
}
...
}
要使用B,類A必須先獲得組件B的實(shí)例引用。若B是一個(gè)具體類,則可通過(guò)new關(guān)鍵字直接創(chuàng)建組件B實(shí)例。但是,如果B是接口,且有多個(gè)實(shí)現(xiàn),則問(wèn)題就變得復(fù)雜了。我們固然可以任意選擇接口B的一個(gè)實(shí)現(xiàn)類,但這也意味著A的可重用性大大降低了,因?yàn)闊o(wú)法采用B的其他實(shí)現(xiàn)。依賴注入是這樣處理此類情景的:接管對(duì)象的創(chuàng)建工作,并將該對(duì)象的引用注入需要該對(duì)象的組件。以上述例子為例,依賴注入框架會(huì)分別創(chuàng)建對(duì)象A和對(duì)象B,將對(duì)象B注入到對(duì)象A中。為了能讓框架進(jìn)行依賴注入,程序員需要編寫(xiě)特定的set方法或者構(gòu)建方法。例如,為了能將B注入到A中,類A會(huì)被修改成如下形式:
publicclassA{
privateBb;
publicvoidimportantMethod(){
//noneedtoworryaboutcreatingBanymore
//Bb=...//getaninstanceofB
b.usefulMethod();
...
}
publicvoidsetB(Bb){
this.b=b;
}
}
修改后的類A新增了一個(gè)set方法,該方法將會(huì)被框架調(diào)用,以注入一個(gè)B的實(shí)例。由于對(duì)象依賴由依賴注入,類A的importantMethod方法不再需要在調(diào)用B的usefulMethod方法前去創(chuàng)建一個(gè)B的實(shí)例。當(dāng)然,也可以采用構(gòu)造器方式注入,如下所示:
publicclassA{
privateBb;
publicA(Bb){
this.b=b;
}
publicvoidimportantMethod(){
//noneedtoworryaboutcreatingBanymore
//Bb=...//getaninstanceofB
b.usefulMethod();
...
}
}
本例中,Spring會(huì)先創(chuàng)建B的實(shí)例,再創(chuàng)建實(shí)例A,然后把B注入到實(shí)例A中。注:Spring管理的對(duì)象稱為beans。通過(guò)提供一個(gè)控制反轉(zhuǎn)容器(或者依賴注入容器),Spring為我們提供一種可以“聰明”地管理Java對(duì)象依賴關(guān)系的方法。其優(yōu)雅之處在于,程序員無(wú)需了解Spring框架的存在,更不需要引入任何Spring類型。從1.0版本開(kāi)始,Spring就同時(shí)支持setter和構(gòu)造器方式的依賴注入。從2.5版本開(kāi)始,通過(guò)Autowired注解,Spring支持基于field方式的依賴注入,但缺點(diǎn)是程序必須引入org.springframework.beans.factory.annotation.Autowired,這對(duì)Spring產(chǎn)生了依賴,這樣,程序無(wú)法直接遷移到另一個(gè)依賴注入容器間。使用Spring,程序幾乎將所有重要對(duì)象的創(chuàng)建工作移交給Spring,并配置如何注入依賴。Spring支持XML或注解兩種配置方式。此外,還需要?jiǎng)?chuàng)建一個(gè)ApplicationContext對(duì)象,代表一個(gè)Spring控制反轉(zhuǎn)容器,org.springframework.context.ApplicationContext接口有多個(gè)實(shí)現(xiàn),包括ClassPathXmlApplicationContext和FileSystemXmlApplicationContext。這兩個(gè)實(shí)現(xiàn)都需要至少一個(gè)包含beans信息的XML文件。ClassPathXmlApplicationContext嘗試在類加載路徑中加載配置文件,而FileSystemXmlApplicationContext則從文件系統(tǒng)中加載。下面為從類路徑中加載config1.xml和config2.xml的ApplicationContext創(chuàng)建的一個(gè)代碼示例。
ApplicationContextcontext=newClassPathXmlApplicationContext(
newString[]{"config1.xml","config2.xml"});
可以通過(guò)調(diào)用ApplicationContext的getBean方法獲得對(duì)象。
Productproduct=context.getBean("product",Product.class);
getBean方法會(huì)查詢id為product且類型為Product的bean對(duì)象。注:理想情況下,我們僅需在測(cè)試代碼中創(chuàng)建一個(gè)ApplicationContext,應(yīng)用程序本身無(wú)需處理。對(duì)于SpringMVC應(yīng)用,可以通過(guò)一個(gè)SpringServlet來(lái)處理ApplicationContext,而無(wú)需直接處理。1.1XML配置文件從1.0版本開(kāi)始,Spring就支持基于XML的配置,從2.5版本開(kāi)始,增加了通過(guò)注解的配置支持。下面介紹如何配置XML文件。配置文件的根元素通常為:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans
<a>/schema/beans/spring-beans-3.0.xsd"></a>
...
</beans>
如果需要更強(qiáng)的Spring配置能力,可以在schemalocation屬性中添加相應(yīng)的schema。配置文件可以是一份,也可以分解為多份,以支持模塊化配置。ApplicationContext的實(shí)現(xiàn)類支持讀取多份配置文件。另一種選擇是,通過(guò)一份主配置文件,將該文件導(dǎo)入到其他配置文件。下面是一個(gè)導(dǎo)入其他配置文件的示例:
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans
<a>/schema/beans/spring-beans-3.0.xsd"></a>
<importresource="config1.xml"/>
<importresource="module2/config2.xml"/>
<importresource="/resources/config3.xml"/>
...
</beans>
bean元素的配置后面將會(huì)詳細(xì)介紹。1.2Spring控制反轉(zhuǎn)容器的使用本節(jié)主要介紹Spring如何管理bean和依賴關(guān)系。1.2.1通過(guò)構(gòu)造器創(chuàng)建一個(gè)bean實(shí)例前面已經(jīng)介紹,通過(guò)調(diào)用ApplicationContext的getBean方法可以獲取到一個(gè)bean的實(shí)例。下面的配置文件中定義了一個(gè)名為product的bean(見(jiàn)清單1.1)。清單1.1一個(gè)簡(jiǎn)單的配置文件
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="/schema/beans"
xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/schema/beans
<a>/schema/beans/spring-beans-3.0.xsd"></a>
<beanname="product"class="app01a.bean.Product"/>
</beans>
該bean的定義告訴Spring通過(guò)默認(rèn)無(wú)參的構(gòu)造器來(lái)初始化Product類。如果不存在該構(gòu)造器(如果類作者重載了構(gòu)造器,且沒(méi)有顯示聲明默認(rèn)構(gòu)造器),則Spring將拋出一個(gè)異常。注意,應(yīng)采用id或者name屬性標(biāo)識(shí)一個(gè)bean。為了讓Spring創(chuàng)建一個(gè)Product實(shí)例,應(yīng)將bean定義的name值“product”(具體實(shí)踐中也可以是id值)和Product類型作為參數(shù)傳遞給ApplicationContext的getBean方法。
ApplicationContextcontext=
newClassPathXmlApplicationContext(
newString[]{"spring-config.xml"});
Productproduct1=context.getBean("product",Product.class);
product1.setName("Excellentsnakeoil");
System.out.println("product1:"+product1.getName());
1.2.2通過(guò)工廠方法創(chuàng)建一個(gè)bean實(shí)例除了通過(guò)類的構(gòu)造器方式,Spring還同樣支持通過(guò)調(diào)用一個(gè)工廠的方法來(lái)初始化類。下面的bean定義展示了通過(guò)工廠方法來(lái)實(shí)例化java.util.Calendar。
<beanid="calendar"class="java.util.Calendar"
factory-method="getInstance"/>
本例中采用了id屬性,而非name屬性來(lái)標(biāo)識(shí)bean,采用了getBean方法來(lái)獲取Calendar實(shí)例。
ApplicationContextcontext=
newClassPathXmlApplicationContext(
newString[]{"spring-config.xml"});
Calendarcalendar=context.getBean("calendar",Calendar.class);
1.2.3DestroyMethod的使用有時(shí),我們希望一些類在被銷毀前能執(zhí)行一些方法。Spring考慮到了這樣的需求。可以在bean定義中配置destroy-method屬性,來(lái)指定在銷毀前要被執(zhí)行的方法。下面的例子中,我們配置Spring通過(guò)java.util.concurrent.Executors的靜態(tài)方法newCachedThreadPool來(lái)創(chuàng)建一個(gè)java.uitl.concurrent.ExecutorService實(shí)例,并指定了destroy-method屬性值為shutdown方法。這樣,Spring會(huì)在銷毀ExecutorService實(shí)例前調(diào)用其shutdown方法。
<beanid="executorService"class="java.util.concurrent.Executors"
factory-method="newCachedThreadPool"
destroy-method="shutdown"/>
1.2.4向構(gòu)造器傳遞參數(shù)Spring支持通過(guò)帶參數(shù)的構(gòu)造器來(lái)初始化類(見(jiàn)清單1.2)。清單1.2Product類
packageapp01a.bean;
importjava.io.Serializable;
publicclassProductimplementsSerializable{
privatestaticfinallongserialVersionUID=748392348L;
privateStringname;
privateStringdescription;
privatefloatprice;
publicProduct(){
}
publicProduct(Stringname,Stringdescription,floatprice){
=name;
this.description=description;
this.price=price;
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}
publicStringgetDescription(){
returndescription;
}
publicvoidsetDescription(Stringdescription){
this.description=description;
}
publicfloatgetPrice(){
returnprice;
}
publicvoidsetPrice(floatprice){
this.price=price;
}
}
如下定義展示了如何通過(guò)參數(shù)名傳遞參數(shù)。
<beanname="featuredProduct"class="app01a.bean.Product">
<constructor-argname="name"value="UltimateOliveOil"/>
<constructor-argname="description"
value="Thepurestoliveoilonthemarket"/>
<constructor-argname="price"value="9.95"/>
</bean>
這樣,在創(chuàng)建Product實(shí)例時(shí),Spring會(huì)調(diào)用如下構(gòu)造器:
publicProduct(Stringname,Stringdescription,floatprice){
=name;
this.description=description;
this.price=price;
}
除了通過(guò)名稱傳遞參數(shù)外,Spring還支持通過(guò)指數(shù)方式傳遞參數(shù),具體如下:
<beanname="featuredProduct2"class="app01a.bean.Product">
<constructor-argindex="0"value="UltimateOliveOil"/>
<constructor-argindex="1"
value="Thepurestoliveoilonthemarket"/>
<constructor-argindex="2"value="9.95"/>
</bean>
需要說(shuō)明的是,采用這種方式,對(duì)應(yīng)構(gòu)造器的所有參數(shù)必須傳遞,缺一不可。1.2.5Setter方式依賴注入下面以Employee類和Address類為例,介紹setter方式依賴注入(見(jiàn)清單1.3和清單1.4)。清單1.3Employee類
packageapp01a.bean;
publicclassEmployee{
privateStringfirstName;
privateStringlastName;
privateAddresshomeAddress;
publicEmployee(){
}
publicEmployee(StringfirstName,StringlastName,Address
homeAddress){
this.firstName=firstName;
this.lastName=lastName;
this.homeAddress=homeAddress;
}
publicStringgetFirstName(){
returnfirstName;
}
publicvoidsetFirstName(StringfirstName){
this.firstName=firstName;
}
publicStringgetLastName(){
returnlastName;
}
publicvoidsetLastName(StringlastName){
this.lastName=lastName;
}
publicAddressgetHomeAddress(){
returnhomeAddress;
}
publicvoidsetHomeAddress(AddresshomeAddress){
this.homeAddress=homeAddress;
}
@Override
publicStringtoString(){
returnfirstName+""+lastName
+"\n"+homeAddress;
}
}
清單1.4Address類
packageapp01a.bean;
publicclassAddress{
privateStringline1;
privateStringline2;
privateStringcity;
privateStringstate;
privateStringzipCode;
privateStringcountry;
publicAddress(Stringline1,Stringline2,Stringcity,
Stringstate,StringzipCode,Stringcountry){
this.line1=line1;
this.line2=line2;
this.city=city;
this.state=state;
this.zipCode=zipCode;
this.country=country;
}
//gettersandsettersomitted
@Override
publicStringtoString(){
returnline1+"\n"
+line2+"\n"
+city+"\n"
+state+""+zipCode+"\n"
+country;
}
}
Employee依賴于Address類,可以通過(guò)如下配置來(lái)保證每個(gè)Employee實(shí)例都能包含Address實(shí)例。
<beanname="simpleAddress"class="app01a.bean.Address">
<constructor-argname="line1"value="151CornerStreet"/>
<constructor-argname="line2"value=""/>
<constructor-argname="city"value="Albany"/>
<constructor-argname="state"value="NY"/>
<constructor-argname="zipCode"value="99999"/>
<constructor-argname="country"value="US"/>
</bean>
<beanname="employee1"class="app01a.bean.Employee">
<propertyname="homeAddress"ref="simpleAddress"/>
<propertyname="firstName"value="Junior"/>
<propertyname="lastName"value="Moore"/>
</bean>
simpleAddress對(duì)象是Address類的一個(gè)實(shí)例,其通過(guò)構(gòu)造器方式實(shí)例化。employee1對(duì)象則通過(guò)配置property元素來(lái)調(diào)用setter方法以設(shè)置值。需要注意的是,homeAddress屬性配置的是simpleAddress對(duì)象的引用。被引用對(duì)象的配置定義無(wú)須早于引用其對(duì)象的定義。本例中,employee1對(duì)象可以出現(xiàn)在simpleAddress對(duì)象定義之前。1.2.6構(gòu)造器方式依賴注入清單1.3所示的Employee類提供了一個(gè)可以傳遞參數(shù)的構(gòu)造器,我們還可以將Address對(duì)象通過(guò)構(gòu)造器注入,如下所示:
<beanname="employee2"class="app01a.bean.Employee">
<constructor-argname="firstName"value="Senior"/>
<constructor-argname="lastName"value="Moore"/>
<constructor-argname="homeAddress"ref="simpleAddress"/>
</bean>
<beanname="simpleAddress"class="app01a.bean.Address">
<constructor-argname="line1"value="151CornerStreet"/>
<constructor-argname="line2"value=""/>
<constructor-argname="city"value="Albany"/>
<constructor-argname="state"value="NY"/>
<constructor-argname="zipCode"value="99999"/>
<constructor-argname="country"value="US"/>
</bean>
1.3小結(jié)本章學(xué)習(xí)了依賴注入的概念以及基于Spring容器的實(shí)踐,后續(xù)將在此基礎(chǔ)之上配置Spring應(yīng)用。
第2章模型2和MVC模式JavaWeb應(yīng)用開(kāi)發(fā)中有兩種設(shè)計(jì)模型,為了方便,分別稱為模型1和模型2。模型1是頁(yè)面中心,適合于小應(yīng)用開(kāi)發(fā)。而模型2基于MVC模式,是JavaWeb應(yīng)用的推薦架構(gòu)(簡(jiǎn)單類型的應(yīng)用除外)。本章將會(huì)討論模型2,并展示3個(gè)不同示例應(yīng)用。第一個(gè)應(yīng)用是一個(gè)基本的模型2應(yīng)用,采用Servlet作為控制器,第二個(gè)應(yīng)用引入了控制器,第三個(gè)應(yīng)用引入了驗(yàn)證控件來(lái)校驗(yàn)用戶的輸入。2.1模型1介紹第一次學(xué)習(xí)JSP,通常通過(guò)鏈接方式進(jìn)行JSP頁(yè)面間的跳轉(zhuǎn)。這種方式非常直接,但在中型和大型應(yīng)用中,這種方式會(huì)帶來(lái)維護(hù)上的問(wèn)題。修改一個(gè)JSP頁(yè)面的名字,會(huì)導(dǎo)致大量頁(yè)面中的鏈接需要修正。因此,實(shí)踐中并不推薦模型1(但僅2~3個(gè)頁(yè)面的應(yīng)用除外)。2.2模型2介紹模型2基于模型—視圖—控制器(MVC)模式,該模式是Smalltalk-80用戶交互的核心概念,那時(shí)還沒(méi)有設(shè)計(jì)模式的說(shuō)法,當(dāng)時(shí)稱為MVC范式。一個(gè)實(shí)現(xiàn)MVC模式的應(yīng)用包含模型、視圖和控制器3個(gè)模塊。視圖負(fù)責(zé)應(yīng)用的展示。模型封裝了應(yīng)用的數(shù)據(jù)和業(yè)務(wù)邏輯??刂破髫?fù)責(zé)接收用戶輸入,改變模型,以及調(diào)整視圖的顯示。注:SteveBurbeck博士的論文:ApplicationsProgramminginSmalltalk-80(TM):HowtouseModel-View-Controller(MVC)詳細(xì)討論了MVC模式,論文地址為/users/smarch/st-docs/mvc.html。模型2中,Servlet或者Filter都可以充當(dāng)控制器。幾乎所有現(xiàn)代Web框架都是模型2的實(shí)現(xiàn)。SpringMVC和Struts1使用一個(gè)Servlet作為控制器,而Struts2則使用一個(gè)Filter作為控制器。大部分都采用JSP頁(yè)面作為應(yīng)用的視圖,當(dāng)然也有其他技術(shù)。而模型則采用POJO(PlainOldJavaObject)。不同于EJB等,POJO是一個(gè)普通對(duì)象。實(shí)踐中會(huì)采用一個(gè)JavaBean來(lái)持有模型狀態(tài),并將業(yè)務(wù)邏輯放到一個(gè)Action類中。一個(gè)JavaBean必須擁有一個(gè)無(wú)參的構(gòu)造器,通過(guò)get/set方法來(lái)訪問(wèn)參數(shù),同時(shí)支持持久化。圖2.1展示了一個(gè)模型2應(yīng)用的架構(gòu)圖。圖2.1模型2架構(gòu)圖每個(gè)HTTP請(qǐng)求都發(fā)送給控制器,請(qǐng)求中的URI標(biāo)識(shí)出對(duì)應(yīng)的action。action代表了應(yīng)用可以執(zhí)行的一個(gè)操作。一個(gè)提供了Action的Java對(duì)象稱為action對(duì)象。一個(gè)action類可以支持多個(gè)action(在SpringMVC以及Struts2中),或者一個(gè)action(在Struts1中)??此坪?jiǎn)單的操作可能需要多個(gè)action。如,向數(shù)據(jù)庫(kù)添加一個(gè)產(chǎn)品,需要兩個(gè)action。(1)顯示一個(gè)“添加產(chǎn)品”的表單,以便用戶能輸入產(chǎn)品信息。(2)將表單信息保存到數(shù)據(jù)庫(kù)中。如前述,我們需要通過(guò)URI方式告訴控制器執(zhí)行相應(yīng)的action。例如,通過(guò)發(fā)送類似如下URI,來(lái)顯示“添加產(chǎn)品”表單。
http://
domain
/
appName
/product_input
通過(guò)類似如下URI,來(lái)保存產(chǎn)品。
http://
domain
/
appName
/product_save
控制器會(huì)解析URI并調(diào)用相應(yīng)的action,然后將模型對(duì)象放到視圖可以訪問(wèn)的區(qū)域(以便服務(wù)端數(shù)據(jù)可以展示在瀏覽器上)。最后,控制器利用RequestDispatcher跳轉(zhuǎn)到視圖(JSP頁(yè)面)。在JSP頁(yè)面中,用表達(dá)式語(yǔ)言以及定制標(biāo)簽顯示數(shù)據(jù)。注意:調(diào)用RequestDispatcher.forward方法并不會(huì)停止執(zhí)行剩余的代碼。因此,若forward方法不是最后一行代碼,則應(yīng)顯式地返回。2.3模型2之Servlet控制器為了便于對(duì)模型2有一個(gè)直觀的了解,本節(jié)將展示一個(gè)簡(jiǎn)單模型2應(yīng)用。實(shí)踐中,模型2應(yīng)用非常復(fù)雜。示例應(yīng)用名為app02a,其功能設(shè)定為輸入一個(gè)產(chǎn)品信息。具體為:用戶填寫(xiě)產(chǎn)品表單(圖2.2)并提交;示例應(yīng)用保存產(chǎn)品并展示一個(gè)完成頁(yè)面,顯示已保存的產(chǎn)品信息(圖2.3)。圖2.2產(chǎn)品表單示例應(yīng)用支持如下兩個(gè)action。(1)展示“添加產(chǎn)品”表單。該action發(fā)送圖2.2中的輸入表單到瀏覽器上,其對(duì)應(yīng)的URI應(yīng)包含字符串product_input。(2)保存產(chǎn)品并返回圖2.3所示的完成頁(yè)面,對(duì)應(yīng)的URI必須包含字符串product_save。示例應(yīng)用app02a由如下組件構(gòu)成。(1)一個(gè)Product類,作為product的領(lǐng)域?qū)ο?。圖2.3產(chǎn)品詳細(xì)頁(yè)(2)一個(gè)ProductForm類,封裝了HTML表單的輸入項(xiàng)。(3)一個(gè)ControllerServlet類,本示例應(yīng)用的控制器。(4)一個(gè)SaveProductAction類。(5)兩個(gè)JSP頁(yè)面(ProductForm.jsp和ProductDetail.jsp)作為view。(6)一個(gè)CSS文件,定義了兩個(gè)JSP頁(yè)面的顯示風(fēng)格。app02a目錄結(jié)構(gòu)如圖2.4所示。圖2.4app02a目錄結(jié)構(gòu)所有的JSP文件都放置在WEB-INF目錄下,因此無(wú)法被直接訪問(wèn)。下面詳細(xì)介紹示例應(yīng)用的每個(gè)組件。2.3.1Product類Product實(shí)例是一個(gè)封裝了產(chǎn)品信息的JavaBean。Product類(見(jiàn)清單2.1)包含3個(gè)屬性:productName、description和price。清單2.1Product類
packageapp02a.domain;
importjava.io.Serializable;
publicclassProductimplementsSerializable{
privatestaticfinallongserialVersionUID=748392348L;
privateStringname;
privateStringdescription;
privatefloatprice;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}
publicStringgetDescription(){
returndescription;
}
publicvoidsetDescription(Stringdescription){
this.description=description;
}
publicfloatgetPrice(){
returnprice;
}
publicvoidsetPrice(floatprice){
this.price=price;
}
}
Product類實(shí)現(xiàn)了java.io.Serializable接口,其實(shí)例可以安全地將數(shù)據(jù)保存到HttpSession中。根據(jù)Serializable要求,Product實(shí)現(xiàn)了一個(gè)serialVersionUID屬性。2.3.2ProductForm類表單類與HTML表單相映射,是后者在服務(wù)端的代表。ProductForm類(見(jiàn)清單2.2)包含了一個(gè)產(chǎn)品的字符串值。ProductForm類看上去同Product類相似,這就引出一個(gè)問(wèn)題:ProductForm類是否有存在的必要。實(shí)際上,表單對(duì)象會(huì)傳遞ServletRequest給其他組件,類似Validator(本章后續(xù)段落會(huì)介紹)。而ServletRequest是一個(gè)Servlet層的對(duì)象,不應(yīng)當(dāng)暴露給應(yīng)用的其他層。另一個(gè)原因是,當(dāng)數(shù)據(jù)校驗(yàn)失敗時(shí),表單對(duì)象將用于保存和展示用戶在原始表單上的輸入。2.5節(jié)將會(huì)詳細(xì)介紹應(yīng)如何處理。注意:大部分情況下,一個(gè)表單類不需要實(shí)現(xiàn)Serializable接口,因?yàn)楸韱螌?duì)象很少保存在HttpSession中。清單2.2ProductForm類
packageapp02a.form;
publicclassProductForm{
privateStringname;
privateStringdescription;
privateStringprice;
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
=name;
}
publicStringgetDescription(){
returndescription;
}
publicvoidsetDescription(Stringdescription){
this.description=description;
}
publicStringgetPrice(){
returnprice;
}
publicvoidsetPrice(Stringprice){
this.price=price;
}
}
2.3.3ControllerServlet類ControllerServlet類(見(jiàn)清單2.3)繼承自javax.servlet.http.HttpServlet類。其doGet和doPost方法最終調(diào)用process方法,該方法是整個(gè)Servlet控制器的核心。可能有人好奇為何這個(gè)Servlet控制器被命名為ControllerServlet,實(shí)際上,這里遵從了一個(gè)約定:所有Servlet的類名稱都帶有servlet后綴。清單2.3ControllerServlet類
packageapp02a.servlet;
importjava.io.IOException;
importjavax.servlet.RequestDispatcher;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServlet;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importapp02a.domain.Product;
importapp02a.form.ProductForm;
publicclassControllerServletextendsHttpServlet{
privatestaticfinallongserialVersionUID=1579L;
@Override
publicvoiddoGet(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsIOException,ServletException{
process(request,response);
}
@Override
publicvoiddoPost(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsIOException,ServletException{
process(request,response);
}
privatevoidprocess(HttpServletRequestrequest,
HttpServletResponseresponse)
throwsIOException,ServletException{
Stringuri=request.getRequestURI();
/*
*uriisinthisform:/contextName/resourceName,
*forexample:/app10a/product_input.
*However,intheeventofadefaultcontext,the
*contextnameisempty,andurihasthisform
*/resourceName,e.g.:/product_input
*/
intlastIndex=uri.lastIndexOf("/");
Stringaction=uri.substring(lastIndex+1);
//executeanaction
if(action.equals("product_input.action")){
//noactionclass,thereisnothingtobedone
}elseif(action.equals("product_save.action")){
//createform
ProductFormproductForm=newProductForm();
//populateactionproperties
productForm.setName(request.getParameter("name"));
productForm.setDescription(
request.getParameter("description"));
productForm.setPrice(request.getParameter("price"));
//createmodel
Productproduct=newProduct();
product.setName(productForm.getName());
product.setDescription(productForm.getDescription());
try{
product.setPrice(Float.parseFloat(
productForm.getPrice()));
}catch(NumberFormatExceptione){
}
//codetosaveproduct
//storemodelinascopevariablefortheview
request.setAttribute("product",product);
}
//forwardtoaview
StringdispatchUrl=null;
if(action.equals("product_input.action")){
dispatchUrl="/WEB-INF/jsp/ProductForm.jsp";
}elseif(action.equals("product_save.action")){
dispatchUrl="/WEB-INF/jsp/ProductDetails.jsp";
}
if(dispatchUrl!=null){
RequestDispatcherrd=
request.getRequestDispatcher(dispatchUrl);
rd.forward(request,response);
}
}
}
若基于Servlet3.0規(guī)范,則可以采用注解的方式,而無(wú)需在部署描述符中進(jìn)行映射。
...
importjavax.servlet.annotation.WebServlet;
...
@WebServlet(name="ControllerServlet",urlPatterns={
"/product_input","/product_save"})
publicclassControllerServletextendsHttpServlet{
...
}
ControllerServlet的process方法處理所有輸入請(qǐng)求。首先是獲取請(qǐng)求URI和action名稱。
Stringuri=request.getRequestURI();
intlastIndex=uri.lastIndexOf("/");
Stringaction=uri.substring(lastIndex+1);
在本示例應(yīng)用中,action值只會(huì)是product_input或product_save。接著,process方法執(zhí)行如下步驟。(1)創(chuàng)建并根據(jù)請(qǐng)求參數(shù)構(gòu)建一個(gè)表單對(duì)象。product_save操作涉及3個(gè)屬性:name、description和price。然后創(chuàng)建一個(gè)領(lǐng)域?qū)ο?,并通過(guò)表單對(duì)象設(shè)置相應(yīng)屬性。(2)執(zhí)行針對(duì)領(lǐng)域?qū)ο蟮臉I(yè)務(wù)邏輯,包括將其持久化到數(shù)據(jù)庫(kù)中。(3)轉(zhuǎn)發(fā)請(qǐng)求到視圖(JSP頁(yè)面)。process方法中判斷action的if代碼塊如下:
//executeanaction
if(action.equals("product_input")){
//thereisnothingtobedone
}elseif(action.equals("product_save")){
...
//codetosaveproduct
}
對(duì)于product_input,無(wú)需任何操作,而針對(duì)product_save,則創(chuàng)建一個(gè)ProductForm對(duì)象和Product對(duì)象,并將前者的屬性值復(fù)制到后者。這個(gè)步驟中,針對(duì)空字符串的復(fù)制處理將留到稍后的“校驗(yàn)器”一節(jié)處理。再次,process方法實(shí)例化SaveProductAction類,并調(diào)用其save方法。
//createform
ProductFormproductForm=newProductForm();
//populateactionproperties
productForm.setName(request.getParameter("name"));
productForm.setDescription(
request.getParameter("description"));
productForm.setPrice(request.getParameter("price"));
//createmodel
Productproduct=newProduct();
product.setName(productForm.getName());
product.setDescription(product.getDescription());
try{
product.setPrice(Float.parseFloat(
productForm.getPrice()));
}catch(NumberFormatExceptione){
}
//executeactionmethod
SaveProductActionsaveProductAction=newSaveProductAction();
saveProductAction.save(product);
//storemodelinascopevariablefortheview
request.setAttribute("product",product);
然后,將Product對(duì)象放入HttpServletRequest對(duì)象中,以便對(duì)應(yīng)的視圖能訪問(wèn)到。
//storeactioninascopevariablefortheview
request.setAttribute("product",product);
最后,process方法轉(zhuǎn)到視圖,如果action是product_input,則轉(zhuǎn)到ProductForm.jsp頁(yè)面,否則轉(zhuǎn)到ProductDetails.jsp頁(yè)面。
//forwardtoaview
StringdispatchUrl=null;
if(action.equals("Product_input")){
dispatchUrl="/WEB-INF/jsp/ProductForm.jsp";
}elseif(action.equals("Product_save")){
dispatchUrl="/WEB-INF/jsp/ProductDetails.jsp";
}
if(dispatchUrl!=null){
RequestDispatcherrd=request.getRequestDispatcher(dispatchUrl);
rd.forward(request,response);
}
2.3.4視圖示例應(yīng)用包含兩個(gè)JSP頁(yè)面。第一個(gè)頁(yè)面ProductForm.jsp對(duì)應(yīng)于product_input操作,第二個(gè)頁(yè)面ProductDetails.jsp對(duì)應(yīng)于product_save操作。ProductForm.jsp以及ProductDetails.jsp頁(yè)面代碼分別見(jiàn)清單2.4和清單2.5。清單2.4ProductForm.jsp
<!DOCTYPEHTML>
<html>
<head>
<title>AddProductForm</title>
<styletype="text/css">@importurl(css/main.css);</style>
</head>
<body>
<divid="global">
<formaction="product_save.action"method="post">
<fieldset>
<legend>Addaproduct</legend>
<p>
<labelfor="name">ProductName:</label>
<inputtype="text"id="name"name="name"tabindex="1">
</p>
<p>
<labelfor="description">Description:</label>
<inputtype="text"id="description"name="description"tabindex="2">
</p>
<p>
<labelfor="price">Price:</label>
<inputtype="text"id="price"name="price"tabindex="3">
</p>
<pid="buttons">
<inputid="reset"type="reset"tabindex="4">
<inputid="submit"type="submit"tabindex="5"value="AddProduct">
</p>
</fieldset>
</form>
</div>
</body>
</html>
清單2.5ProductDetails.jsp
<!DOCTYPEHTML>
<html>
<head>
<title>SaveProduct</title>
<styletype="text/css">@importurl(css/main.css);</style>
</head>
<body>
<divid="global">
<h4>Theproducthasbeensaved.</h4>
<p>
<h5>Details:</h5>
ProductName:${}<br/>
Description:${product.description}<br/>
Price:$${product.price}
</p>
</div>
</body>
</html>
ProductForm.jsp頁(yè)面包含了一個(gè)HTML表單。頁(yè)面沒(méi)有采用HTML表格方式進(jìn)行布局,而采用了位于css目錄下的main.css中的CSS樣式表進(jìn)行控制。ProductDetails.jsp頁(yè)面通過(guò)表達(dá)式語(yǔ)言(EL)訪問(wèn)HttpServletRequest所包含的product對(duì)象。本書(shū)第8章“表達(dá)式語(yǔ)言”會(huì)詳細(xì)介紹。本示例應(yīng)用作為一個(gè)模型2的應(yīng)用,可以通過(guò)如下幾種方式避免用戶通過(guò)瀏覽器直接訪問(wèn)JSP頁(yè)面。將JSP頁(yè)面都放到WEB-INF目錄下。WEB-INF目錄下的任何文件或子目錄都受保護(hù),無(wú)法通過(guò)瀏覽器直接訪問(wèn),但控制器依然可以轉(zhuǎn)發(fā)請(qǐng)求到這些頁(yè)面。利用一個(gè)servletfilter過(guò)濾JSP頁(yè)面。在部署
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2025年度建筑木工環(huán)保建材研發(fā)與應(yīng)用合同
- 2025年度城市更新工程款支付保證委托擔(dān)保合同
- 邵陽(yáng)2024年湖南邵陽(yáng)市隆回縣部分事業(yè)單位招聘20人筆試歷年參考題庫(kù)附帶答案詳解
- 綏化2024年黑龍江綏化市北林區(qū)事業(yè)單位招聘77人筆試歷年參考題庫(kù)附帶答案詳解
- 深圳2024年廣東深圳市環(huán)境科學(xué)研究院招聘(第二批)筆試歷年參考題庫(kù)附帶答案詳解
- 棗莊2025年山東棗莊市商務(wù)發(fā)展促進(jìn)中心高層次急需緊缺人才招聘2人筆試歷年參考題庫(kù)附帶答案詳解
- 2025年中國(guó)復(fù)合材料籃球板市場(chǎng)調(diào)查研究報(bào)告
- 2025年中國(guó)全自動(dòng)鍋爐軟化水裝置市場(chǎng)調(diào)查研究報(bào)告
- 2025年車(chē)門(mén)總成項(xiàng)目可行性研究報(bào)告
- 2025至2031年中國(guó)遙信電源浪涌保護(hù)器行業(yè)投資前景及策略咨詢研究報(bào)告
- 《有機(jī)化學(xué)》課件-第十章 羧酸及其衍生物
- 人教版道德與法治五年級(jí)下冊(cè)《第一單元 我們一家人》大單元整體教學(xué)設(shè)計(jì)2022課標(biāo)
- 2024-2030年中國(guó)茶具行業(yè)市場(chǎng)競(jìng)爭(zhēng)格局及未來(lái)發(fā)展趨勢(shì)預(yù)測(cè)報(bào)告
- 2024年高考真題-政治(福建卷) 含解析
- 中醫(yī)培訓(xùn)課件:《經(jīng)穴推拿術(shù)》
- 新能源汽車(chē)畢業(yè)論文
- 壓瘡的預(yù)防及護(hù)理課件(完整版)
- 專升本-英語(yǔ)高頻詞匯
- 《修辭立其誠(chéng)》課件+2023-2024學(xué)年統(tǒng)編版高中語(yǔ)文選擇性必修中冊(cè)
- excel培訓(xùn)課件教學(xué)
- 2024年浙江省中考社會(huì)試卷真題(含標(biāo)準(zhǔn)答案及評(píng)分標(biāo)準(zhǔn))
評(píng)論
0/150
提交評(píng)論