帶你逐步深入瞭解SSM框架——SpringMVC框架詳解
1 SpringMVC架構
1.1 Spring web mvc介紹
Spring web mvc和Struts2都屬於表現層的框架,它是Spring框架的一部分,我們可以從Spring的整體結構中看得出來:
1.2 Web MVC
mvc設計模式在b/s系統下應用:
1、 使用者發起request請求至控制器(Controller)
控制接收使用者請求的資料,委託給模型進行處理
2、 控制器通過模型(Model)處理資料並得到處理結果
模型通常是指業務邏輯
3、 模型處理結果返回給控制器
4、 控制器將模型資料在檢視(View)中展示
web中模型無法將資料直接在檢視上顯示,需要通過控制器完成。如果在C/S應用中模型是可以將資料在檢視中展示的。
5、 控制器將檢視response響應給使用者
通過檢視展示給使用者要的資料或處理結果。
1.3 Spring web mvc 架構
1.3.1 架構圖
1.3.2 架構流程
1、 使用者傳送請求至前端控制器DispatcherServlet
2、 DispatcherServlet收到請求呼叫HandlerMapping處理器對映器。
3、 處理器對映器根據請求url找到具體的處理器,生成處理器物件及處理器攔截器(如果有則生成)一併返回給DispatcherServlet。
4、 DispatcherServlet通過HandlerAdapter處理器介面卡呼叫處理器
5、 執行處理器(Controller,也叫後端控制器)。
6、 Controller執行完成返回ModelAndView
7、 HandlerAdapter將controller執行結果ModelAndView返回給DispatcherServlet
8、 DispatcherServlet將ModelAndView傳給ViewReslover檢視解析器
9、 ViewReslover解析後返回具體View
10、 DispatcherServlet對View進行渲染檢視(即將模型資料填充至檢視中)。
11、 DispatcherServlet響應使用者
1.3.3 元件說明
以下元件通常使用框架提供實現:
u DispatcherServlet:前端控制器
使用者請求到達前端控制器,它就相當於mvc模式中的c,dispatcherServlet是整個流程控制的中心,由它呼叫其它元件處理使用者的請求,dispatcherServlet的存在降低了元件之間的耦合性。
u HandlerMapping:處理器對映器
HandlerMapping負責根據使用者請求找到Handler即處理器,springmvc提供了不同的對映器實現不同的對映方式,例如:配置檔案方式,實現介面方式,註解方式等。
u Handler:處理器
Handler 是繼DispatcherServlet前端控制器的後端控制器,在DispatcherServlet的控制下Handler對具體的使用者請求進行處理。
由於Handler涉及到具體的使用者業務請求,所以一般情況需要程式設計師根據業務需求開發Handler。
u HandlAdapter:處理器介面卡
通過HandlerAdapter對處理器進行執行,這是介面卡模式的應用,通過擴充套件介面卡可以對更多型別的處理器進行執行。
u View Resolver:檢視解析器
View Resolver負責將處理結果生成View檢視,View Resolver首先根據邏輯檢視名解析成物理檢視名即具體的頁面地址,再生成View檢視物件,最後對View進行渲染將處理結果通過頁面展示給使用者。 springmvc框架提供了很多的View檢視型別,包括:jstlView、freemarkerView、pdfView等。
一般情況下需要通過頁面標籤或頁面模版技術將模型資料通過頁面展示給使用者,需要由程式設計師根據業務需求開發具體的頁面。
2 商品訂單業務說明
本教程在通過商品訂單業務學習使用springmvc進行功能開發。
2.1 業務流程
1、管理員維護商品資訊
2、使用者挑選商品,購買,建立訂單
2.2 資料庫環境
先匯入sql_table.sql,再匯入 sql_data.sql指令碼:
如下:
2.3 商品訂單資料模型
3 SpringMVC入門
3.1 需求
實現商品查詢列表功能。
3.2 開發環境準備
本教程使用Eclipse+tomcat7開發
詳細參考“Eclipse開發環境配置-indigo.docx”文件
3.3 第一步:建立一個Web專案
在eclipse下建立動態web工程springmvc_first。
3.4 第二步:匯入spring3.2.0的jar包
3.5 第三步:前端控制器配置
在WEB-INF\web.xml中配置前端控制器,
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
load-on-startup:表示servlet隨服務啟動;
url-pattern:*.action的請交給DispatcherServlet處理。
contextConfigLocation:指定springmvc配置的載入位置,如果不指定則預設加
載WEB-INF/[DispatcherServlet的Servlet 名字]-servlet.xml。
3.5.1 Servlet攔截方式
1、攔截固定字尾的url,比如設定為 *.do、*.action, 例如:/user/add.action
此方法最簡單,不會導致靜態資源(jpg,js,css)被攔截。
2、攔截所有,設定為/,例如:/user/add /user/add.action
此方法可以實現REST風格的url,很多網際網路型別的應用使用這種方式。
但是此方法會導致靜態檔案(jpg,js,css)被攔截後不能正常顯示。需要特殊處理。
3、攔截所有,設定為/*,此設定方法錯誤,因為請求到Action,當action轉到jsp時再次被攔截,提示不能根據jsp路徑mapping成功。
3.6 第四步:springmvc配置檔案
Springmvc預設載入WEB-INF/[前端控制器的名字]-servlet.xml,也可以在前端控制器定義處指定載入的配置檔案,如下:
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
如上程式碼,通過contextConfigLocation載入classpath下的springmvc.xml配置檔案。
3.7 第五步:配置處理器介面卡
在springmvc.xml檔案配置如下:
SimpleControllerHandlerAdapter:即簡單控制器處理介面卡,所有實現了org.springframework.web.servlet.mvc.Controller 介面的Bean作為
Springmvc的後端控制器。
3.8 第六步:處理器開發
publicclass ItemList1implements Controller {
@Override
public ModelAndViewhandleRequest(HttpServletRequest request,
HttpServletResponseresponse)throws Exception {
//商品列表
List<Items>itemsList =new ArrayList<Items>();
Items items_1= new Items();
items_1.setName("聯想筆記本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430聯想膝上型電腦!");
Items items_2= new Items();
items_2.setName("蘋果手機");
items_2.setPrice(5000f);
items_2.setDetail("iphone6蘋果手機!");
itemsList.add(items_1);
itemsList.add(items_2);
//建立modelAndView準備填充資料、設定檢視
ModelAndView modelAndView =new ModelAndView();
//填充資料
modelAndView.addObject("itemsList", itemsList);
//檢視
modelAndView.setViewName("order/itemsList");
return modelAndView;
}
}
org.springframework.web.servlet.mvc.Controller:處理器必須實現Controller 介面。
ModelAndView:包含了模型資料及邏輯檢視名
3.9 第七步:配置處理器對映器
在springmvc.xml檔案配置如下:
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!-- 處理器對映器 -->
<!-- 根據bean的name進行查詢Handler將action的url配置在bean的name中 -->
<bean
BeanNameUrlHandlerMapping:表示將定義的Bean名字作為請求的url,需要將編寫的controller在spring容器中進行配置,且指定bean的name為請求的url,且必須以.action結尾。
3.10 第八步:處理器配置
在springmvc.xml檔案配置如下:
<!-- controller配置 -->
<bean name="/items1.action"id="itemList1"
class="cn.itcast.springmvc.controller.first.ItemList1"/>
name="/items1.action":前邊配置的處理器對映器為BeanNameUrlHandlerMapping,如果請求的URL 為“上下文/items1.action”將會成功對映到ItemList1控制器。
3.11 第九步:配置檢視解析器
在springmvc.xml檔案配置如下:
<propertyname="viewClass"value="org.springframework.web.servlet.view.JstlView"/>
<propertyname="prefix"value="/WEB-INF/jsp/"/>
<propertyname="suffix"value=".jsp"/>
</bean>
InternalResourceViewResolver:支援JSP檢視解析
viewClass:JstlView表示JSP模板頁面需要使用JSTL標籤庫,所以classpath中必須包含jstl的相關jar 包;
prefix 和suffix:查詢檢視頁面的字首和字尾,最終檢視的址為:
字首+邏輯檢視名+字尾,邏輯檢視名需要在controller中返回ModelAndView指定,比如邏輯檢視名為hello,則最終返回的jsp檢視地址 “WEB-INF/jsp/hello.jsp”
3.12 第十步:檢視開發
建立/WEB-INF/jsp/order/itemsList.jsp檢視頁面:
<%@pagelanguage="java"contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@tagliburi="http://java.sun.com/jsp/jstl/core"prefix="c"%>
<%@tagliburi="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPEhtmlPUBLIC "-//W3C//DTDHTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html; charset=UTF-8">
<title>查詢商品列表</title>
</head>
<body>
商品列表:
<tablewidth="100%"border=1>
<tr>
<td>商品名稱</td>
<td>商品價格</td>
<td>商品描述</td>
</tr>
<c:forEachitems="${itemsList }"var="item">
<tr>
<td>${item.name }</td>
<td>${item.price }</td>
<td>${item.detail }</td>
</tr>
</c:forEach>
</table>
</body>
</html>
3.13 第十一步:部署在tomcat測試
通過請求:http://localhost:8080/springmvc_first/items1.action,如果頁面輸出商品列表就表明我們成功了!
3.14 DispatcherServlet
DispathcerServlet作為springmvc的中央排程器存在,DispatcherServlet建立時會預設從DispatcherServlet.properties檔案載入springmvc所用的各各元件,如果在springmvc.xml中配置了元件則以springmvc.xml中配置的為準,DispatcherServlet的存在降低了springmvc各各元件之間的耦合度。
3.15 HandlerMapping處理器對映器
HandlerMapping 負責根據request請求找到對應的Handler處理器及Interceptor攔截器,將它們封裝在HandlerExecutionChain 物件中給前端控制器返回。
3.15.1 BeanNameUrlHandlerMapping
BeanNameUrl處理器對映器,根據請求的url與spring容器中定義的bean的name進行匹配,從而從spring容器中找到bean例項。
<!—beanName Url對映器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
3.15.2 SimpleUrlHandlerMapping
simpleUrlHandlerMapping是BeanNameUrlHandlerMapping的增強版本,它可以將url和處理器bean的id進行統一對映配置。
<!—簡單url對映 -->
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/items1.action">controller的bean id</prop>
<prop key="/items2.action">controller的bean id</prop>
</props>
</property>
</bean>
3.16 HandlerAdapter處理器介面卡
HandlerAdapter會根據介面卡介面對後端控制器進行包裝(適配),包裝後即可對處理器進行執行,通過擴充套件處理器介面卡可以執行多種型別的處理器,這裡使用了介面卡設計模式。
3.16.1 SimpleControllerHandlerAdapter
介面卡配置如下:
<beanclass="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/>
HttpRequestHandlerAdapter,http請求處理器介面卡,所有實現了org.springframework.web.HttpRequestHandler 介面的Bean通過此介面卡進行適配、執行。
介面卡配置如下:
<beanclass="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/>
Controller實現如下:
publicclass ItemList2implements HttpRequestHandler {
@Override
publicvoid handleRequest(HttpServletRequestrequest,
HttpServletResponseresponse)throws ServletException, IOException {
// 商品列表
List<Items> itemsList =new ArrayList<Items>();
Items items_1 = new Items();
items_1.setName("聯想筆記本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430聯想膝上型電腦!");
Items items_2 = new Items();
items_2.setName("蘋果手機");
items_2.setPrice(5000f);
items_2.setDetail("iphone5 蘋果手機!");
itemsList.add(items_1);
itemsList.add(items_2);
// 填充資料
request.setAttribute("itemsList", itemsList);
// 檢視
request.getRequestDispatcher("/WEB-INF/jsp/order/itemsList.jsp").forward(request, response);
}
}
從上邊可以看出此介面卡器的handleRequest方法沒有返回ModelAndView,可通過response修改定義響應內容,比如返回json資料:
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
3.17 註解對映器和介面卡
3.17.1 Controller的程式碼
@Controller
publicclass ItemList3 {
@RequestMapping("/queryItem.action")
public ModelAndView queryItem() {
// 商品列表
List<Items> itemsList =new ArrayList<Items>();
Items items_1 = new Items();
items_1.setName("聯想筆記本");
items_1.setPrice(6000f);
items_1.setDetail("ThinkPad T430聯想膝上型電腦!");
Items items_2 = new Items();
items_2.setName("蘋果手機");
items_2.setPrice(5000f);
items_2.setDetail("iphone6蘋果手機!");
itemsList.add(items_1);
itemsList.add(items_2);
// 建立modelAndView準備填充資料、設定檢視
ModelAndView modelAndView =new ModelAndView();
// 填充資料
modelAndView.addObject("itemsList", itemsList);
// 檢視
modelAndView.setViewName("order/itemsList");
return modelAndView;
}
}
3.17.2 元件掃描器
使用元件掃描器省去在spring容器配置每個controller類的繁瑣。使用<context:component-scan自動掃描標記@controller的控制器類,配置如下:
<!--掃描controller註解,多個包中間使用半形逗號分隔 -->
<context:component-scanbase-package="cn.itcast.springmvc.controller.first"/>
註解式處理器對映器,對類中標記@ResquestMapping的方法進行對映,根據ResquestMapping定義的url匹配ResquestMapping標記的方法,匹配成功返回HandlerMethod物件給前端控制器,HandlerMethod物件中封裝url對應的方法Method。
配置如下:
<!--註解對映器 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>
註解描述:
@RequestMapping:定義請求url到處理器功能方法的對映
註解式處理器介面卡,對標記@ResquestMapping的方法進行適配。
配置如下:
<!--註解介面卡 -->
<beanclass="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>
3.17.5 <mvc:annotation-driven>
springmvc使用<mvc:annotation-driven>自動載入RequestMappingHandlerMapping和RequestMappingHandlerAdapter,可用在springmvc.xml配置檔案中使用<mvc:annotation-driven>替代註解處理器和介面卡的配置。
3.18 springmvc處理流程原始碼分析
1. 使用者傳送請求到DispatherServlet前端控制器
2. DispatherServlet呼叫HandlerMapping(處理器對映器)根據url查詢Handler
3. DispatherServlet呼叫HandlerAdapter(處理器介面卡)對HandlerMapping找到Handler進行包裝、執行。HandlerAdapter執行Handler完成後,返回了一個ModleAndView(springmvc封裝物件)
DispatherServlet找一個合適的介面卡:
介面卡執行Hanlder
4. DispatherServlet拿著ModelAndView呼叫ViewResolver(檢視解析器)進行檢視解析,解析完成後返回一個View(很多不同檢視型別的View)
檢視解析:
5. DispatcherServlet進行檢視渲染,將Model中資料放到request域,在頁面展示
將model資料放在request域:
4 整合mybatis
為了更好的學習springmvc和mybatis整合開發的方法,需要將springmvc和mybatis進行整合。
整合目標:控制層採用springmvc、持久層使用mybatis實現。
4.1 需求
實現商品查詢列表,從mysql資料庫查詢商品資訊。
4.2 jar包
包括:spring(包括springmvc)、mybatis、mybatis-spring整合包、資料庫驅動、第三方連線池。
參考:“mybatis與springmvc整合全部jar包”目錄
4.3 Dao
目標:
1、spring管理SqlSessionFactory、mapper
詳細參考mybatis教程與spring整合章節。
4.3.1 db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mybatis
jdbc.username=XXXX
jdbc.password=XXXX
4.3.2 log4j.properties
#Global logging configuration,建議開發環境中要用debug
log4j.rootLogger=DEBUG, stdout
#Console output...
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
4.3.3 sqlMapConfig.xml
在classpath下建立mybatis/sqlMapConfig.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<!DOCTYPEconfiguration
PUBLIC"-//mybatis.org//DTDConfig 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!—使用自動掃描器時,mapper.xml檔案如果和mapper.java介面在一個目錄則此處不用定義mappers -->
<mappers>
<package name="cn.itcast.ssm.mapper" />
</mappers>
</configuration>
4.3.4 applicationContext-dao.xml
配置資料來源、事務管理,配置SqlSessionFactory、mapper掃描器。
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
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-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd">
<!--載入配置檔案 -->
<context:property-placeholderlocation="classpath:db.properties"/>
<!--資料庫連線池 -->
<beanid="dataSource"class="org.apache.commons.dbcp.BasicDataSource"destroy-method="close">
<property name="driverClassName"value="${jdbc.driver}"/>
<property name="url"value="${jdbc.url}"/>
<property name="username"value="${jdbc.username}"/>
<property name="password"value="${jdbc.password}"/>
<property name="maxActive"value="30"/>
<property name="maxIdle"value="5"/>
</bean>
<!--讓spring管理sqlsessionfactory使用mybatis和spring整合包中的 -->
<bean id="sqlSessionFactory"class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 資料庫連線池 -->
<property name="dataSource"ref="dataSource"/>
<!-- 載入mybatis的全域性配置檔案 -->
<property name="configLocation"value="classpath:mybatis/SqlMapConfig.xml"/>
</bean>
<!-- mapper掃描器 -->
<