[1]
此文檔講述的內(nèi)容適合于對(duì)
Spring MVC
和數(shù)據(jù)持久層
ORM
概念有一定基礎(chǔ)的開發(fā)者,著重于講述基于
Spring
框架基礎(chǔ)之上進(jìn)行
Java
開發(fā)的其中一種技術(shù)解決方案,而不是講述相關(guān)技術(shù)的原理,想要了解技術(shù)原理內(nèi)容請(qǐng)參考相關(guān)文檔資料。
?
現(xiàn)在,網(wǎng)絡(luò)上流傳的Spring+Struts+Hibernate用得非常火,幾乎成為很多對(duì)技術(shù)癡迷的人的技術(shù)架構(gòu)標(biāo)準(zhǔn),可是在我看來,也許是因?yàn)轫?xiàng)目都不算大,人力也不夠多,這個(gè)技術(shù)架構(gòu)太復(fù)雜了。從Spring本身來講,從MVC到數(shù)據(jù)操作,都可以不需要其他附加組件即可實(shí)現(xiàn),并且結(jié)構(gòu)清晰,使用簡(jiǎn)單,功能還更加強(qiáng)大,本文講述的重點(diǎn)就是單獨(dú)使用Spring來建立一個(gè)簡(jiǎn)易的開發(fā)框架。
?
首先說,為什么選擇Spring呢?大概在2003年的時(shí)候,Struts已經(jīng)開始流行了,但是在學(xué)習(xí)Struts的時(shí)候感覺這個(gè)技術(shù)框架比原始的JSP+JavaBean的方式復(fù)雜了很多,后來2004年做新項(xiàng)目時(shí)在論壇上看到推薦Spring,下載一試,上手非常的容易,結(jié)構(gòu)也很清晰,支持的功能也非常多,所以決定用它了(其實(shí)那時(shí)候?qū)τ谝蕾囎⑷牒?/span>AOP代理還不甚了解,也很少用到接口)。
在2001-2003年的時(shí)候都是自己封裝了JavaBean做為公共模塊來訪問數(shù)據(jù)庫的,后來ORM興起了,先是看了Hibernate的,3.0版還沒用出,還不支持存儲(chǔ)過程,因?yàn)槟菚r(shí)候也做Delphi相關(guān)開發(fā),用慣了SQL語句,始終覺得HQL這樣的東東增加了開發(fā)的復(fù)雜度和不可控制性,原生的復(fù)雜SQL語句無法使用,不喜歡。后來看到了iBATIS,經(jīng)過試用,正是我所需要的,SQL語句配置簡(jiǎn)單,基本不會(huì)破壞SQL語句的結(jié)構(gòu),這樣將SQL語句Copy到外部數(shù)據(jù)庫工具中進(jìn)行調(diào)試也非常的方便,加上SQL語句可以使用很多的特定數(shù)據(jù)庫的函數(shù),執(zhí)行效率和簡(jiǎn)潔性也非常好,修改了SQL又不需要重新編譯程序。
有網(wǎng)友說Hibernate支持多個(gè)數(shù)據(jù)庫移值啊,我認(rèn)為這個(gè)就不僅僅是SQL語句的問題了,還有很多其他方面的因素,大多數(shù)項(xiàng)目都可以不用考慮。又有網(wǎng)友說Hibernate對(duì)于數(shù)據(jù)庫結(jié)構(gòu)修改的影響比較小,這種情況影響的也不僅僅是幾句代碼的問題,涉及到界面表現(xiàn)、業(yè)務(wù)流程等很多重要方面,相對(duì)說來修改代碼倒是小Case了。
說完了上面的
ORM
組件,再說說
JDBC
,
Spring
的
JdbcTemplate
將我們常用的
JDBC
流程封裝起來,使用非常簡(jiǎn)單,一般執(zhí)行的
SQL
就是一句話,構(gòu)造
SQL
隨著業(yè)務(wù)的復(fù)雜而復(fù)雜,并且也支持
PrepareStatement
的執(zhí)行模式避免
SQL
注入漏洞發(fā)生,同樣具備完整的數(shù)據(jù)操作功能如查詢、更新、存儲(chǔ)過程、異常捕捉等等,經(jīng)過幾年的使用比較,我認(rèn)為輕型的項(xiàng)目使用
JdbcTemplate
是非常不錯(cuò)的選擇。
由于能力所限,其中細(xì)節(jié)如有欠缺之處,請(qǐng)多多批評(píng)指正。
2.
參考資料
2 ?
Spring
官方網(wǎng)站:
http://www.springframework.org/
;
2 ?
Spring 2.0
中文參考手冊(cè):
http://spring.jactiongroup.net/
;
2 ?
Apache Jakarta
官方網(wǎng)站:
http://jakarta.apache.org/
;
2 ?
JSTL
官方網(wǎng)站:
http://java.sun.com/products/jsp/jstl/
;
2 ?
Intellij IDEA
官方網(wǎng)站:
http://www.jetbrains.com/
;
3.
架構(gòu)概覽
MVC
層在
Spring
的
AbstractController
類基礎(chǔ)上進(jìn)行了繼承和重構(gòu),使整個(gè)框架僅使用單一的公共控制器,數(shù)據(jù)操作采用
Spring
JdbcTemplate
,在邏輯層中直接集成了
Spring Jdbc
能力,可直接操作數(shù)據(jù),表現(xiàn)層
Jstl
,除此之外,未定義任何的表單對(duì)象、數(shù)據(jù)庫表映射對(duì)象和其他
ORM
的配置文件,在保留對(duì)關(guān)鍵功能的集成度的基礎(chǔ)上技術(shù)入門度極低,重點(diǎn)關(guān)注業(yè)務(wù)功能和優(yōu)化
SQL
語句
。
請(qǐng)求處理流傳如圖所示:
1)?????
用戶訪問
http://www.fyyk.com/a.do
;
2)?????
Web
應(yīng)用服務(wù)器(如
tomcat
)解析擴(kuò)展名為
*.do
的請(qǐng)求,通過
Spring
分發(fā)器
org.springframework.web.servlet.DispatcherServlet
讀取
servlet-do.xml
中的配置,將請(qǐng)求轉(zhuǎn)發(fā)給公共控制器類
LogicController.java
;
3)?????
公共控制器類
LogicController.java
根據(jù)
servlet-do.xml
文件中的配置信息調(diào)用
DoLogicImpl.java
類中相對(duì)應(yīng)名稱的方法;
4)?????
DoLogicImpl.java
類中的方法在處理完成業(yè)務(wù)邏輯后,將數(shù)據(jù)內(nèi)容
ModelAndView
返回給公共控制器類
LogicController.java
;
5)?????
公共控制器類
LogicController.java
處理
ModelAndView
信息,執(zhí)行
b.jsp
將結(jié)果數(shù)據(jù)顯示出來;
3.1.
控制器
Controller
控制器類配置在
servlet-xxx.xml
文件中,封裝后的
Controller
特點(diǎn)如下:
1)???
繼承
AbstractController
類,便于調(diào)用應(yīng)用環(huán)境的
Web
特性;
2)??
只用控制器做請(qǐng)求的轉(zhuǎn)發(fā),業(yè)務(wù)實(shí)現(xiàn)全部在邏輯層;
3)?????
采用反映射機(jī)制(
reflect
),運(yùn)行期調(diào)用邏輯類中的方法,而請(qǐng)求
URI
、邏輯類和方法名之間的對(duì)應(yīng)關(guān)系只需要在
servlet-xxx.xml
中配置,這樣,控制器實(shí)現(xiàn)就只有唯一的一個(gè)類文件;
3.2.
邏輯層
Logic
邏輯層類在
applicationContext-xxx.xml
文件配置
Bean
定義中,主要實(shí)現(xiàn)兩項(xiàng)功能:一是處理業(yè)務(wù)邏輯,二是操作數(shù)據(jù)庫;
邏輯層類首先需要定義一個(gè)接口類,統(tǒng)一以
xxxLogic.java
命名,實(shí)現(xiàn)類命名為
xxxLogicImpl.java
,并繼承
JdbcDaoSupport
類,這樣邏輯類便具有了數(shù)據(jù)庫訪問能力。
邏輯類的方法如果被公共控制器類
LogicController.java
的反映射機(jī)制直接調(diào)用,則其接口類需要繼承空的公共接口類
BasicLogic
,定義方法時(shí)參數(shù)和返回值是固定的,如果是被其他邏輯類調(diào)用則不需要。
public ModelAndView initLogin(HttpServletRequest request, HttpServletResponse response, ServletContext servletContext);
|
控制器層直接將請(qǐng)求的
request
、
response
和
servletContext
全部傳遞過來交由邏輯層自由控制,對(duì)于
request
中的表單數(shù)據(jù),未采用
SimpleFormController
的模式定義表單對(duì)象,建議手工獲取,從代碼量本身來將并不復(fù)雜,反而更加靈活。在業(yè)務(wù)處理完成后,必須構(gòu)造一個(gè)
ModelAndView
對(duì)象,作為方法返回值回傳給控制器。
范例代碼如下:
public class AdminLogicImpl extends JdbcDaoSupport implements AdminLogic
{
?
public ModelAndView insertUser(HttpServletRequest request, HttpServletResponse response,
??? ServletContext servletContext) throws DataAccessException
??? {
?
????
??String userId = request.getParameter("userId");
?
????
??String userName = request.getParameter("userName");
?
????
??int age = Integer.parseInt(request.getParameter("age"));
?
????
??double weight = Double.parseDouble(request.getParameter("weight"));
?
?
????
??String sqlStr = "insert into testuser (userId,username,age,weight,updatetime) values (?,?,?,?,?)";
??
????
?Object[] object = new Object[]{userId, userName, age, weight, new Date()};
??
????
?getJdbcTemplate().update(sqlStr, object);
?
?
????
?Map<String, Object> model = new HashMap<String, Object>();
??
????
?model.put("msg", "
插入用戶成功!
");
???
????model.put("url", "pageForm.user");
??
????
?String view = "admin/message.jsp";
??
????
?return new ModelAndView(view, model);
??? }
}
|
3.3.
表現(xiàn)層
Jstl
表現(xiàn)層采用
Jstl taglib 1.2
,在
*.jsp
頁面中加入
taglib
引用即可使用
Jstl
標(biāo)簽的大部分功能了,標(biāo)簽的具體使用方法請(qǐng)參考相關(guān)文檔。
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
|
??
Java
編輯器
Intellij IDEA 6.0.5
、
Eclipse WTP 3.2
;
??
JDK5.0 Update 11
;
??
Web
服務(wù)器
Tomcat 5.5.20
;
??
數(shù)據(jù)庫
Oracle10g
;
spring.jar
|
spring 2.0.3
|
jstl.jar
standard.jar
|
Jstl 1.2
|
commons-io-1.3.1.jar
commons-fileupload-1.2.jar
|
文件上傳組件
|
commons-logging-1.1.jar
log4j-1.2.14.jar
|
日志組件
|
mail.jar
activation.jar
|
郵件組件
|
quartz-1.5.2.jar
|
時(shí)序調(diào)度組件
|
aspectjweaver.jar
|
AOP
組件
|
commons-lang-2.3.jar
|
Apache
公共包
|
commons-codec-1.3.jar
commons-collections-3.2.jar
commons-httpclient-3.0.1.jar
|
Httpclient
組件
|
路
?
徑
|
說
?
明
|
/
|
工程根目錄
|
/lib
|
工程所用的庫文件目錄
|
/src
|
源代碼目錄
|
/webapp
|
站點(diǎn)根目錄
|
/webapp/css
|
樣式表目錄
|
/webapp/images
|
圖片目錄
|
/webapp/js
|
Js
腳本目錄
|
/webapp/WEB-INF
|
web.xml
等配置文件所在目錄
|
/webapp/WEB-INF/classes
|
Class
所在目錄
|
/webapp/WEB-INF/jsp
|
Jsp
文件存放目錄
|
/webapp/WEB-INF/lib
|
jar
包目錄
|
/webapp/WEB-INF/logs
|
程序日志目錄
|
/webapp/WEB-INF/temp
|
臨時(shí)文件保存目錄
|
程序文件全部為
UTF-8
字符集,使用開發(fā)工具建立工程時(shí)需要修改工程的默認(rèn)字符集。
在
IDEA
中通過
Ctrl+Alt+S
快捷鍵打開設(shè)置窗口,選擇
IDE Settings
下面的
General
打開通用設(shè)置窗口,修改
File Encoding
下面的
Default encoding
為
UTF-8
,同時(shí)修改
Properties Files
下面的
Default encoding
為
UTF-8
。
在
Eclipse
中點(diǎn)擊菜單
Window-Preferences
打開參數(shù)設(shè)置窗口,選擇左側(cè)樹形節(jié)點(diǎn)
General-Workspace
,修改
Text File Encoding
為
UTF-8
。
如果需要使用已經(jīng)存在的源文件,使用
IDEA
建立同名新文件,然后
copy
原始文件內(nèi)容到新文件中,注意不要直接使用源文件,可能會(huì)產(chǎn)生亂碼問題。
由于數(shù)據(jù)庫連接池組件包使用的是
Tomcat
自帶,所以數(shù)據(jù)庫驅(qū)動(dòng)程序包需要放在
Tomcat
可以訪問的位置,
Oracle
驅(qū)動(dòng)
ojdbc14.jar
文件必須
Copy
到
tomcat/common/lib
這樣的目錄下,而不能放在開發(fā)工具工程
lib
目錄下。
web.xml
采用
servlet2.4
規(guī)范,默認(rèn)配置了會(huì)話過期時(shí)間和網(wǎng)站首頁文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="2.4"
?????? xmlns="http://java.sun.com/xml/ns/j2ee"
?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
?????? xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
?
??? <!--
會(huì)話的時(shí)間
-->
?
??<session-config>
????????????? <session-timeout>30</session-timeout>
?????? </session-config>
?
?????? <!--
歡迎頁面
-->
?????? <welcome-file-list>
????????????? <welcome-file>index.jsp</welcome-file>
?????? </welcome-file-list>
??????
</web-app>
|
在
web.xml
文件中加入如下配置:
<!--
設(shè)置環(huán)境變量,將
web
應(yīng)用根目錄存儲(chǔ)到環(huán)境變量中
-->
<context-param>
??? <param-name>webAppRootKey</param-name>
??? <param-value>webapp.root</param-value>
</context-param>?
?
<!--
設(shè)置環(huán)境變量指定
applicationContext.xml
配置文件
-->
<context-param>
??? <param-name>contextConfigLocation</param-name>
??? <param-value>
??????? /WEB-INF/applicationContext.xml
??????? /WEB-INF/applicationContext-admin.xml
??????? /WEB-INF/applicationContext-quartz.xml
??? </param-value>
</context-param>???
?
<!--
設(shè)置
context
的監(jiān)聽,啟動(dòng)時(shí)加載
applicationContext.xml
文件,初始化
applicationContext
實(shí)例
-->
<listener>
??? <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
|
首先,在
web.xml
文件中加入如下配置:
<!--
設(shè)置環(huán)境變量指定
log4j
的配置文件
-->
<context-param>
??? <param-name>log4jConfigLocation</param-name>
??? <param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
?
<!--
設(shè)置
log4j
的監(jiān)聽,使日志組件能夠使用,調(diào)用
log4jConfigLocation
中設(shè)置的環(huán)境變量
-->
<listener>
??? <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
|
log4j.properties
文件放在
/WEB-INF/
目錄下,
文件內(nèi)容如下例,其中根日志級(jí)別為
warn
,而在包
cn.idtag
中的類的日志級(jí)別為
info
。
#
定義根日志的級(jí)別和輸出路徑
fatal, error, warn, info, debug
log4j.rootCategory=warn, stdout, logfile
?
#
在包
cn.idtag
中的類的日志級(jí)別
log4j.logger.cn.idtag=info
?
#
日志輸出參數(shù)
#%c:
日志信息所在類名
#%d:
日志信息產(chǎn)生時(shí)間
#%p:
日志信息級(jí)別
#%m:
產(chǎn)生的日志具體信息
#%n:
輸出日志信息換行
log4j.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%p] %c%n%m%n%n
?
#
控制臺(tái)輸出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=${log4j.ConversionPattern}
?
#
日志文件輸出
log4j.appender.logfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.logfile.File=${webapp.root}/WEB-INF/logs/log.txt
log4j.appender.logfile.Append = true
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=${log4j.ConversionPattern}
|
在
web.xml
文件中加入如下配置,可以解決表單提交的編碼,不需要在每個(gè)
*.jsp
、
*.htm
等頁面上編寫代碼“
<%@ page contentType="text/html; charset=gbk" language="java"%>
”了,并且為瀏覽器端設(shè)置的“
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
”代碼也不需要寫了,瀏覽器會(huì)自動(dòng)識(shí)別,注意建立文件時(shí)一定要使用
UTF-8
字符集。
<!--
設(shè)置字符串過濾器,解決表單
Post
提交中的亂碼問題
-->
<filter>
??? <filter-name>characterEncoding</filter-name>
??? <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
??? <init-param>
??
?????<param-name>encoding</param-name>
??????? <param-value>utf-8</param-value>
??? </init-param>
??? <init-param>
??????? <param-name>forceEncoding</param-name>
??????? <param-value>true</param-value>
??? </init-param>
</filter>
<filter-mapping>
??? <filter-name>characterEncoding</filter-name>
??? <url-pattern>/*</url-pattern>
</filter-mapping>
?
<!--
設(shè)置
jsp,htm,html
頁面的字符集,是否使用標(biāo)簽,是否使用
jsp
腳本等,頭尾載入頁面等
-->
<jsp-config>
??? <jsp-property-group>
??????? <description>
指定
JSP
文件的配置屬性
</description>
??????? <display-name>jspConfiguration</display-name>
??????? <url-pattern>*.jsp</url-pattern>
??????? <el-ignored>false</el-ignored>
??????? <page-encoding>utf-8</page-encoding>
??????? <scripting-invalid>false</scripting-invalid>
??????? <include-prelude></include-prelude>
??????? <include-coda></include-coda>
??? </jsp-property-group>
?
??? <jsp-property-group>
??????? <description>
指定
htm
文件的配置屬性
</description>
??????? <display-name>jspConfiguration</display-name>
??????? <url-pattern>*.htm</url-pattern>
??????? <el-ignored>false</el-ignored>
??????? <page-encoding>utf-8</page-encoding>
??????? <scripting-invalid>false</scripting-invalid>
??????? <include-prelude></include-prelude>
??????? <include-coda></include-coda>
??? </jsp-property-group>
?
??? <jsp-property-group>
??????? <description>
指定
html
文件的配置屬性
</description>
??????? <display-name>jspConfiguration</display-name>
??????? <url-pattern>*.html</url-pattern>
??????? <el-ignored>false</el-ignored>
??????? <page-encoding>utf-8</page-encoding>
??????? <scripting-invalid>false</scripting-invalid>
??????? <include-prelude></include-prelude>
??????? <include-coda></include-coda>
??? </jsp-property-group>
?
</jsp-config>
|
如果應(yīng)用服務(wù)器是
Tomcat
,編輯
Tomcat
根目錄下的“
/conf/server.xml
”文件,找到
Connector
配置部分,在配置結(jié)尾加入“
URIEncoding="utf-8"
”:
<Connector port="8080" maxThreads="150" …… disableUploadTimeout="true"/>
改為:
<Connector port="8080" maxThreads="150" …… disableUploadTimeout="true" URIEncoding="UTF-8"/>
|
可解決系統(tǒng)內(nèi)部
GET
方法傳遞中文字符參數(shù)的亂碼問題,但是在外部
URL
請(qǐng)求中參數(shù)值帶有中文的,必須使用
URLEncode
編碼。
在
web.xml
文件中配置
servlet
請(qǐng)求路徑和實(shí)現(xiàn)類:
<servlet>
??? <servlet-name>sendSms</servlet-name>
??? <servlet-class>cn.idtag.test.servlet.SendSmsServlet</servlet-class>
</servlet>
<servlet-mapping>
??? <servlet-name>sendSms</servlet-name>
??? <url-pattern>/servlet/sendsms</url-pattern>
</servlet-mapping>
|
而
SendSmsServlet.java
文件需要繼承
HttpServlet
類,如果
response
要輸出內(nèi)容并包含非英文字符,要設(shè)置輸出的字符集為
UTF-8
:
package cn.idtag.test.servlet;
?
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.ServletException;
import java.io.IOException;
?
public class SendSmsServlet extends HttpServlet
{
??? public void doGet(HttpServletRequest request, HttpServletResponse response)
??????????? throws ServletException, IOException
{
??????? response.setContentType("text/html;charset=utf-8");
??????? PrintWriter out = new PrintWriter(new OutputStreamWriter(response.getOutputStream(), "utf-8"));
??????? try
??????? {
??????? //do something…
??????? } finally
??????? {
??????????? out.close();
??????? }
??? }
?
??? public void doPost(HttpServletRequest request, HttpServletResponse response)
??????????? throws ServletException, IOException
??
?{
??????? doGet(request, response);
??? }
}
|
配置
Spring
環(huán)境公共設(shè)置的
applicationContext.xml
文件放在
/WEB-INF/
目錄下,
首先定義視圖類型為
Jstl
,并約定
JSP
文件的默認(rèn)保存路徑,配置異常捕獲處理
Bean
,當(dāng)系統(tǒng)發(fā)生異常時(shí),自動(dòng)重新定向到
error.jsp
文件顯示異常內(nèi)容。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
?????? xmlns:aop="http://www.springframework.org/schema/aop"
?????? xmlns:tx="http://www.springframework.org/schema/tx"
?????? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
?????????? http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
?????????? http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
?
??? <!--
返回的視圖資源的前綴和后綴,基于
Jstl
模板
-->
??? <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
??????? <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
??????
?<property name="prefix" value="/WEB-INF/jsp/"/>
??? </bean>
?
??? <!--
啟動(dòng)加載異常處理的類,用于監(jiān)聽各模塊中觸發(fā)的異常
-->
??? <bean id="exceptionResolver" class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
??????? <property name="defaultErrorView" value="error.jsp"/>
??? </bean>
</beans>
|
在
applicationContext.xml
文件中加入下面配置,首先加載數(shù)據(jù)庫配置文件
jdbc.properties
,然后配置數(shù)據(jù)源,此處使用的是
TOMCAT
自帶的數(shù)據(jù)庫連接池實(shí)現(xiàn),其實(shí)就是
Apache DBCP
連接池的重新封裝。
<!--
加載
properties
配置文件
-->
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
??? <property name="locations">
??????? <list>
??????????? <value>/WEB-INF/jdbc.properties</value>
??????? </list>
??? </property>
</bean>
?
<!--
數(shù)據(jù)源
-->
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
??? <property name="driverClassName" value="${jdbc.driverClassName}"/>
??? <property name="url" value="${jdbc.url}"/>
??? <property name="username" value="${jdbc.username}"/>
??? <property name="password" value="${jdbc.password}"/>
</bean>
|
jdbc.properties
文件在
/WEB-INF/
目錄下:
jdbc.driverClassName=oracle.jdbc.OracleDriver
jdbc.url=jdbc:oracle:thin:@localhost:1521:oradb
jdbc.username=demo
jdbc.password=123456
|
在
applicationContext.xml
文件中加入下面配置,數(shù)據(jù)庫事務(wù)管理,采用的是
AOP
代理,對(duì)所有文件名稱以
Logic
結(jié)尾的接口類進(jìn)行事務(wù)代理。在接口類中,方法名稱以
insert
、
update
等開頭的采用事務(wù)管理,設(shè)置
Propagation
為
REQUIRED
表示支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就新建一個(gè)事務(wù);而其他的方法以
*
表示,設(shè)置
Propagation
為
SUPPORTS
表示支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù)就以非事務(wù)方式執(zhí)行,
read-Only
為
true
表示對(duì)應(yīng)事務(wù)被最優(yōu)化為只讀事務(wù)。
<!--
事務(wù)管理器
-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
??? <property name="dataSource" ref="dataSource"/>
</bean>
?
<!--aop
代理,對(duì)所有以
Logic
為后綴文件名的接口類進(jìn)行代理
-->
<aop:config>
??? <aop:advisor pointcut="execution(* *..*Logic.*(..))" advice-ref="txAdvice"/>
</aop:config>
?
<!--
數(shù)據(jù)庫事務(wù)代理,對(duì)類中的指定前綴的方法進(jìn)行事務(wù)控制
-->
<tx:advice id="txAdvice">
??? <tx:attributes>
??????? <tx:method name="insert*" propagation="REQUIRED"/>
??????? <tx:method name="update*" propagation="REQUIRED"/>
??????? <tx:method name="delete*" propagation="REQUIRED"/>
??????? <tx:method name="upload*" propagation="REQUIRED"/>
??????? <tx:method name="*" propagation="SUPPORTS" read-only="true"/>
??? </tx:attributes>
</tx:advice>
|
pointcut
的語法說明如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
??
除了返回類型模式、名字模式和參數(shù)模式以外,所有的部分都是可選的;
??
返回類型模式(
ret-type-pattern
)決定了方法的返回類型必須依次匹配一個(gè)連接點(diǎn),返回類型模式
*
代表了匹配任意的返回類型;
??
名字模式(
name-pattern
)匹配的是方法名,可以使用
*
通配符作為所有或者部分命名模式;
??
參數(shù)模式(
param-pattern
)稍微有點(diǎn)復(fù)雜,
()
匹配了一個(gè)不接受任何參數(shù)的方法,而
(..)
匹配了一個(gè)接受任意數(shù)量參數(shù)的方法(零或者更多),模式
(*)
匹配了一個(gè)接受一個(gè)任何類型的參數(shù)的方法,模式
(*,String)
匹配了一個(gè)接受兩個(gè)參數(shù)的方法,第一個(gè)可以是任意類型,第二個(gè)則必須是
String
類型。
?
下面給出一些常見切入點(diǎn)表達(dá)式的例子。
??
任意公共方法的執(zhí)行:
execution(public * *(..))
;
??
任何一個(gè)以“
set
”開始的方法的執(zhí)行:
execution(* set*(..))
;
??
AccountService
接口的任意方法的執(zhí)行:
execution(* com.xyz.service.AccountService.*(..))
;
??
定義在
service
包里的任意方法的執(zhí)行:
execution(* com.xyz.service.*.*(..))
;
??
定義在
service
包或者子包里的任意方法的執(zhí)行:
execution(* com.xyz.service..*.*(..))
;
?
表達(dá)式
execution(* *..BookManager.save(..))
的解讀:
??
第一顆
*
代表
ret-type-pattern
返回值可任意;
??
*..BookManager
代表任意
Pacakge
里的
BookManager
類,如果寫成
com.xyz.service.*
則代表
com.xyz.service
下的任意類,
com.xyz.service..* com.xyz.service
則代表
com.xyz.service
及其子
package
下的任意類;
??
save
代表
save
方法,也可以寫
save*
代表
saveBook()
等方法;
??
(..)
匹配
0
個(gè)參數(shù)或者多個(gè)參數(shù)的,任意類型,
(x,..)
第一個(gè)參數(shù)的類型必須是
X
,
(x,,,s,..)
匹配至少
4
個(gè)參數(shù),第一個(gè)參數(shù)必須是
x
類型,第二個(gè)和第三個(gè)參數(shù)可以任意,第四個(gè)必須是
s
類型。
控制器的配置文件為
servlet-xxx.xml
,
xxx
為
URI
請(qǐng)求的擴(kuò)展名,此文件可以在
web.xml
中配置,如果不配置,
spring
默認(rèn)查找的是
xxx-servlet.xml
文件,前后調(diào)轉(zhuǎn)一下可方便很多的同類文件排序查看:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
?????? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
?????? xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
?
??? <import resource="applicationContext.xml"/>
?
??? <bean id="defaultHandlerMapping" class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
?
??? <bean name="/mainpage.do" class="org.springframework.web.servlet.mvc.ParameterizableViewController">
??????? <property name="viewName" value="mainpage.jsp"/>
??? </bean>
?
??? <!--
無攔截請(qǐng)求
-->
??? <bean id="noInterceptors" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
??????? <property name="mappings">
??????????? <props>
??????????????? <prop key="login.do">doController</prop>
??????????? </props>
??????? </property>
??? </bean>
?
??? <!--
有攔截請(qǐng)求
-->
??? <bean id="hasInterceptors" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
??????? <property name="interceptors">
??????????? <list>
??????????????? <ref bean="authInterceptor"/>
??????????? </list>
??????? </property>
??????? <property name="mappings">
??????????? <props>
??????????????? <prop key="enter.do">doController</prop>
??????????????? <prop key="logout.do">doController</prop>
??????????? </props>
??????? </property>
??? </bean>
?
??? <!--
請(qǐng)求與方法映射控制器
-->
??? <bean id="doController" class="com.fyyk.core.LogicController">
??????? <property name="logicClass" ref="doLogic"/>
??????? <property name="uriMethodMapping">
??????????? <props>
??????????????? <prop key="login">login</prop>
??????????????? <prop key="enter">enter</prop>
??????????????? <prop key="logout">logout</prop>
??????????? </props>
??????? </property>
??? </bean>
?
</beans>
|
邏輯類的配置文件為
applicationContext-xxx.xml
,此文件可以在
web.xml
中配置,如
applicationContext-admin.xml
文件,也可以配置合并在
applicationContext.xml
中:
??? <bean id="authInterceptor" class="com.fyyk.interceptor.AuthInterceptor">
??????? <property name="noLoginRedirect" value="/WEB-INF/jsp/noLogin.jsp"/>
??? </bean>
?
??? <bean id="doLogic" class="com.fyyk.logic.DoLogicImpl">
??????? <property name="dataSource" ref="dataSource"/>
??? </bean>
|
一般說來,完成一個(gè)操作流程的全部開發(fā)需要完成以下工作:
1.??
配置
servlet-xxx.xml
文件,加入
URI
請(qǐng)求的控制器
Bean
、邏輯類及方法;
2.??
配置
applicaionContext-xxx.xml
文件,加入響應(yīng)
URI
請(qǐng)求的邏輯類
Bean
定義;
3.??
建立邏輯類文件接口類文件,加入響應(yīng)
URI
請(qǐng)求的方法,并實(shí)現(xiàn)該類和方法,在方法體中完成具體的業(yè)務(wù)代碼,如果需要操作數(shù)據(jù)庫,則實(shí)現(xiàn)類需要繼承
JdbcDaoSupport
類;
4.??
建立
.jsp
文件,輸出請(qǐng)求結(jié)果;
點(diǎn)此下載演示代碼
接下來會(huì)有一些應(yīng)用范例程序介紹給大家。