![我們所學(xué)習(xí)的技術(shù)框架有很多_第1頁(yè)](http://file4.renrendoc.com/view/24e7805af2ab9d28c4cc0f66e979e614/24e7805af2ab9d28c4cc0f66e979e6141.gif)
![我們所學(xué)習(xí)的技術(shù)框架有很多_第2頁(yè)](http://file4.renrendoc.com/view/24e7805af2ab9d28c4cc0f66e979e614/24e7805af2ab9d28c4cc0f66e979e6142.gif)
![我們所學(xué)習(xí)的技術(shù)框架有很多_第3頁(yè)](http://file4.renrendoc.com/view/24e7805af2ab9d28c4cc0f66e979e614/24e7805af2ab9d28c4cc0f66e979e6143.gif)
![我們所學(xué)習(xí)的技術(shù)框架有很多_第4頁(yè)](http://file4.renrendoc.com/view/24e7805af2ab9d28c4cc0f66e979e614/24e7805af2ab9d28c4cc0f66e979e6144.gif)
![我們所學(xué)習(xí)的技術(shù)框架有很多_第5頁(yè)](http://file4.renrendoc.com/view/24e7805af2ab9d28c4cc0f66e979e614/24e7805af2ab9d28c4cc0f66e979e6145.gif)
版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
我們所學(xué)習(xí)的技術(shù)框架有很多,例如struts1、struts2、JSF、Spring、SpringMVC、Hibernate、ibatis····在上篇博客我說(shuō)了我們可能在開(kāi)發(fā)的路途上會(huì)要學(xué)習(xí)這些框架,我也給出了我對(duì)框架學(xué)習(xí)的幾點(diǎn):
我們首先要看一下這個(gè)框架屬于開(kāi)發(fā)結(jié)構(gòu)中的那一層。因?yàn)槲覀兊拈_(kāi)發(fā)都是要用分層的思想來(lái)做的,所以我們第一個(gè)就要看看我們開(kāi)發(fā)分層中,各個(gè)層次之間有哪些框架。
我們從圖上看到了那些框架屬于哪一層的(這里還有很多框架沒(méi)有涉及到)。之后我們來(lái)看一些常用的框架(這個(gè)常用相對(duì)于個(gè)人而言,我這里所說(shuō)的常用針對(duì)我自己來(lái)說(shuō),如果這里我沒(méi)有介紹全的話(huà),大家可以到相關(guān)的框架官網(wǎng)去查閱一下資料自主學(xué)習(xí))。
下面我就簡(jiǎn)單的介紹一些我經(jīng)常使用的框架的結(jié)構(gòu)和一些分析:
Struts框架(分為struts1和struts2):
一、Struts框架結(jié)構(gòu)圖:
優(yōu)點(diǎn):
1.Struts框架是一個(gè)基于mvc的框架,所以它繼承了所有mvc的優(yōu)點(diǎn),例如:復(fù)用性好,團(tuán)隊(duì)開(kāi)發(fā)分工明確,結(jié)構(gòu)層次分明等
2.給程序開(kāi)發(fā)者在servlet層上節(jié)約了大量的開(kāi)發(fā)時(shí)間,應(yīng)用程序開(kāi)發(fā)者不再去觸及大量的servlet的編寫(xiě),僅僅變換為配置文件。
二、Struts1框架
1.框架的結(jié)構(gòu)圖:
2.Struts1框架有五個(gè)常用對(duì)象:actionservlet、actionmapping、actionform、action、actionforward
a)Actionservlet是核心控制,URL地址映射、ActionForm的匹配、Action的執(zhí)行都需要這個(gè)類(lèi)來(lái)進(jìn)行導(dǎo)航
b)Actionmapping:它們可將請(qǐng)求URI映射到Action類(lèi),并且將Action類(lèi)與ActionFormbean相關(guān)聯(lián)
c)Actionform:收集表單數(shù)據(jù)
d)Action:完成所需的業(yè)務(wù)邏輯,確定要跳轉(zhuǎn)的頁(yè)面
e)Actionforward:用來(lái)封裝轉(zhuǎn)發(fā)路徑的
3.Struts1框架的執(zhí)行流程:
1)檢索和用戶(hù)匹配的ActionMapping實(shí)例,如果不存在,就返回請(qǐng)求路徑無(wú)效的錯(cuò)誤信息
2)如果ActionForm實(shí)例不存在,就創(chuàng)建一個(gè)ActionForm的對(duì)象,把客戶(hù)提交的表單數(shù)據(jù)封裝到ActionForm對(duì)象中。
3)根據(jù)配置信息決定是否要進(jìn)行表單驗(yàn)證,如果需要,就調(diào)用ActionForm的validate()方法
4)如果validate()方法放回null,或者并不包含ActionMessage的ActionError對(duì)象,就表示驗(yàn)證成功
5)ActionServlet根據(jù)ActionMapping所包含的映射信息決定將請(qǐng)求轉(zhuǎn)發(fā)給那個(gè)action,如果相應(yīng)的action實(shí)例不存在,就先創(chuàng)建這個(gè)action對(duì)象,然后再調(diào)用這個(gè)action的excute()方法
6)action的execute()方法返回一個(gè)ActionForword對(duì)象,ActionServlet會(huì)把客戶(hù)請(qǐng)求轉(zhuǎn)發(fā)給ActionForword對(duì)象所指向的JSP組件
7)ActionForword對(duì)象指向JSP組件生成動(dòng)態(tài)網(wǎng)頁(yè)返回給客戶(hù)
4.優(yōu)點(diǎn):和struts框架的優(yōu)點(diǎn)相同
5.缺點(diǎn):
1)表現(xiàn)層技術(shù)單一:僅能用jsp
2)與servletAPI耦合性高,難于測(cè)試(httpservletrequest、httpservletresponse)
3)嚴(yán)重依賴(lài)于ServletAPI(繼承action,繼承actionform),與struts1框架耦合性太高
這篇博客就寫(xiě)到這里,如果再寫(xiě)篇幅可能會(huì)過(guò)長(zhǎng),對(duì)讀者的閱讀造成負(fù)面影響,所以我會(huì)在下面的博客中陸續(xù)介紹我經(jīng)常使用的框架,當(dāng)然我也會(huì)在這些同層之間的框架的分析中加入各個(gè)框架的區(qū)別,當(dāng)然在適當(dāng)?shù)牡胤綍?huì)畫(huà)一些圖片來(lái)表示他們之間的知識(shí)關(guān)聯(lián)性,希望讀者能夠我一些建議和意見(jiàn)。
在上篇博客中,我簡(jiǎn)單的介紹了我們分層開(kāi)發(fā)中每一層中擁有的框架,而且介紹了我常用的框架struts1的結(jié)構(gòu)和原理分析,那么今天我繼續(xù)介紹我熟悉的框架struts2的框架的結(jié)構(gòu)和原理分析。
在說(shuō)struts2框架之前,我要先介紹另外一個(gè)框架webwork框架,這個(gè)框架也是一個(gè)mvc的框架,這個(gè)框架的設(shè)計(jì)思路是采用攔截鏈將用戶(hù)的請(qǐng)求的數(shù)據(jù)轉(zhuǎn)發(fā)到Action中,并負(fù)責(zé)將Action的處理結(jié)果轉(zhuǎn)換成對(duì)用戶(hù)的響應(yīng)。它的這種設(shè)計(jì)思路能夠和ServletAPI分離,鑒于我們的上篇博客介紹的struts1的缺點(diǎn),所以webwork框架解決了struts1的這個(gè)缺點(diǎn)。
我們來(lái)看一下webwork框架的結(jié)構(gòu)圖:
有了這個(gè)流程圖,我就不給大家講解具體的原理流程了,它采用的是攔截鏈的機(jī)制,通過(guò)這些攔截鏈完成用戶(hù)的相應(yīng)請(qǐng)求,從而與servletAPI分離,當(dāng)與servlet分離開(kāi)的時(shí)候,也就是表明和容器解耦了;另外,我們從結(jié)構(gòu)圖中看到它的視圖模版有jsp、FreeMarker等等,它的表示層技術(shù)比struts1框架的飽滿(mǎn)許多。
所以,webwork框架解決了struts1框架存在的問(wèn)題,而且它的設(shè)計(jì)思路是非常好的,鑒于此,struts2框架就在struts1框架的基礎(chǔ)上引入了webwork框架的設(shè)計(jì)思路應(yīng)運(yùn)而生了。所以我們就能夠發(fā)現(xiàn)struts2兼具struts1的特性而且通過(guò)引入webwork框架的設(shè)計(jì)思路解決了struts1的一些缺點(diǎn)。
struts2框架的大致的體系圖:
從圖中我們能夠看出它是引入的webwork框架的設(shè)計(jì)思路,而且它也是基于mvc的一個(gè)開(kāi)源的框架。之后我們來(lái)說(shuō)一下struts2框架的一個(gè)執(zhí)行流程(流程圖和webwork框架非常類(lèi)似):
瀏覽器發(fā)送請(qǐng)求,通過(guò)幾層過(guò)濾器完成一些功能,之后到actionmapper中,之后將請(qǐng)求傳到核心控制器中核心控制器filterDispatcher根據(jù)請(qǐng)求決定調(diào)用合適的Action調(diào)用webwork的攔截器鏈自動(dòng)請(qǐng)求通用功能,如校驗(yàn)之類(lèi)的操作回調(diào)action的execute方法,獲取用戶(hù)請(qǐng)求執(zhí)行相應(yīng)的業(yè)務(wù)邏輯之后返回字符串,匹配result,之后跳轉(zhuǎn)到相應(yīng)的視圖或其他的文檔之后在執(zhí)行相應(yīng)的攔截器鏈自動(dòng)請(qǐng)求功能,隨后轉(zhuǎn)到web客戶(hù)端。
這樣我們就對(duì)struts2框架的結(jié)構(gòu)上的東西做了一個(gè)簡(jiǎn)單的介紹。在上篇博客講解了struts1框架,所以有必要在這里對(duì)他倆進(jìn)行一下對(duì)比(我僅僅總結(jié)了五條我認(rèn)為比較重要的,以后如果發(fā)現(xiàn)其他的在隨時(shí)補(bǔ)充):
在Action實(shí)現(xiàn)類(lèi)方面的對(duì)比(struts1的Action繼承action,struts2實(shí)現(xiàn)接口,也可以不實(shí)現(xiàn),可以定制服務(wù))線(xiàn)程模式方面的對(duì)比(struts1存在線(xiàn)程安全問(wèn)題,struts2不存在)
ServletAPI依賴(lài)方面的對(duì)比(struts1依賴(lài)servletAPI,struts2不是)可測(cè)性方面的對(duì)比(struts1難測(cè)試,依賴(lài)容器,struts2不是)封裝請(qǐng)求參數(shù)的對(duì)比(struts1使用actionform;struts2直接寫(xiě)到action,并且支持pojo對(duì)象)
在上篇博客中介紹了struts2框架的原理和流程分析,可以說(shuō)struts框架一路走來(lái),改變非常大,而且讓我們開(kāi)發(fā)人員變得更加輕松,里面的設(shè)計(jì)理念的改變也是讓我們編程人員的思路得到更大的擴(kuò)展。
可以說(shuō),一個(gè)先進(jìn)的技術(shù)或者框架就是要不斷的進(jìn)步才能永遠(yuǎn)讓編程人員喜歡和使用,一個(gè)優(yōu)秀的編程人員也是要不斷的進(jìn)步才能永遠(yuǎn)讓這個(gè)世界變得更加絢麗多彩。
其實(shí)編程就是這樣有意思的!
前面說(shuō)了一些宏觀上學(xué)習(xí)框架相關(guān)的思想方面的東西,下面繼續(xù)來(lái)介紹我經(jīng)常使用的框架和框架的分析,這篇博客主要介紹的是hibernate框架。
首先說(shuō)hibernate框架是數(shù)據(jù)持久層的框架,這個(gè)框架是非常強(qiáng)大的,它讓編程人員純粹的用面向?qū)ο蟮姆绞絹?lái)做開(kāi)發(fā),讓編程人員所面對(duì)的都是對(duì)象。僅僅從這一點(diǎn)它的設(shè)計(jì)思路就是非常讓編程人員喜愛(ài)的。
回想我們普通的開(kāi)發(fā)流程,和客戶(hù)溝通定需求,抽象出來(lái)原型,從原型中建立數(shù)據(jù)模型到庫(kù)表結(jié)構(gòu)的建立,之后在映射成對(duì)象模型,之后在用oo的設(shè)計(jì)思想完成后續(xù)的程序開(kāi)發(fā)。但是當(dāng)我們使用了hibernate框架以后,原先的設(shè)計(jì)思路就顯得不再那么具有優(yōu)勢(shì)了。我們直接建立對(duì)象模型,之后利用hibernate框架映射成數(shù)據(jù)模型,我們不再去考慮數(shù)據(jù)庫(kù)關(guān)系模型的東西,僅僅考慮的東西僅僅就是類(lèi)和對(duì)象,這樣的開(kāi)發(fā)才是面向?qū)ο蟮拈_(kāi)發(fā),也才是最接近人類(lèi)思考問(wèn)題的方式。所以hibernate框架的設(shè)計(jì)思路是非常好的。
hibernate框架設(shè)計(jì)思路的優(yōu)越性其實(shí)體現(xiàn)在了它本身的框架的原理上。hibernate封裝了JDBC,減輕了開(kāi)發(fā)人員在持久層的大量重復(fù)性工作,它利用了java反射機(jī)制來(lái)實(shí)現(xiàn)程序的透明性;它就是通過(guò)這兩點(diǎn)才達(dá)到從對(duì)象出發(fā)而非關(guān)系數(shù)據(jù)庫(kù)出發(fā)的效果。
介紹這么多理論性的東西之后我們能夠感覺(jué)到hibernate框架的強(qiáng)大,來(lái)看看它的結(jié)構(gòu)圖:
在hibernate框架中有幾個(gè)比較重要的接口和類(lèi):Query接口:Query負(fù)責(zé)執(zhí)行各種數(shù)據(jù)庫(kù)查詢(xún)。它可以使用HQL語(yǔ)句或SQL語(yǔ)句兩種表達(dá)方式。Configuration類(lèi):Configuration類(lèi)負(fù)責(zé)配置并啟動(dòng)Hibernate,創(chuàng)建SessionFactory對(duì)象SessionFactory接口:SessionFactory接口負(fù)責(zé)初始化Hibernate。它充當(dāng)數(shù)據(jù)存儲(chǔ)源的代理,并負(fù)責(zé)創(chuàng)建Session對(duì)象Session接口:Session接口負(fù)責(zé)執(zhí)行被持久化對(duì)象的CRUD操作Transaction接口:Transaction接口負(fù)責(zé)事務(wù)相關(guān)的操作
hibernate框架就是在利用這幾個(gè)接口來(lái)封裝了JDBC,而且我們用這些接口來(lái)操作數(shù)據(jù)庫(kù)變得非常簡(jiǎn)單,減少了我們?cè)诔志脤拥拇a量。
從這個(gè)結(jié)構(gòu)圖和我的一些分析就能發(fā)現(xiàn)hibernate框架是非常強(qiáng)大,而且它給我們開(kāi)發(fā)人員的開(kāi)發(fā)帶來(lái)了非常大的便利,尤其是他的設(shè)計(jì)思路還有它的“全自動(dòng)”的映射對(duì)象模型和關(guān)系模型。
但是hibernate框架也有它的一些缺點(diǎn):既然是封裝了JDBC,所以很明顯它沒(méi)有JDBC的效率高,尤其是在大量的處理表更新操作的時(shí)候。它有局限性,一個(gè)持久化類(lèi)不能映射多個(gè)表它應(yīng)對(duì)大數(shù)量的時(shí)候顯得非常笨拙,這一點(diǎn)沒(méi)有JDBC和接下來(lái)要介紹的IBatis框架
其實(shí)一項(xiàng)技術(shù)或者一個(gè)框架都有它的優(yōu)缺點(diǎn),選擇最合適的才是王道。
這篇博客主要是介紹了hibernate框架的結(jié)構(gòu)和分析,闡述了hibernate框架的優(yōu)缺點(diǎn),【具體詳細(xì)使用要等到我的框架學(xué)習(xí)的后續(xù)文章】??偟膩?lái)說(shuō)hibernate框架在持久層的作用非常明顯,我們懂得了它的優(yōu)缺點(diǎn)之后,才能做到我們是否是要選擇這個(gè)框架作為我們持久層開(kāi)發(fā)的必須的技術(shù)支撐,所以這些我常用的框架結(jié)構(gòu)和分析不單單是在介紹一些框架學(xué)習(xí)的宏觀知識(shí)把控,更多的是在為將來(lái)做項(xiàng)目開(kāi)發(fā)中選擇合適的技術(shù)支撐做鋪墊。
后續(xù)的博客在不斷更新,希望這些博客能夠?qū)ψx者的開(kāi)發(fā)過(guò)程帶來(lái)幫助,當(dāng)然如果讀者對(duì)我的博客有什么好的建議或者意見(jiàn),請(qǐng)與我聯(lián)系。聯(lián)系方式見(jiàn)博客側(cè)邊欄!
先看MVC模式流程圖(其實(shí)MVC設(shè)計(jì)模式就是java中的model2。):
就像圖上所標(biāo)識(shí)的C層主要是Servlet層控制頁(yè)面跳轉(zhuǎn),M層就是具體的業(yè)務(wù)處理邏輯,而JSP就是所謂的V層。MVC是有別于我們所說(shuō)的三層,我們平常所說(shuō)的三層是UI層、BLL層、DAL層,具體的區(qū)別如圖:
從圖上能看出來(lái),JSP和Servlet構(gòu)成了UI層,而Model層分成了BLL層和DAL層(也就是業(yè)務(wù)邏輯和數(shù)據(jù)持久層)。
從理論上認(rèn)清了MVC設(shè)計(jì)模式之后,下面開(kāi)始動(dòng)手敲一個(gè)MVC設(shè)計(jì)模式示例代碼:
JSP索引頁(yè)面index.jsp:
[html]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?<%@
page
language="java"
contentType="text/html;
charset=GB18030"
pageEncoding="GB18030"%>
<!DOCTYPE
html
PUBLIC
"-//W3C//DTD
HTML
4.01
Transitional//EN"
"/TR/html4/loose.dtd">
<html>
<head>
<meta
http-equiv="Content-Type"
content="text/html;
charset=GB18030">
<title>Insert
title
here</title>
</head>
<body>
<form
action="servlet/addUser.action"
method="post">
姓名:<input
type="text"
name="username"
>
<input
type="submit"
value="提交">
</form>
</body>
</html>
業(yè)務(wù)邏輯代碼UserManager:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.util.ArrayList;
import
java.util.List;
public
class
UserManager
{
public
void
addUser(String
username){
System.out.println("UserManager.addUsre()>username:"+username);
}
public
void
delUser(String
username){
System.out.println("UserManager.delUser()>username:"+username);
}
public
void
modifyUser(String
username){
System.out.println("UserManager.modifyUser()>username"+username);
}
public
List
queryUser(String
username){
System.out.println("UserManager.queryUser()>username"+username);
List
userList=new
ArrayList();
userList.add("a");
userList.add("b");
userList.add("c");
return
userList;
}
}
Servlet控制代碼:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.io.IOException;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
TestServlet
extends
HttpServlet
{
protected
void
doGet(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException,
IOException
{
String
requestURI=request.getRequestURI();
System.out.println("request="+requestURI);
String
path=requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));
System.out.println("path="+path);
String
username=request.getParameter("username");
UserManager
userManager=new
UserManager();
//userManager.addUser(username);
String
forward="";
if("/servlet/delUser".equals(path)){
userManager.delUser(username);
forward="/del_success.jsp";
}else
if("/servlet/addUser".equals(path)){
userManager.addUser(username);
forward="/add_success.jsp";
}else
if("/servlet/modifyUser".equals(path)){
userManager.modifyUser(username);
forward="/modify_success.jsp";
}else
if("/servlet/queryUser".equals(path)){
List
userList=userManager.queryUser(username);
request.setAttribute("userList",
userList);
forward="/query_success.jsp";
}else{
throw
new
RuntimeException("請(qǐng)求失敗");
}
request.getRequestDispatcher(forward).forward(request,
response);
}
這個(gè)servlet代碼主要實(shí)現(xiàn)的功能判斷是那個(gè)頁(yè)面請(qǐng)求服務(wù)器做那些操作,之后調(diào)用業(yè)務(wù)邏輯實(shí)現(xiàn)相應(yīng)業(yè)務(wù)操作。
配置Servlet:
[html]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?<?xml
version="1.0"
encoding="UTF-8"?>
<web-app
xmlns:xsi="/2001/XMLSchema-instance"
xmlns="/xml/ns/javaee"
xmlns:web="/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="/xml/ns/javaee
/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID"
version="3.0">
<display-name>test_Servlet</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>TestServlet</servlet-name>
<servlet-class>com.cjq.servlet.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TestServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
輸出結(jié)果:
通過(guò)上面的示例已經(jīng)對(duì)MVC設(shè)計(jì)模式有了初步的認(rèn)識(shí),其實(shí)這個(gè)示例是對(duì)Struts框架學(xué)習(xí)的基礎(chǔ),只有弄清楚了這個(gè)實(shí)例才能弄清楚Struts框架的實(shí)現(xiàn)原理和Struts框架使用。
那么我們?cè)趺床拍芡ㄟ^(guò)這個(gè)示例引入Struts框架呢?這個(gè)問(wèn)題從IF-Eles開(kāi)始。
首先我們看到了TestServlet中出現(xiàn)了許多if-else語(yǔ)句,這樣是非常不穩(wěn)定的,這樣的程序是非常不靈活的,以后如果有變化,那么維護(hù)是非常差的;而且我們?cè)趇f-else中出現(xiàn)了大量的字符串,這樣在coding的時(shí)候會(huì)出現(xiàn)寫(xiě)錯(cuò),這樣無(wú)形中給調(diào)試帶來(lái)了麻煩。所以去掉if-else成了我們重構(gòu)的第一步,也是我們進(jìn)行Struts框架學(xué)習(xí)的第一步。
如何才能去掉If-ELSE呢?請(qǐng)看下一篇文章《深入淺出學(xué)習(xí)Struts1框架(二):重構(gòu)MVC模式代碼中跳轉(zhuǎn)路徑和業(yè)務(wù)邏輯》。
在上篇博文《深入淺出學(xué)習(xí)Struts1框架(一):一個(gè)簡(jiǎn)單mvc模式代碼示例開(kāi)始》中簡(jiǎn)單說(shuō)了一下MVC模式代碼的實(shí)現(xiàn)和MVC模式和三層架構(gòu)的區(qū)別,并且留下一個(gè)問(wèn)題—如何去掉TestServlet中的IF-Else語(yǔ)句塊。
因?yàn)樵赥estServlet中出現(xiàn)了If-Else語(yǔ)句塊,所以讓程序變得不再靈活,讓?xiě)?yīng)付需求變化時(shí)變得笨拙。所以就承接上篇文章來(lái)重構(gòu)一下TestServlet代碼,主要是用繼承多肽來(lái)進(jìn)一步對(duì)TestServlet進(jìn)行重構(gòu)。雖然這一篇文章最后沒(méi)有將if-else徹底去掉,但是比起上篇文章的代碼顯得更加靈活,也為下一篇徹底去掉If-else埋下伏筆。
下面進(jìn)入重構(gòu)階段:
先看一下上篇文章的TestServlet代碼:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.io.IOException;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
TestServlet
extends
HttpServlet
{
protected
void
doGet(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException,
IOException
{
String
requestURI=request.getRequestURI();
System.out.println("request="+requestURI);
String
path=requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));
System.out.println("path="+path);
String
username=request.getParameter("username");
UserManager
userManager=new
UserManager();
//userManager.addUser(username);
String
forward="";
if("/servlet/delUser".equals(path)){
userManager.delUser(username);
forward="/del_success.jsp";
}else
if("/servlet/addUser".equals(path)){
userManager.addUser(username);
forward="/add_success.jsp";
}else
if("/servlet/modifyUser".equals(path)){
userManager.modifyUser(username);
forward="/modify_success.jsp";
}else
if("/servlet/queryUser".equals(path)){
List
userList=userManager.queryUser(username);
request.setAttribute("userList",
userList);
forward="/query_success.jsp";
}else{
throw
new
RuntimeException("請(qǐng)求失敗");
}
request.getRequestDispatcher(forward).forward(request,
response);
}
}
首先我們看到了在每個(gè)語(yǔ)句塊中都出現(xiàn)了給forward賦值,其實(shí)也就是給頁(yè)面跳轉(zhuǎn)的路徑賦值,針對(duì)每個(gè)請(qǐng)求路徑判斷來(lái)賦值跳轉(zhuǎn)路徑。另外每個(gè)IF-Else語(yǔ)句塊中都有業(yè)務(wù)處理,我們要把這些業(yè)務(wù)處理分別放到類(lèi)里面,讓職責(zé)更加單一,這樣更加符合面向?qū)ο蟮乃悸贰?/p>
就從這里我們開(kāi)始重構(gòu),我們可以將這個(gè)跳轉(zhuǎn)路徑和業(yè)務(wù)邏輯封裝起來(lái)。
既然封裝,那么我們就抽象出來(lái)一個(gè)借口,主要完成一個(gè)方法,這個(gè)方法主要的功能就是要完成業(yè)務(wù)邏輯封裝和路徑跳轉(zhuǎn)的返回。隨后建立四個(gè)類(lèi),主要實(shí)現(xiàn)相應(yīng)的增刪改查的業(yè)務(wù)處理和處理之后的跳轉(zhuǎn)路徑返回。
代碼如下:
接口Action:[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
interface
Action
{
public
String
execute(HttpServletRequest
request,HttpServletResponse
response)
throws
Exception;
}
增刪改查實(shí)現(xiàn)類(lèi):
添加用戶(hù)實(shí)現(xiàn)類(lèi):[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?<pre
name="code"
class="java">package
com.cjq.servlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
AddUserAction
implements
Action
{
public
String
execute(HttpServletRequest
request,
HttpServletResponse
response)
throws
Exception
{
String
username=request.getParameter("username");
UserManager
userManager=new
UserManager();
userManager.addUser(username);
return
"/add_success.jsp";
}
}</pre><br><br>
刪除用戶(hù)實(shí)現(xiàn)類(lèi):[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
DelUserAction
implements
Action
{
public
String
execute(HttpServletRequest
request,
HttpServletResponse
response)
throws
Exception
{
String
username=request.getParameter("username");
UserManager
userManager=new
UserManager();
userManager.delUser(username);
return
"/del_success.jsp";
}
}
更新用戶(hù)實(shí)現(xiàn)類(lèi):[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
ModifyUserAction
implements
Action
{
@Override
public
String
execute(HttpServletRequest
request,
HttpServletResponse
response)
throws
Exception
{
String
username=request.getParameter("username");
UserManager
userManager=new
UserManager();
userManager.modifyUser(username);
return
"/modify_success.jsp";
}
}
查詢(xún)用戶(hù)實(shí)現(xiàn)類(lèi):[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.util.List;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
QueryUserAction
implements
Action
{
@Override
public
String
execute(HttpServletRequest
request,
HttpServletResponse
response)
throws
Exception
{
String
username=request.getParameter("username");
UserManager
userManager=new
UserManager();
List
userList=userManager.queryUser(username);
request.setAttribute("userList",
userList);
return
"/query_success.jsp";
}
}
TestServlet類(lèi)重構(gòu)如下:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.io.IOException;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
TestServlet
extends
HttpServlet
{
protected
void
doGet(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException,
IOException
{
String
requestURI=request.getRequestURI();
System.out.println("request="+requestURI);
String
path=requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));
System.out.println("path="+path);
Action
action=null;
if("/servlet/delUser".equals(path)){
action=new
DelUserAction();
}else
if("/servlet/addUser".equals(path)){
action=new
AddUserAction();
}else
if("/servlet/modifyUser".equals(path)){
action=new
ModifyUserAction();
}else
if("/servlet/queryUser".equals(path)){
action=new
QueryUserAction();
}else{
throw
new
RuntimeException("請(qǐng)求失敗");
}
String
forward=null;
try{
forward=action.execute(request,
response);
}catch(Exception
e){
e.printStackTrace();
}
request.getRequestDispatcher(forward).forward(request,
response);
}
}
運(yùn)行結(jié)果:
這樣TestServlet類(lèi)雖然沒(méi)有徹底去掉If-Else,但是這樣的代碼變得更加簡(jiǎn)練,利用多肽實(shí)現(xiàn)業(yè)務(wù)邏輯處理和路徑跳轉(zhuǎn)返回。職責(zé)更加清晰,讓維護(hù)變得更加輕松。
問(wèn)題遺留:
If-else語(yǔ)句塊沒(méi)有徹底剔除,而且程序中依舊出現(xiàn)了過(guò)多的字符串,所以程序依舊是不靈活,而且字符串過(guò)多增加調(diào)試的復(fù)雜性。所以下一篇文章就把if-else語(yǔ)句塊剔除,并且把字符串放到配置文件來(lái)用dom4j來(lái)動(dòng)態(tài)讀取。
我們離Struts框架越來(lái)越近,當(dāng)我們把if-else和字符串剔除之后就會(huì)出現(xiàn)Struts框架的雛形。期待下一篇文章。
在《深入淺出學(xué)習(xí)Struts1框架(一):一個(gè)簡(jiǎn)單mvc模式代碼示例開(kāi)始》和《深入淺出學(xué)習(xí)Struts1框架(二):重構(gòu)MVC模式代碼中跳轉(zhuǎn)路徑和業(yè)務(wù)邏輯》文章中已經(jīng)說(shuō)了分層和mvc模式的區(qū)別,和一些為了去掉mvc模式代碼中的TestServlet類(lèi)中的if-else。因?yàn)閕f-else在程序代碼中是相對(duì)不穩(wěn)定的,所以通過(guò)去掉if-else來(lái)引入對(duì)struts框架的學(xué)習(xí)。
在《深入淺出學(xué)習(xí)Struts1框架(二):重構(gòu)MVC模式代碼中跳轉(zhuǎn)路徑和業(yè)務(wù)邏輯》中我們已經(jīng)抽象出來(lái)了一個(gè)接口和四個(gè)實(shí)現(xiàn)類(lèi),主要封裝了業(yè)務(wù)處理和頁(yè)面跳轉(zhuǎn)路徑字符串放回,以便利用多肽來(lái)重構(gòu)了TestServlet代碼(具體見(jiàn)博客)。
在上兩篇博客我們遺留了兩個(gè)問(wèn)題,一是if-else,二是字符串太多。今天這篇博客就要解決這兩個(gè)問(wèn)題。
上一篇TestServlet重構(gòu)后的代碼:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.io.IOException;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
TestServlet
extends
HttpServlet
{
protected
void
doGet(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException,
IOException
{
String
requestURI=request.getRequestURI();
System.out.println("request="+requestURI);
String
path=requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));
System.out.println("path="+path);
Action
action=null;
if("/servlet/delUser".equals(path)){
action=new
DelUserAction();
}else
if("/servlet/addUser".equals(path)){
action=new
AddUserAction();
}else
if("/servlet/modifyUser".equals(path)){
action=new
ModifyUserAction();
}else
if("/servlet/queryUser".equals(path)){
action=new
QueryUserAction();
}else{
throw
new
RuntimeException("請(qǐng)求失敗");
}
String
forward=null;
try{
forward=action.execute(request,
response);
}catch(Exception
e){
e.printStackTrace();
}
request.getRequestDispatcher(forward).forward(request,
response);
}
}
解決字符串問(wèn)題,當(dāng)然就要用到配置文件了,用到配置文件就要有用來(lái)讀取配置文件的相關(guān)的類(lèi)和方法,這里就用dom4j中的類(lèi)來(lái)讀取配置文件,這里的配置文件的書(shū)寫(xiě)是有點(diǎn)邏輯上的難度的。
我們來(lái)看TestServlet中的代碼,我們要在這個(gè)testservlet中實(shí)現(xiàn)讀取配置文件和path比較,還有利用多肽實(shí)例化相應(yīng)的實(shí)現(xiàn)類(lèi),最后通過(guò)實(shí)例化的實(shí)現(xiàn)類(lèi)的方法來(lái)返回跳轉(zhuǎn)路徑,最終跳轉(zhuǎn)到相應(yīng)的頁(yè)面。
所以我們的配置文件就要不僅配上testservlet中出現(xiàn)的字符串,還要配置相應(yīng)的Action接口的實(shí)現(xiàn)類(lèi)(我們可以利用反射來(lái)實(shí)例化該類(lèi)的對(duì)象,進(jìn)而使用這個(gè)類(lèi)的所有屬性和方法),另外還有跳轉(zhuǎn)路徑字符串。這樣我們的配置文件就變成了如下代碼所示:[html]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?<?xml
version="1.0"
encoding="UTF-8"?>
<action-config>
<action
path="/servlet/delUser"
type="com.cjq.servlet.DelUserAction">
<forward
name="success">/del_success.jsp</forward>
<forward
name="error">/del_error.jsp</forward>
</action>
<action
path="/servlet/addUser"
type="com.cjq.servlet.AddUserAction">
<forward
name="success">/add_success.jsp</forward>
<forward
name="error">/add_error.jsp</forward>
</action>
<action
path="/servlet/modifyUser"
type="com.cjq.servlet.ModifyUserAction">
<forward
name="success">/modify_success.jsp</forward>
<forward
name="error">/modify_error.jsp</forward>
</action>
<action
path="/servlet/queryUser"
type="com.cjq.servlet.QueryUserAction">
<forward
name="success">/query_success.jsp</forward>
<forward
name="error">/query_error.jsp</forward>
</action>
</action-config>
我們有了配置文件之后就要想法通過(guò)相關(guān)類(lèi)讀取,并且實(shí)現(xiàn)相應(yīng)的功能。所以這里用dom4j來(lái)讀取完成。其實(shí)如果能把這個(gè)邏輯捋順之后就能發(fā)現(xiàn),其實(shí)懂我們利用dom4j讀取完配置文件的時(shí)候,我們是取得的是一個(gè)配套的匹配路徑字符串、相應(yīng)業(yè)務(wù)邏輯類(lèi)還有處理業(yè)務(wù)邏輯之后跳轉(zhuǎn)頁(yè)面路徑字符串。這樣我們就能直截了當(dāng)?shù)娜サ袅薸f-else。(這里可能邏輯上會(huì)出現(xiàn)一些困難,但是看到下面的重構(gòu)之后的testservlet中的代碼和讀取配置文件之后的代碼就會(huì)一目了然)。
現(xiàn)在等待解決的問(wèn)題就是我們要把從配置文件取得的一整套內(nèi)容放到那里,當(dāng)然這是毋庸置疑的要放到類(lèi)中。所以我們就建立一個(gè)ActionMapping類(lèi)來(lái)放我們的那一整套內(nèi)容。
ActionMapping中的代碼如下:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.util.Map;
public
class
ActionMapping
{
private
String
path;
private
Object
type;
private
Map
forwardMap;
public
String
getPath()
{
return
path;
}
public
void
setPath(String
path)
{
this.path
=
path;
}
public
Object
getType()
{
return
type;
}
public
void
setType(Object
type)
{
this.type
=
type;
}
public
Map
getForwardMap()
{
return
forwardMap;
}
public
void
setForwardMap(Map
forwardMap)
{
this.forwardMap
=
forwardMap;
}
}
現(xiàn)在ActionMapping類(lèi)已經(jīng)有了,剩下的工作就是要利用dom4j來(lái)讀取配置文件類(lèi),具體代碼如下:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.io.InputStream;
import
java.util.HashMap;
import
java.util.Iterator;
import
java.util.Map;
import
org.dom4j.Document;
import
org.dom4j.DocumentException;
import
org.dom4j.Element;
import
org.dom4j.io.SAXReader;
public
class
XmlConfigReader
{
private
static
XmlConfigReader
instance=new
XmlConfigReader();
ActionMapping
actionMapping=new
ActionMapping();
private
Document
doc;
private
Map
actionMap=new
HashMap();
private
XmlConfigReader(){
try
{
SAXReader
reader=new
SAXReader();
InputStream
in=Thread.currentThread().getContextClassLoader().getResourceAsStream("action_config.xml");
doc=reader.read(in);
}
catch
(DocumentException
e)
{
//
TODO
Auto-generated
catch
block
e.printStackTrace();
}
}
public
ActionMapping
getActionMapping(String
path){
synchronized(this){
Object
type=null;
/*if(action.containsKey(path)){
type=action.get(path);
}*/
Element
eltAction
=
(Element)doc.selectObject("http://action[@path=\""
+
path
+
"\"]");
try{
type=Class.forName(eltAction.attributeValue("type")).newInstance();
}catch(Exception
e){
e.printStackTrace();
}
Element
eltForwards
=
eltAction.element("forward");
for
(Iterator
iter
=
eltForwards.elementIterator();
iter.hasNext();)
{
Element
eltForward
=
(Element)
iter.next();
actionMap.put(
eltForward.attributeValue("name"),eltForward.getTextTrim());
}
actionMapping.setPath(path);
actionMapping.setType(type);
actionMapping.setForwardMap(actionMap);
return
actionMapping;
}
}
public
static
synchronized
XmlConfigReader
getInstance(){
return
instance;
}
/**
*
@param
args
*/
public
static
void
main(String[]
args)
{
//
TODO
Auto-generated
method
stub
ActionMapping
actionMapping=XmlConfigReader.getInstance().getActionMapping("/servlet/delUser");
System.out.println(actionMapping.getPath());
System.out.println(actionMapping.getType());
System.out.println(actionMapping.getForwardMap().toString());
}
}
我們通過(guò)返回ActionMapping來(lái)動(dòng)態(tài)創(chuàng)建出action相應(yīng)的實(shí)現(xiàn)類(lèi),進(jìn)而完成業(yè)務(wù)邏輯和頁(yè)面跳轉(zhuǎn),重構(gòu)之后的TestServlet代碼如下:
[java]
\o"viewplain"viewplain
\o"copy"copy
\o"print"print\o"?"?package
com.cjq.servlet;
import
java.io.IOException;
import
java.util.List;
import
javax.servlet.ServletException;
import
javax.servlet.http.HttpServlet;
import
javax.servlet.http.HttpServletRequest;
import
javax.servlet.http.HttpServletResponse;
public
class
TestServlet
extends
HttpServlet
{
protected
void
doGet(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException,
IOException
{
String
requestURI=request.getRequestURI();
System.out.println("request="+requestURI);
String
path=requestURI.substring(requestURI.indexOf("/",1),requestURI.indexOf("."));
System.out.println("path="+path);
String
forward="";
ActionMapping
actionMapping=XmlConfigReader.getInstance().getActionMapping(path);
Action
action=(Action)actionMapping.getType();
try
{
forward=action.execute(request,
response);
}
catch
(Exception
e)
{
//
TODO
Auto-generated
catch
block
e.printStackTrace();
}
request.getRequestDispatcher(forward).forward(request,
response);
}
protected
void
doPost(HttpServletRequest
request,
HttpServletResponse
response)
throws
ServletException,
IOException
{
doGet(request,response);
}
}
我們可以清晰的看到if-else已經(jīng)沒(méi)有了,字符串也已經(jīng)沒(méi)有了。通過(guò)這篇文章對(duì)if-else還有字符串問(wèn)題的解決,又一次重構(gòu)了testservlet代碼,程序相對(duì)靈活許多。通過(guò)這一次的重構(gòu),我們已經(jīng)看到了struts框架的雛形,下一篇文章就真正開(kāi)始了struts框架的學(xué)習(xí)。
下一篇引子:
其實(shí)框架就是對(duì)程序的高度封裝,我們經(jīng)歷了這三篇文章之后,一步一步重構(gòu),一步一步封裝,逐步向框架靠攏,其實(shí)框架沒(méi)有什么難的,其實(shí)沒(méi)有學(xué)習(xí)框架之前感覺(jué)挺神秘,其實(shí)如果一步一步來(lái)研究之后發(fā)現(xiàn)框架就是封裝的高度化,分層的高度化。
下一篇文章《深入淺出學(xué)習(xí)struts1框架(四):從MVC模式代碼認(rèn)識(shí)struts框架》就借助剛剛完成的實(shí)例來(lái)簡(jiǎn)單認(rèn)識(shí)struts框架,看看真正的struts框架和我們這個(gè)mvc小實(shí)例有什么相同和相異之處?!渡钊霚\出學(xué)習(xí)Struts1框架(一):一個(gè)簡(jiǎn)單mvc模式代碼示例開(kāi)始》分析mvc和三層關(guān)系開(kāi)始,引出這個(gè)mvc設(shè)計(jì)模式實(shí)例,到《深入淺出學(xué)習(xí)Struts1框架(二):重構(gòu)MVC模式代碼中跳轉(zhuǎn)路徑和業(yè)務(wù)邏輯》抽象封裝業(yè)務(wù)處理和路徑跳轉(zhuǎn),再到《深入淺出學(xué)習(xí)Struts1框架(三):徹底去掉TestServlet中的字符串和if-else語(yǔ)句塊》去掉if-else語(yǔ)句塊和字符串,經(jīng)過(guò)三篇文章循序漸進(jìn)的重構(gòu)了一個(gè)mvc設(shè)計(jì)模式實(shí)例,其實(shí)也就是重構(gòu)出來(lái)了一個(gè)struts框架雛形。今天來(lái)看看什么是struts1框架。1.
框架
框架(Framework)是整個(gè)或部分系統(tǒng)的可重用設(shè)計(jì),表現(xiàn)為一組抽象構(gòu)件及構(gòu)件實(shí)例間交互的方法。也就是說(shuō)框架是一個(gè)半成品的應(yīng)用程序。我們所面對(duì)的應(yīng)用程序一般都是分為兩部分,一部分是業(yè)務(wù)相關(guān)的組件部分,另一部分是和業(yè)務(wù)無(wú)關(guān)的組件部分。而我們知道和業(yè)務(wù)相關(guān)的組件部分的重用性是非常低的,這也是顯而易見(jiàn)的事情;而和業(yè)務(wù)無(wú)關(guān)的組件部分,如驗(yàn)證、異常、程序流程控制等等服務(wù)組件的復(fù)用性是非常高的。所以當(dāng)人們?cè)诓煌膽?yīng)用程序中抽出共性的組件,構(gòu)成一個(gè)半成品應(yīng)用程序,這時(shí)候框架就應(yīng)運(yùn)而生了。2.
Struts1
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 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ì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 智能城市管理與服務(wù)作業(yè)指導(dǎo)書(shū)
- IT領(lǐng)域云服務(wù)平臺(tái)架構(gòu)規(guī)劃與建設(shè)方案
- 軟件測(cè)試技術(shù)及實(shí)施流程作業(yè)指導(dǎo)書(shū)
- 綠色農(nóng)業(yè)發(fā)展作業(yè)指導(dǎo)書(shū)
- 工程居間合同
- 能源化工行業(yè)項(xiàng)目管理作業(yè)指導(dǎo)書(shū)
- 2025年??谪涍\(yùn)從業(yè)資格證年考試題及答案
- 2025年酒泉普通貨運(yùn)從業(yè)資格證考試
- 2024-2025學(xué)年高中地理第四單元從人地關(guān)系看資源與環(huán)境單元活動(dòng)4遙感技術(shù)及其應(yīng)用練習(xí)含解析魯教版必修1
- 景觀設(shè)計(jì)師年終總結(jié)
- 小學(xué)班會(huì)-交通安全伴我行(共25張課件)
- 消防安全一懂三會(huì)四能
- 起重吊裝工程安全監(jiān)理細(xì)則模版(3篇)
- 《VAVE價(jià)值工程》課件
- 四川政采評(píng)審專(zhuān)家入庫(kù)考試基礎(chǔ)題復(fù)習(xí)試題及答案(一)
- 分享二手房中介公司的薪酬獎(jiǎng)勵(lì)制度
- 安徽省2022年中考道德與法治真題試卷(含答案)
- GB 4793-2024測(cè)量、控制和實(shí)驗(yàn)室用電氣設(shè)備安全技術(shù)規(guī)范
- 廣電雙向網(wǎng)改造技術(shù)建議書(shū)
- 項(xiàng)目人員管理方案
- 重大火災(zāi)隱患判定方法
評(píng)論
0/150
提交評(píng)論