Spring Web MVC 介紹
SpringMVC 是 Spring 框架的一個模塊,Spring 和 SpringMVC 是無需通過中間整合層進行整合。例如 Struts 與 Spring 整合的時候,會有一個 struts-spring 這樣的 jar 包,這個包就是整合層。
SpringMVC 是一個基於 MVC 的一個 Web 框架。
MVC:是一個設計模式(設計模式:總結了我們日常開發當中一些很好的經驗和編寫代碼方法,把他抽取一個模式,讓我們軟件工程師按照這種模式開發,可以少走彎路)。使用這種模式是為了剛好的讓我們的系統能夠更好的擴展,其在 B/S 和 C/S 下都有應用,
SpringMVC 框架
前端控制器:DispatcherServlet,這個 request 還是請求到了 Servlet 了,請求到 SpringMvc的前端控制器了,比如就是用戶注冊,他跟我們上面所說的請求是一樣的,接受請求,然后響應,誰來處理呢?模型,我們寫之前的項目的時候,需要些 service,dao,pojo。
在 SpringMVC 里面,最直接的模型是,是 Handler 處理器,平時我們開發的時候,交流問題的時 候,我們 稱之為 controller,在 SpringMVC 里面 DispatcherServlet 不能直接調用Handler,我們的請求要發一個 url,請求鏈接 前端控制器要通過,處理器映射器處理器映射器:根據 URL 來找到對應的處理器,其實他是根據 XML 配置的方式來找。找到之后,就返回 Handler,返回的不是一個單純的 Handler , 返回的是一個執行鏈,叫做 HandlerExecutionChain{ },在這個鏈當中,就有一個 Handler,在 Handler 之前還有
1.request
前端控制器
DispatcherServlet
接受用戶請求,響應
Handler 處理器
平常我們稱之為 controller
處理器映
射器
HandlerM
apping
2. 請求查找
Handler
3.返回一個執行鏈
HandlerExceutionCh
ain{
HandlerIntercepter1
HandlerIntercepter2
…
Handler
}
處理器適配器
HanderAdapter
去執行 Handler
4. 請 求 執 行
Handler
5.執行
6.返回 ModelAndView
7.
返 回
ModelAmdView、
View 視圖、
Jsp、
Freemark、
Excel 、
Pdf
視圖解析器
View resolver
8.請求視圖解
析
9. 返回View
10.視圖渲染將模型數據填 充 到request 作用域中
11.Response很多的 HandlerIntercepter 攔截器,可以只有一個,也可以有多個。
框架的設計,講究的是框架的可擴展性,其實,在這里,有各種 Handler,我們不可 能 把
Handler 寫到 DispatcherServlet 里面,如果我們把這個邏輯寫到 DispatcherServlet,我
們的程序代碼很難維護。
這個時候,我們就需要一個組件,那就是處理器適配器,HandlerAdapter 去執行 Handler,
舉例:手機充電器,接受的電壓很小,然后通過充電器進行變壓,剃須刀的適配器,也可
以改變電壓
我們會寫不同的 Handler,不同的 handler 由不同的的適配器去執行。
此時:適配器就調用 Handler 處理器去執行請求,返回 ModelAndView 是模型和視圖的結合
體。
視圖:框架講究的是可擴展性,視圖包括很多,jsp、freemark、excel、pdf 等
SpringMVC:通過視圖解析器(View resolver)來解析各種視圖,解析完畢,返回給前端控制
器(DispatcherServlet),返回一個真正的視圖,請求的其實是一個邏輯視圖,返回真正
的視圖 View。
最后: 視圖渲染將模型數據填充到 request 作用域中
總結:
1. 發起請求到前端控制器(DispatcherServlet)
2. 前端控制器請求 HandlerMapping 查找 Handler
- 可以根據 XML 配置
- 也可以根據注解來查找
3. 處理器映射器,向前端控制器返回 Handler
4. 前端控制器要執行 Handler,調用處理器適配器來執行 Handler
5. 處理器適配器去執行 Handler
6. Handler 執行完,給處理器適配器返回 ModelAndView,是 SpringMVC 的一個底層對象
7. 處理器適配器,向前端控制器返回一個 ModelAndView
8. 請求視圖解析器,去進行視圖解析,根據邏輯視圖名,來解析出真正的視圖
9. 將視圖解析器解析的結果 View,返回給前端控制器
10. 前端控制器進行視圖的渲染(就是講模型數據【在 ModelAndView 中】填充到 request
域中),最終返回給用戶
11. 前端控制器,向用戶響應。
組件:
1. 前端控制器(DispatcherServlet)[中央處理器](不需要程序員開發)
- 作用:接受請求和響應結果(相當於轉發器)
- 有了 DispatcherServlet 就減少了其他組件之間的耦合性,
2. 處理器映射器 HandlerMapping(不需要程序員開發)
- 作用:根據請求的 URL 來查找 Handler
3. 處理器適配器 HandlerAdapter
- 作用:按照特定的規則(HandlerAdapter 要求的規則):執行 Handler
4. 處理器 Handler(需要程序員開發)
- 注意:開發 Hander 的時候,要按照 HandlerAdapter 的要求去做,這樣適配器才可以去
正確執行 Handler
5. 視圖解析器:(不需要程序員開發)
- 作用:進行視圖解析,根據邏輯視圖,來解析真正的視圖(View)
6. 視圖(需要程序員來開發 JSP)
- View 是一個接口,他的實現類就是來支持不同的 View 類型,(jsp,freemark,pdf……)
1.需要jar包
2.配置前端控制器
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!-- 配置前端控制器 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocaion配置SpringMVC加載的配置文件(配置處理器映射器,適配器等等) --> <!-- 如果不配置 contextConfigLocaion 系統會自動去 /WEB-INF/servlet名稱-servlet.xml (springmvc-servlet) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- 第一種:*.action,可以訪問.action結尾的請求由DispatcherServlet進行解析 --> <!-- 第二種:/ 所有訪問地址都由DispatcherServlet進行解析,對於靜態的文件解析需要配置 不讓DispatcherServlet進行解析,但是使用這種方法可以實現RESTful風格的url --> <!-- 第三種:/* 這種配置方式不對,使用這種配置,當我們轉發到一個jsp頁面時 仍然由DispatcherServlet進行解析JSP地址,不能根據JSP頁面找到handler,會報錯 --> <url-pattern>*.action</url-pattern> </servlet-mapping> <!--<display-name>springmvcdoml</display-name>--> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
log4j.properties
# Global logging configuration
# 在實際開發過程中,日志級別要設置成DEBUG,生產環境要設置成info或error
log4j.rootLogger=debug, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 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
3.配置處理器適配器
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd"> <!-- 配置handler --> <bean id="itemsController1" name="/queryItems1.action" class="com.hzxy.springmvcdoml.controller.ItemsController1" /> <!-- 配置另外一個Handler --> <!-- 對於注解的Handler可以單個配置 --> <!-- 實際開發中,建議使用組件掃描 --> <!-- <bean class="cn.atwyl.ssm.controller.ItemsController3" /> --> <!-- 組件掃描的配置方法,可以掃描controller,service...... --> <!-- 這里我想讓掃描controller,指定controller的包就可以了 --> <context:component-scan base-package="com.hzxy.springmvcdoml.controller" /> <!-- 處理器映射器 --> <!-- BeanNameUrlHandlerMapping 將bean的name作為URL進行查詢找handler --> <!-- 在配置handler的時候,要指定你的beanname(就是url) --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <!-- 簡單URL映射 --> <!--<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">--> <!--<property name="mappings">--> <!--<props>--> <!--<prop key="/queryItems1.action">itemsController1</prop>--> <!--</props>--> <!--</property>--> <!--</bean>--> <!-- 處理器適配器 所有的處理器適配器,都實現了一個接口 HandlerAdapter --> <!--<bean--> <!--class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />--> <!-- 還有一個適配器 所有的處理器適配器,都實現了一個接口 HandlerAdapter --> <!--<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />--> <!-- 試圖解析器 --> <!-- 解析jsp,默認使用jstl,classpath下的有jstl的包 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--<property name="prefix" value="jsp/"/>--> <!--<property name="prefix" value="web/"/>--> <property name="suffix" value=".jsp"/> </bean> <!-- 注解的映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> <!-- 注解的適配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /> <!-- 使用代替上面的兩個器,一個是注解映射器,一個是注解適配器 --> <!-- mvc:annotation-driven這個mvc的注解驅動,默認還加載了很多的參數的綁定方法 --> <!-- 比如json的轉換,默認加載了json的轉換器,如果使用了這個注解驅動, 上面兩行的配置就不需要了 --> <!-- 實際開發過程中,我就使用這種注解驅動的配置方式 --> <mvc:annotation-driven></mvc:annotation-driven> </beans>
如下配置
此適配器能執行----實現了 Controller 接口的 Handler。通過查看源碼,如下視圖:
4.編寫 Handler
Hanlder 需要實現 Controller 接口,才能由 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter 這個適配器來執行。
public class ItemsController1 implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletRespons e response) throws Exception { //調用 Service 查詢數據,先使用模擬數據 List<Items> list=new ArrayList<>(); Items items1=new Items(); items1.setId(1) items1.setItemsCreatetime(new Date()); items1.setItemsDetail("IPhone7Plua Details"); items1.setItemsName("蘋果手機 IPhone7s"); items1.setItemsPic("iphone7s.jpg"); items1.setItemsPrice(5888.66f); Items items2=new Items(); items2.setId(2); items2.setItemsCreatetime(new Date()); items2.setItemsDetail("IPhone8Plua Details"); items2.setItemsName("蘋果手機 IPhone8s"); items2.setItemsPic("iphone8s.jpg"); items2.setItemsPrice(5888.66f); list.add(items1); list.add(items2); //創建 ModelAndView 准備填充數據,設置試圖 ModelAndView modelAndView=new ModelAndView(); //填充數據 modelAndView.addObject("itemList",list); //視圖 modelAndView.setViewName("jsp/items/"); return modelAndView; }
}
5.視圖的編寫
6. 配置 Handler
7. 配置映射器處理器
8.配置視圖解析器
非注解的處理器映射器和適配器
1.非注解的處理器映射器
處理器映射器
org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping
下面多個映射器並存
測試結果:看地址欄,三個地址都可以正常的訪問。多個映射器可以並存,前端控制器判斷 URL,能讓哪些映射器映射,就讓正確的映射器處理,
2.非注解的處理器適配器
非注解的處理器適配器org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter該適配器要求處理器適配器 所有的處理器適配器,都實現了一個接口 Controller。
編寫的 Handler 實現了 HttpRequestHandler 接口。
配置 springmvc.xml
DispatcherServlet.properties
注解的處理器映射器和適配器
在 Spring3.1 之前注解使用映射器: org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 注解映 射器文器。 在 Spring3.1 之后,就使用映射器: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 注解映射文器。 在 3.1 之前注解使用的適配器是: org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 在 3.1 之后注解使用適配器是: org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
3.配置注解的映射器和適配器
3.開發注解的 Handler
4.在 Spring 容器中,來加載 Handler
5.測試
源碼分析(了解)
SpringMVC 和 MyBatis 整合
1. 整合的思路
第一步:整合 dao 層(持久層)
- MyBatis 和 Spring 整合,通過 Spring 管理 Mapper 接口,使用 Mapper 的掃描器,來自
動掃描 mapper 接口在 Spring 中進行注冊。
第二步:整合 service 層
- 通過 Spring 管理 service 接口,使用配置的方式,將 Service 接口配置在 Spirng 配置文件。
表現層
業務層:service 接口
持久層:MyBatis
MySQL
Spring 在架構中的作用:
Spring 將各層進行整合
通過 Spring 的整合,可以管理持久層的
mapper,相當於我們寫的 dao 的接口。
通過 Spring 管理業務層的 service,service 層
可以調用 Mapper 接口,另外還要進行事務
的控制。
通過 Spring 管理表現層的 Handler,Handler
里面可以調用 Service 里面的接口
Mapper,Service,Handler 都是 JavaBean- 實現事務的控制。
第三步:整合 SpirngMVC
- 由於 SpringMVC 是 Spring 的一個模塊,所以這里面不需要整合。
2.log4j.properties
# Global logging configuration
# 在實際開發過程中,日志級別要設置成DEBUG,生產環境要設置成info或error
log4j.rootLogger=debug, stdout
# MyBatis logging configuration...
log4j.logger.org.mybatis.example.BlogMapper=TRACE
# 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
3.db.properties
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/mybatis
jdbc.username=root
jdbc.password =971128
#jdbc.maxPoolSize=20
#jdbc.minPoolSize=2
4.SqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!--開啟延遲加載放到properties 標簽下--> <settings> <setting name="lazyLoadTriggerMethods" value="true"/> <setting name="aggressiveLazyLoading" value="false"/> <!--開啟二級緩存--> <setting name="cacheEnabled" value="true"/> </settings> <!-- SSM SSH Spring MyBatis Hibernate Struts --> <!-- 以后該配置將會配置到Spring內,此處被廢棄 --> <typeAliases> <package name="com.hxzy.SSM.mapper"/> </typeAliases> </configuration>
5.applicationContext-dao.xml
<?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: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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd"> <!--開啟注解掃描--> <context:component-scan base-package="com.hxzy.SSM.controller"/> <!--1.加載db.properties的配置文件--> <context:property-placeholder location="classpath:db.properties"/> <!--開啟AOP--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> <!-- 配置事務管理器 --> <!--<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">--> <!--<property name="dataSource" ref="dataSource"/>--> <!--</bean>--> <!--開啟事務注解--> <!--<tx:annotation-driven transaction-manager="transactionManager"/>--> <!--2.配置j3po的數據源--> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="${jdbc.driver}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}"/> <!--<property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>--> <!--<property name="jdbc.minPoolSize" value="${jdbc.minPoolSize}"/>--> </bean> <!--3.配置sqlSessionFactory--> <bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean"> <!--加載mybatis的配置文件--> <property name="configLocation" value="mybatis/SqlMapConfig.xml"/> <!--配置dataSource的數據源--> <property name="dataSource" ref="dataSource"/> </bean> <!--批量掃描mapper.xml文件 嚴格首字母大寫--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.hxzy.SSM.mapper"></property> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactoryBean"/> </bean> <!--//將service注入--> <bean id="itemsService" class="com.hxzy.SSM.service.ItemsServiceImpl"/> <!--聲明事務控制--> <bean id="dataSourceTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--通知--> <tx:advice id="txAdvice" transaction-manager="dataSourceTransactionManager"> <!--轉播行為--> <tx:attributes> <tx:method name="save*" propagation="REQUIRED"/> <tx:method name="delete*" propagation="REQUIRED"/> <tx:method name="insert*" propagation="REQUIRED"/> <tx:method name="update*" propagation="REQUIRED"/> <tx:method name="find*" propagation="SUPPORTS" read-only="true"/> <tx:method name="get*" propagation="SUPPORTS" read-only="true"/> <tx:method name="select*" propagation="SUPPORTS" read-only="true"/> </tx:attributes> </tx:advice> <aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.hxzy.SSM.service.*Impl.*.*(..))"/> </aop:config> </beans>
6. 整合 SpringMVC springmvc.xml
配置web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- contextConfigLocaion配置SpringMVC加載的配置文件(配置處理器映射器,適配器等等) --> <!-- 如果不配置 contextConfigLocaion 系統會自動去 /WEB-INF/servlet名稱-servlet.xml (springmvc-servlet) --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc/springmvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springMVC</servlet-name> <!-- 第一種:*.action,可以訪問.action結尾的請求由DispatcherServlet進行解析 --> <!-- 第二種:/ 所有訪問地址都由DispatcherServlet進行解析,對於靜態的文件解析需要配置 不讓DispatcherServlet進行解析,但是使用這種方法可以實現RESTful風格的url --> <!-- 第三種:/* 這種配置方式不對,使用這種配置,當我們轉發到一個jsp頁面時 仍然由DispatcherServlet進行解析JSP地址,不能根據JSP頁面找到handler,會報錯 --> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>
springmvc.xml
<?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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd"> <!-- 配置handler --> <!--<bean id="itemsController1" name="/queryItems1.action" class="com.hzxy.springmvcdoml.controller.ItemsController1" />--> <!-- 配置另外一個Handler --> <!-- 對於注解的Handler可以單個配置 --> <!-- 實際開發中,建議使用組件掃描 --> <!-- <bean class="cn.atwyl.ssm.controller.ItemsController3" /> --> <!-- 組件掃描的配置方法,可以掃描controller,service...... --> <!-- 這里我想讓掃描controller,指定controller的包就可以了 --> <context:component-scan base-package="com.hxzy.SSM.controller" /> <!-- 處理器映射器 --> <!-- BeanNameUrlHandlerMapping 將bean的name作為URL進行查詢找handler --> <!-- 在配置handler的時候,要指定你的beanname(就是url) --> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" /> <!-- 簡單URL映射 --> <!--<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">--> <!--<property name="mappings">--> <!--<props>--> <!--<prop key="/queryItems1.action">itemsController1</prop>--> <!--</props>--> <!--</property>--> <!--</bean>--> <!-- 處理器適配器 所有的處理器適配器,都實現了一個接口 HandlerAdapter --> <!--<bean--> <!--class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter" />--> <!-- 還有一個適配器 所有的處理器適配器,都實現了一個接口 HandlerAdapter --> <!--<bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter" />--> <!-- 試圖解析器 --> <!-- 解析jsp,默認使用jstl,classpath下的有jstl的包 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!--<property name="prefix" value="jsp/"/>--> <!--<property name="prefix" value="web/"/>--> <property name="suffix" value=".jsp"/> </bean> <!-- 注解的映射器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping" /> <!-- 注解的適配器 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter" /> <!-- 使用代替上面的兩個器,一個是注解映射器,一個是注解適配器 --> <!-- mvc:annotation-driven這個mvc的注解驅動,默認還加載了很多的參數的綁定方法 --> <!-- 比如json的轉換,默認加載了json的轉換器,如果使用了這個注解驅動, 上面兩行的配置就不需要了 --> <!-- 實際開發過程中,我就使用這種注解驅動的配置方式 --> <mvc:annotation-driven></mvc:annotation-driven> </beans>
注解
@RequestMapping 注解
1.URL 映射
定義 controller 方法對應的 url,進行處理器映射使用。
2.窄化請求映射
為了很好的分類管理我的這個 url 映射,我就在 controller 上面定義一個根。最終訪問的路徑,即使根路徑+子路徑比如說商品的列表:/items/queryItems.action,這種叫做窄化請求映射
3.限制請求方法
可以限制 HTTP 的請求的方法:處於一些安全的考慮,對一些 HTTP 的鏈接進行限制,可以是 get 也可以是 post,也可以是即使 get 又是 post
Cntroller 方法的返回值
1. 可以返回 ModelAndView
- 方法結束的時候,定義 ModelAndView,將 model 和 view 分別進行設置。
2. 還可以返回 Srring
- 如果 controller 返回的是 String,表示返回的是邏輯視圖名
- 真正的視圖(JSP 路徑)=前綴+邏輯視圖名+后綴

-Redirect 重定向
- forward 頁面轉發
- 通過 forward 地址欄不變,request 可以共享。

3. 還可以返回 void
參數綁定
@RequestParam
通過@RequestParam 對簡單的類型的參數進行綁定,如果不使用這個注解@RequestParam,要求 request 傳入的參數名稱要和 controller 方法的形參名稱一致,方可綁定成功。

SpringMVC 參數綁定的過程
從客戶端請求 Key/Value 數據,經過參數綁定,將 Key/Value 的數據,綁定到 Controller 的形參上。在 SpringMVC 中,是通過方法的形參,來接受數據,而不是在 Controller 來定義成員變量。
默認支持的類型
直接在方法的形參上,定義下邊類型的對象,就可以使用這些對象,就是在參數綁定的過程中,如果遇到下邊的類型,就直接進行綁定。
1. HttpServletRequest
- 通過 request 獲取信息
2. HttpServletResponse
- 通過 response 處理相應信息
3. HttpSession
- 通過 session 對象得到 session 中存放對象
4. Model/ModelMap
- Model 是一個接口
- ModelMap 是一個接口的實現,寫 Model 和寫 ModelMap 其實都一樣。
- 作用:將模型數據,填充到 request 域
簡單類型
POJO 綁定
頁面中的 input 的 name 與 controller 的 pojo 形參的屬性名一致。將頁面中的數據,綁定到POJO。頁面的定義如下:
形參 ItemsCustom 的屬性名:

自定義參數綁定實現日期類型的綁定
對於 Controller 形參中的 pojo 對象,如果屬性中有日期類型,需要自定義參數綁定。將請求的日期字符串轉成日期類型,要轉換的日期類型,和 pojo 中的屬性的類型保持一致。所以說,自定義的參數綁定要
將日期轉成 java.util.Date 類型。需要向處理器適配器中,注入我們自定義的參數綁定組件:

配置方式:
亂碼
包裝類參數綁定

集合類型綁定
數組的綁定
List 綁定
通常情況下需要批量提交數據的時候,將提交的數據綁定到 List<pojo>中,比如說,成績的錄入,會產生批量提交的情況。本例子:批量商品的修改:在頁面中輸入多個商品的信息, 將多個商品的信息 , 提交到Controller 的方法中……
1. 進入批量修改的頁面:(頁面樣式,可以參考我們的商品列表頁面實現 )
2. 批量商品修改提交:
使用 List 接受頁面提交的批量數據,通過包裝 pojo 來接受,在包裝 pojo 中,要定義 list 屬
性
Map 的綁定
服務端校驗
校驗的理解
項目中,通常使用的較多的是前端的校驗,比如頁面中的 js 校驗, 對應安全性要求較高的屬性字段,建議在服務器端校驗。服務端校驗:控制層:controller 校驗頁面請求參數的合法性。在服務端控制層 controller 校驗,不區分客戶端的類型(瀏覽器,手機客戶端,遠程接口的調用)。業務層:service 主要校驗業務比較關鍵的一些參數,僅限於 service 接口中所使用的參數。
持久層 dao:一般不校驗。用較多的是 service 層。你不能只知道 JS 校驗,你也要知道服務端也可以校驗。
SpringMVC 的校驗
SpringMVC 使用 Hibernate 的校驗框架 validation(和 Hibernate 沒有任何關系)。就是一個校驗框架。
校驗的思路:
頁面提交的請求的參數,請求到 controller 方法中,使用我們上面所說的 validation 進行校驗,如果校驗通過,就往 service 里面走,如果校驗失敗,將錯誤信息展現在頁面。
需求:
商品修改,我們要添加校驗(校驗商品的名稱的長度 1-30 個字符,生產日期非空校驗),如果出錯,我們在修改商品的頁面顯示錯誤信息。
准備環境
Hibernate 的校驗框架 validation 所需 jar 包
配置校驗器
<!-- 配置校驗器 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"> <!-- hibernate 校驗器 --> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property> <!-- 指定校驗使用的資源文件,如果不指定則默認使用 classpath 下的 ValidationMessage.properties --> <property name="validationMessageSource" ref="messageSource"></property> </bean> <!-- 驗證錯誤信息配置文件 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMe ssageSource"> <!-- 資源文件名 --> <property name="basenames"> <list><value>classpath:CustomValidationMessage</value> </list> </property> <!-- 資源文件編碼方式 --> <property name="fileEncodings" value="UTF-8"></property> <!-- 對資源文件內容緩存時間,單位秒 --> <property name="cacheSeconds" value="120"></property> </bean>
校驗器注入到處理器適配器
校驗的錯誤信息 CustomValidationMessage.properties
###配置驗證的錯誤消息
items.name.length.error=請輸入長度為1-30個字符以內的商品名稱
items.createtime.notnull.error=商品的生產日期不能為空
在 pojo 中添加校驗的規則
Controler 里面的校驗寫法
在頁面中顯示錯誤信息:
Validation 校驗-分組校驗
在 pojo 中,定義校驗規則,而 pojo 中是被多個 controller 所共用,當需要不同的 controller方法對同一個 pojo 進行校驗,每個 Controller 對同一個的 pojo 屬性,需要不同的校驗方法,該怎么解決?
解決方法:定義多個校驗分組(其實就是一個 Java 接口);分組中定義有哪些規則。每個 Controller 方法使用不同的校驗組

在校驗規則中,添加分組

在 Controller 方法中,使用分組

數據回顯
提交后,如果出現錯誤,將剛才提交的數據回顯到提交頁面。
1. SpringMVC 默認對 pojo 數據進行回顯,
- Pojo 數據傳入 controller 中以后,springmvc 自動的將 pojo 的數據存入 request 作用域中,
key 等於 pojo 類型的首字母小寫。
2. 我們使用@ModelAttribute 指定 pojo 回顯到頁面在 request 中的 key。

4. @ModelAttribute 還可以將方法的返回值傳到頁面:
- 需求:
- 在商品的查詢的列表頁面,通過商品的類型來查詢商品的信息:
- 在 controller 中來定義商品查詢的方法,最終將商品的類型傳到頁面。

最簡單的數據回顯的方法其實就是使用 model
簡單數據類型的回顯只能使用 model
使用簡單的方法 model:model.addAttribute("id", id);
異常處理的思路
系統中異常包括兩類:預期異常和運行時異常 RuntimeException,前者通過捕獲異常從而獲取異常信息,后者主要通過規范代碼開發,測試通過手段減少運行時異常的發生。系統的 dao、service、controller 出現都通過 throws Exception 向上拋出,最后由 springmvc 前端控制器交由異常處理器進行異常的處理,如下圖:
自定義的異常類
對不同的異常類型定義異常類,有多少種異常的類型,你就定義多少種異常的類就行了。異常類,要繼承 Exception;
全局異常處理器
當我們系統遇到異常,在程序中,手動拋出,Dao 拋給 Service,Service 拋給 Controller,最后 Controller 拋給前端控制器,前端控制器調用全局的異常處理器:全局異常處理器的思路;首先要解析出當前的異常類型。如果該異常是系統自定義的異常,就直接取出異常的錯誤信息,在錯誤頁面顯示如果不是系統自定義的異常,那基本上都是系統的運行時異常,那么我們就構造一個自定義異常,構造出一個自定義異常類型(信息為“未知錯誤”)
錯誤頁面
在 SpringMVC 中,來配置全局異常處理器
異常測試:
在 Controller、service、dao 中任意一處需要手動拋出異常。如果在程序中手動拋出異常,在錯誤頁面中顯示自定義異常信息,如果不是手動拋出的異常,說明是一個運行時異常,在錯誤頁面顯示“未知錯誤”。我們在商品修改的 Controller 方法中拋出異常:
上傳圖片
加入上傳圖片的 jar 包
SpringMVC 中對多部件類型的解析
jsp 的頁面的 form 中提交 enctype=multipart/form-data 的數據的時候,需要 SpringMVC在 SpringMVC 的配置文件中,springmvc.xml 中配置 multipart 類型的解析器。
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.Common sMultipartResolver"> <!-- 設置上傳文件的最大的尺寸為 5M --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean>
配置上傳圖片的解析器:
創建一個圖片的虛擬目錄來存放圖片
也可以直接修改 Tomcat 的配置文件 Tomcat-----conf------server.xml添加虛擬目錄:
//綁定參數修改 @RequestMapping(value = "/editItemsSubmit",method = {RequestMethod.POST,RequestMethod.GET}) //在修改時進行校驗 //需要添加@Validated注解 //提示信息添加 //分組校驗添加value = ValidationGroupOne.class //進行回顯 public String editItemsSubmit(Model model, @ModelAttribute("itemsCustom") @Validated(value = ValidationGroupTow.class) ItemsCustom itemsCustom , BindingResult bindingResult, MultipartFile items_pic, @RequestParam(value = "id",required = true) Integer id) throws Exception { System.out.println(itemsCustom); System.out.println("______________________________進來哦了_________________________________________"); System.out.println("______________________________進來哦了_________________________________________"); //獲得校驗信息 if (bindingResult.hasErrors()) { //輸出校驗信息 List<ObjectError> allError = bindingResult.getAllErrors(); //輸出遍歷校驗信息 System.out.println("*********輸出遍歷校驗信息***********"+allError.toString()); for (ObjectError objectError : allError) { System.out.println(objectError.getDefaultMessage()); } model.addAttribute("allErrors", allError); //利用 model.addAttribute也可以進行回顯 //model.addAttribute("itemsCustom",itemsCustom); return "items/editItems";//輸入錯誤返回當前頁面 } else { //上傳文件 //判斷得到的文件是否是否空,文件的名稱的長度>0 if (items_pic!=null&&items_pic.getOriginalFilename().length()>0){ //保存文件的物理路徑 String pic_th="F:\\upload\\"; //拿到圖片的原始名稱 String originalFilename=items_pic.getOriginalFilename(); //獲得原始圖片的后綴名 String lastName=originalFilename.substring(originalFilename.lastIndexOf(".")); //新圖片的名稱,使用UUID的隨機數獲得 String newFileName= UUID.randomUUID()+lastName; //新的圖片 File newFile=new File(pic_th+newFileName); //將內存中的圖片寫入磁盤 items_pic.transferTo(newFile); //將新的文件寫入數據庫 itemsCustom.setPic(newFileName); } itemsService.updateByPrimaryKeyWithBLOBs(itemsCustom, id); return "redirect:queryItems.action";//成功轉到展示頁面 } }
Json 的數據交互
@RequestBody
SpringMVC 默認用 MappingJacksonHttpMessageConverter 對 json 數據進行轉換,需要加入客戶端請求 K/V 串請求的是 JSON 串不是默認的類型,需要指定:contentType=”application/json”@RequestBody 將 JSON 串轉換成Java 對@ResponseBody 將 Java 對象轉換成Json 對象輸出請求的是 key/value默認的類型,不需要指定:contentType=”application/x-www-form-urlencoded”不需要@RequestBody 將 JSON 串轉換成 Java 對象@ResponseBody 將 Java 對象轉換成 Json 對象輸出最終:都輸出 Json 數據,為了在前端方便對請求的結果進行解析11jar 包:在 SpirngMVC 中,用以下三個 jar包進行 Json 轉換。(@RequestBody 和 @ResponseBody 使用下邊這兩個包進行 Json 轉換。)
配置 Json 轉換器
攔截器
定義:Spring Web MVC 的處理器攔截器類似於 Servlet 開發中的過濾器,用於對處理器進行預處理和后處理。
攔截器的定義:定義攔截器,它實現了 HandlerInterceptor
public class HandlerInterceptor1 implements HandlerInterceptor { @Override //進入Handler 方法之前執行 //可以用於身份證和身份授權 //比如 身份證不通過,就表明認證不通過,沒有登錄,就用此方法來攔截,不在往下執行 public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception { //獲得訪問路徑 String url=httpServletRequest.getRequestURI(); if (url.indexOf("userLagin.action")>=0){ return true; } HttpSession session=httpServletRequest.getSession(); //獲得session作用域的用戶名 String username= (String) session.getAttribute("username"); if (username!=null&&username!=""){ return true; } httpServletRequest.getRequestDispatcher("/loginUser.jsp").forward(httpServletRequest,httpServletResponse); return false ; } //進入Handler后,返回ModelAndView之前,執行 //應用場景從ModelAndView出發,可以將公共的模型(列如:面包屑導航)傳統到視圖 //可以在此方法中,統一指定視圖 @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override //Handler執行完成,執行該方法 //應用:可以統一異常處理 //統一的日志處理 public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
攔截器的配置
Spring Web MVC 的攔截器,是針對 HandlerMapping 進行攔截設置。第一種配置方式:(這種方式我們一般不推薦使用,麻煩)如果在某個 HandlerMapping 中配置攔截器,經過 HandlerMapping 映射成功的 Handler 才能使用攔截器。
第二種配置方法:
Spring Web MVC 配置類似全局的攔截器,SpringMVC 框架,會將配置的攔截器,自動的注入到每一個 HandlerMapping 中。
攔截器的測試測試
需求
1:測試多個攔截器各個方法的執行時機。
HandlerInterceptor1......preHandle
HandlerInterceptor2......preHandle
HandlerInterceptor2......postHandle
HandlerInterceptor1......postHandle
HandlerInterceptor2......afterCompletion
HandlerInterceptor1......afterCompletion