Spring MVC教程——檢視閱讀css
參考html
Spring MVC教程——一點——藍本前端
Spring MVC教程——c語言中午網——3.0版本太老了vue
Spring MVC教程——易百——4.0版本不是經過maven建立的java
Spring MVC教程——javaschool純理論mysql
Spring MVC應用——javaschool純理論react
Spring MVC學習總結jquery
Spring MVC 4.2.4.RELEASE 中文文檔——基礎學習後看git
SpringMVC面試題程序員
目前大多數使用的是spring4.x.
springboot基於 Spring Framework 5.0 on JDK 8 & 9
Spring 框架提供了構建 Web 應用程序的全功能 MVC 模塊。
什麼是MVC
MVC是一個架構,或者說是一個設計模式,它就是強制性使應用程序的輸入,處理和輸出分開。將一個應用程序分爲三個部分:Model,View,Controller。
原理圖 :
Model模型:負責完成業務邏輯:由JavaBean構成,在MVC的三個部件中,模型擁有最多的處理任務。例如它可能用像EJB和javabean這樣的構件對象來處理數據庫。因爲應用於模型的代碼只需寫一次就能夠被多個視圖重用,因此減小了代碼的重複性。
View視圖:就是負責跟用戶交互的界面。通常就是由HTML,css元素組成的界面,固然如今還有一些像js,ajax,flex一些也都屬於視圖層。 在視圖層裏沒有真正的處理髮生,只負責數據輸出,並容許用戶操縱的方式。MVC能爲應用程序處理不少不一樣的視圖。
Controller控制器:負責接收請求—>調用模型—>根據結果派發頁面並通過模型處理返回相應數據。
MVC的優勢
一、分工明確:使用MVC能夠把數據庫開發,程序業務邏輯開發,頁面開發分開,每一層都具備相同的特徵,方便之後的代碼維護。它使程序員能夠集中精力於各自的模型開發領域。
二、鬆耦合:視圖層和業務層分離,這樣就容許更改視圖層代碼而不用從新編譯模型和控制器代碼,一樣,一個應用的業務流程或者業務規則的改變只須要改動MVC的模型層便可。由於模型與控制器和視圖相分離,因此很容易改變應用程序的數據層和業務規則。
三、複用性高(利於各層邏輯的複用):像多個視圖可以共享一個模型,不論你視圖層是用flash界面或是wap界面,用一個模型就能處理他們。將數據和業務規則從表示層分開,就能夠最大化從用代碼。
四、有利於標準化.
MVC的缺點
一、有時會致使級聯的修改。這種修改尤爲體如今自上而下的方向。若是在表示層中須要增長一個功能,爲保證其設計符合分層式結構,可能須要在相應的業務邏輯層和數據訪問層中都增長相應的代碼。
二、下降了系統的性能。這是不言而喻的。若是不採用分層式結構,不少業務能夠直接造訪數據庫,以此獲取相應的數據,現在卻必須經過中間層來完成。
三、增長理解的複雜度。因爲它沒有明確的定義,因此徹底理解MVC並非很容易。
常見的MVC框架
常見的服務器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常見前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另一些模式如:MVP、MVVM。
什麼是Spring MVC
Spring MVC概述
Spring MVC是Spring Framework的一部分,是基於Java實現MVC的輕量級Web框架。Spring MVC的特色:
Spring MVC功能
Spring MVC圍繞DispatcherServlet設計。 DispatcherServlet的做用是將請求分發到不一樣的處理器。從Spring 2.5開始,使用Java 5或者以上版本的用戶能夠採用基於註解的Controller聲明方式。官網上說Spring的Web模塊提供了大量獨特的功能,包括:
Spring MVC 快速入門
示例:
一、能夠經過module建立工程,再經過"JBLJavaToWeb"插件把Java項目改成Web項目。
二、直接maven建立一個webapp工程,再添加對應的文件夾和包。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.self</groupId> <artifactId>hellospringmvc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <dependencies> <!--SpringMVC依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> </dependencies> </project>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置核心控制器 :DispatcherServlet --> <servlet> <servlet-name>hellospringmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- springmvc配置文件加載路徑 1)默認狀況下,讀取WEB-INF下面的default-servlet.xml文件 2)能夠改成加載類路徑下(resources目錄),加上classpath: --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/hellospringmvc-servlet.xml</param-value> </init-param> <!--init-param必須放在load-on-startup前,不然會報錯:invalid content was found starting with element 'init-param'. One of '{"http://java.sun.com/xml/ns/javaee":run-as, "http://java.sun.com/xml/ns/javaee":security-role-ref}' is expected--> <!-- DispatcherServlet對象建立時間問題 1)默認狀況下,第一次訪問該Servlet時建立對象,默認是訪問時建立,意味着在這個時間纔去加載hellospringmvc-servlet.xml 2)能夠改變爲在項目啓動時候就建立該Servlet,提升用戶訪問體驗。 <load-on-startup>1</load-on-startup> 數值越大,對象建立優先級越低! (數值越低,越先建立) --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hellospringmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
注意事項:
hellospringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.掃描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.開啓mvc註解驅動--> <!--不添加也能使用,高版本spring已經默認實現了。 在Spring中通常採用@RequestMapping註解來完成映射關係,要想使@RequestMapping註解生效必須向上下文中註冊DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例,這兩個實例分別在類級別和方法級別處理。而<mvc:annotation-driven/>配置幫助咱們自動完成上述兩個實例的注入。 --> <!--<mvc:annotation-driven/>--> </beans>
Controller控制器
控制器類是開發Spring MVC程序過程寫的最多的類了。控制器類一般叫Controller,在裏面編寫接收參數,調用業務方法,返回視圖頁面等邏輯。
@Controller註解是爲了讓Spring IOC容器初始化時自動掃描到該Controller類;@RequestMapping是爲了映射請求路徑,這裏由於類與方法上都有映射因此訪問時應該是/hello;方法返回的結果是視圖的名稱success,該名稱不是完整頁面路徑,最終會通過視圖解析器解析爲完整頁面路徑並跳轉。
@Controller public class HelloController { @RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello Spring MVP</title> </head> <body> <h1>Hello Spring MVPPPPPPPPPPPPPPPPPPPPPP!</h1> </body> </html>
請求:http://localhost:8080/hellospringmvc/hello
輸出:
報錯:
一、UnsupportedClassVersionError : Unsupported major.minor version 52.0 。
報錯以下。
Caused by: java.lang.UnsupportedClassVersionError: org/springframework/web/SpringServletContainerInitializer : Unsupported major.minor version 52.0 (unable to load class org.springframework.web.SpringServletContainerInitializer)
A:這是由於JDK版本太低了,spring5.X要求JDK版本要8及以上,目前配置的是JDK7,版本不符合要求了。換成JDK8便可。
二、請求404,獲取/hellospringmvc/WEB-INF/pagessuccess.jsp 沒有結果。
報錯以下:
A:這是由於在配置springmvc配置文件hellospringmvc-servlet.xml時配置視圖解析器沒配置好,很明顯確實了/斜槓分隔符。這視圖解析器視圖根據先後綴來拼接jsp視圖的路徑時因爲前綴少了斜槓而致使映射路徑不對,加上便可,在新增jsp視圖時也要按照格式規範在/WEB-INF/pages/路徑下添加jsp頁面,不然會致使視圖解析器拼接時報錯。
<!-- 2.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean>
Spring MVC 執行流程分析
Spring MVC執行流程圖
關鍵組件分析
Spring MVC 三大組件
處理映射器
處理映射器做用
經過處理器映射,你能夠將Web 請求映射到正確的處理器 Controller 上。當接收到請求時,DispactherServlet 將請求交給 HandlerMapping 處理器映射,讓他檢查請求並找到一個合適的HandlerExecutionChain,這個HandlerExecutionChain 包含一個能處理該請求的處理器 Controller。而後,DispactherServlet 執行在HandlerExecutionChain 中的處理器 Controller。
Spring內置了許多處理器映射策略,目前主要由三個實現。
SimpleUrlHandlerMapping、 BeanNameUrlHandlerMapping RequestMappingHandlerMapping。 //注意:Spring MVC3.1以前使用DefaultAnnotationHandlerMapping,Spring MVC3.1以後改成RequestMappingHandlerMapping。
1)SimpleUrlHandlerMapping
SimpleUrlHandlerMapping 在應用上下文中能夠進行配置,而且有Ant風格的路徑匹配功能。例如咱們在springmvc.xml 中配置一個SimpleUrlHandlerMapping 處理器映射。
實例:
simple-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立SimpleUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <props> <prop key="/hello">simpleController</prop> <!--若是有更多的請求映射就在這邊添加映射配置--> </props> </property> </bean> <!--2.建立Controller對象--> <bean id="simpleController" class="com.self.controller.SimpleController"/> <!--每一個請求Controller或者說Handler就要配置一個bean對象--> <!-- 3.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 3.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 3.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> </beans>
web.xml
<init-param> <param-name>contextConfigLocation</param-name> <!--<param-value>WEB-INF/hellospringmvc-servlet.xml</param-value>--> <param-value>WEB-INF/simple-servlet.xml</param-value> </init-param>
SimpleController
//實現org.springframework.web.servlet.mvc.Controller接口的handleRequest方法 public class SimpleController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("----------SimpleController-----handleRequest---------------"); ModelAndView mv = new ModelAndView("success"); return mv; } }
pom.xml
<!--servlet依賴--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
報錯:
一、@Override is not allowed when implementing interface method
A:這是由於idea的java編譯設置中設置的是jdk1.5的,跟編譯器版本問題有關。編譯器1.5只支持@Override註釋重寫父類方法,不支持實現接口方法。將language level設置高於jdk1.5版本便可 。
參考
2)BeanNameUrlHandlerMapping
BeanNameUrlHandlerMapping 將收到的Http請求映射到bean的名字上。
示例:
beanname-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立Controller對象,這裏的id必須頁面訪問的路徑(以斜槓開頭)--> <!--若是要繼續添加映射只要在這裏配置好映射路徑和註冊bean便可--> <bean id="/hello" class="com.self.BeanNameController"/> <!-- 3.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 3.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 3.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> </beans> //實現org.springframework.web.servlet.mvc.Controller接口的handleRequest方法 public class BeanNameController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("----------BeanNameController-----handleRequest---------------"); ModelAndView mv = new ModelAndView("success"); return mv; } }
pom.xml
<!--servlet依賴--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
web.xml
<init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/beanname-servlet.xml</param-value> <!--<param-value>WEB-INF/hellospringmvc-servlet.xml</param-value>--> </init-param>
請求:http://localhost:8080/hellospringmvc/hello
注意:在bean的id中要加上斜杆,Controller的代碼跟前面的SimpleUrlHandlerMapping同樣,實現Controller,重寫handlerRequest()方法便可。
在默認狀況下,若是沒有在上下文中沒有找處處理器映射,DispactherServlet 會爲你建立一個BeanNameUrlHandlerMapping。
3)RequestMappingHandlerMapping
RequestMappingHandlerMapping是三個中最經常使用的HandlerMapping,由於註解方式比較通俗易懂,代碼界面清晰,只須要在代碼前加上@RequestMapping()的相關注釋就能夠了 。
實例:
@Controller public class HelloController { //@RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
hellospringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.掃描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.開啓mvc註解驅動--> <!--不添加也能使用,高版本spring已經默認實現了。 在Spring中通常採用@RequestMapping註解來完成映射關係,要想使@RequestMapping註解生效必須向上下文中註冊DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例,這兩個實例分別在類級別和方法級別處理。而<mvc:annotation-driven/>配置幫助咱們自動完成上述兩個實例的注入。 --> <!--<mvc:annotation-driven/>--> </beans>
注意:重點是添加mvc:annotation-driven/標籤! 這個要在有其餘HandlerMapping接口的狀況下才須要。
處理適配器
處理器適配器做用
HandlerAdapter字面上的意思就是處理適配器,它的做用就是調用具體的方法對用戶發來的請求來進行處理。當HandlerMapping獲取到執行請求的Controller時,DispatcherServlte會根據Controller對應的Controller類型來調用相應的HandlerAdapter來進行處理。
HandlerAdapter的實現有:
1)HttpRequestHandlerAdapter
HttpRequestHandlerAdapter能夠處理類型爲HttpRequestHandler的handler,對handler的處理是調用HttpRequestHandler的handleRequest()方法。
示例:
public class HttpRequestHandlerController implements HttpRequestHandler{ @Override public void handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { //HttpRequestHandlerAdapter用來處理HttpRequestHandler類型的Controller //注意該類型Controller都沒有ModelAndView,至關於servlet httpServletResponse.getWriter().write("Hello HttpRequestHandler."); } }
httprequesthandler-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立HttpRequestHandlerAdapter,用來處理HttpRequestHandler類型的Controller--> <bean class="org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter"/> <!--3.建立Controller對象,這裏的id必須頁面訪問的路徑(以斜槓開頭)--> <!--若是要繼續添加映射只要在這裏配置好映射路徑和註冊bean便可--> <bean id="/hi" class="com.self.HttpRequestHandlerController"/> </beans>
輸出:
報錯:The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler 。
A:這是由於建立HttpRequestHandlerAdapter,用來處理HttpRequestHandler類型的Controller,而public class BeanNameController implements Controller 不是HttpRequestHandler類型的Controller,處理不了,因此報錯,應該換上合適的HandlerAdapter,如RequestMappingHandlerAdapter。
2)SimpleServletHandlerAdapter
SimpleServletHandlerAdapter能夠處理類型爲Servlet,就是把Servlet當作Controller來處理,使用Servlet的service方法處理用戶請求。 業務Controller繼承HttpServlet 實現doGet()或doPost()方法。
示例:
public class SimpleServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //SimpleServletHandlerAdapter用來處理HttpServlet類型的Controller resp.getWriter().write("Hello HttpServlet."); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } }
httpservletHandler-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立SimpleServletHandlerAdapter--> <bean class="org.springframework.web.servlet.handler.SimpleServletHandlerAdapter"/> <!--3.建立Controller對象,這裏的id必須頁面訪問的路徑(以斜槓開頭)--> <!--若是要繼續添加映射只要在這裏配置好映射路徑和註冊bean便可--> <bean id="/hi" class="com.self.SimpleServlet"/> </beans>
輸出:
3)SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter能夠處理類爲Controller的控制器,使用Controller的handlerRequest方法處理用戶請求。
beanname-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--1.建立BeanNameUrlHandlerMapping--> <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> <!--2.建立Controller對象,這裏的id必須頁面訪問的路徑(以斜槓開頭)--> <!--若是要繼續添加映射只要在這裏配置好映射路徑和註冊bean便可--> <bean id="/hi" class="com.self.BeanNameController"/> <!-- 3.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 3.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 3.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> <!--默認不配置SimpleControllerHandlerAdapter, 也能處理Controller類型爲org.springframework.web.servlet.mvc.Controller的接口, SimpleControllerHandlerAdapter會默認註冊--> <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> </beans> //實現org.springframework.web.servlet.mvc.Controller接口的handleRequest方法 public class BeanNameController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { System.out.println("----------BeanNameController-----handleRequest---------------"); ModelAndView mv = new ModelAndView("success"); return mv; } }
4)RequestMappingHandlerAdapter
RequestMappingHandlerAdapter能夠處理類型爲HandlerMethod的控制器,經過Java反射調用HandlerMethod的方法來處理用戶請求。
補充:類型爲HandlerMethod的控制器是在容器初始化時,經過RequestMappingHandlerMapping在添加映射時把咱們寫業務Controller轉化爲HandlerMethod類型,存儲在LinkedHashMap中。
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#registerHandlerMethod org.springframework.web.servlet.handler.AbstractHandlerMethodMapping#createHandlerMethod
注意:
若是有在web.xml中配置指定的HandlerMapping 和 HandlerAdapter 的話,則只註冊配置的處理器。
示例:
hellospringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.掃描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--2.建立RequestMappingHandlerMapping--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/> <!--3.建立RequestMappingHandlerAdapter--> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/> <!-- 4.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 4.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 4.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> </beans> @Controller public class HelloController { @RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
視圖解析器
視圖解析器做用
Spring MVC中的視圖解析器的主要做用就是將邏輯視圖轉換成用戶能夠看到的物理視圖。
流轉邏輯:
當用戶對SpringMVC應用程序發起請求時,這些請求都會被Spring MVC的DispatcherServlet處理,經過處理器找到最爲合適的HandlerMapping定義的請求映射中最爲合適的映射,而後經過HandlerMapping找到相對應的Handler,而後再經過相對應的HandlerAdapter處理該Handler。返回結果是一個ModelAndView對象,當該ModelAndView對象中不包含真正的視圖,而是一個邏輯視圖路徑的時候,ViewResolver就會把該邏輯視圖路徑解析爲真正的View視圖對象,而後經過View的渲染,將最終結果返回給用戶。
SpringMVC中處理視圖最終要的兩個接口就是ViewResolver和View,ViewResolver的做用是將邏輯視圖解析成物理視圖,View的主要做用是調用其render()方法將物理視圖進行渲染。
常見的視圖解析器
如下爲Spring MVC提供常見視圖解析器:
視圖類型 說明
BeanNameViewResolver 將邏輯視圖名稱解析爲一個Bean,Bean的Id等於邏輯視圖名
InternalResourceViewResolver 將視圖名解析爲一個URL文件,通常使用該解析器將視圖名映射爲一個保存在WEB-INF目錄下的程序文件,如 JSP
JaperReportsViewResolver JapserReports是基於Java的開源報表工具,該解析器解析爲報表文件對應的URL
FreeMarkerViewResolver 解析爲基於FreeMarker模板的模板文件
VelocityViewResolver 解析爲Velocity模板技術的模板文件
VelocityLayoutViewResolver 解析爲Velocity模板技術的模板文件
其中,最經常使用的是InternalResourceViewResolver,配置以下:
<!-- 4.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 4.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 4.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean>
Spring MVC 核心源碼分析
DispathcerServlet屬性配置
Spring MVC核心包裏面有一個配置文件:DispathcerServlet.properties
E:/localwarehouse/org/springframework/spring-webmvc/5.0.2.RELEASE/spring-webmvc-5.0.2.RELEASE.jar!/org/springframework/web/servlet/DispatcherServlet.properties
該配置提供許多的默認組件,這些組件爲Spring MVC的執行提供了支持,其中劃線部分就是咱們以前說到的Spring MVC三大組件。
doDispatch方法源碼追蹤
DispatcherServlet類的層次結構 :
從Spring MVC的執行流程咱們知道,用戶的請求最早到達就是DispatcherServlet,它是Spring MVC的核心,能夠把它叫作中央處理器,所以咱們分析源碼以前,先看看他是什麼樣的流程,經過源碼能夠看出,它是繼承FrameworkServlet,它也是Spring MVC提供的類,繼續往下繼承關係看,FrameworkServlet繼承HttpServletBean,它是Spring提供的類,最終直到到它繼承HttpServlet。
DispathcerServlet既然是Servlet,那麼它確定有一個service方法(Servlet最核心的方法),咱們看這個方法在哪裏實現的,一個個看,發現HttpServletBean並無,在FrameworkServlet中,所以Spring實現這個serivice方法在這裏實現的。
serivice()方法的做用的就是獲得客戶端的請求,而後判斷這個請求是否是PATCH請求方式,若是不是就調用父類(HttpServlet)中的service方法,咱們調用父類這個service方法其實實際是調用該類的doGet方法或者doPost方法等等,拿到不一樣的請求方式處理不一樣的業務,咱們以get方式爲例:
進入到processRequest方法,直接進入doService方法.跳到DispatcherServlet這個類裏面來了,其實doSerivice能夠猜到被子類各類重寫 。
到此爲止,咱們知道DispatcherServlet做爲Spring MVC的核心控制器,把用戶請求最終轉到了它裏面的doDispatch()方法來完成具體工做。
處理器映射器核心源碼
在doDispathcer方法裏面,首先是建立一個ModelAndView對象 = null,判斷當前請求是否是二進制(文件上傳)的請求。
processedRequest = this.checkMultipart(request)
再往下看代碼:
mappedHandler = this.getHandler(processedRequest);
這句代碼很是重要!這是根據當前請求去拿一個Handler(控制器),這個Handler其實就是咱們寫的Controller類,進入到getHandler方法的源碼:
有個handlerMappings的List集合,該集合存儲了當前環境全部HandlerMapping對象,經過遍歷該List集合,經過最合適的HandlerMapping找到Handler對象。
找到了Handler對象後,返回的是一個HandlerExecutionChain類型的Handle,這裏面封裝了一個HelloController,也就是咱們本身的建立Controlller,若是有配置攔截器,還會使用一個interceptors集合封裝全部攔截器。
處理器適配器核心源碼
doDispatcher方法咱們往下看,會到如下代碼:
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
Spring MVC會根據當前環境的配置和代碼去選擇一個合適的HandlerAdapter實現類來執行Handler。
最後,handler方法會返回ModelAndView對象。該對象交給給後面的視圖解析器解析處理。
視圖解析器核心源碼
回到DispathcerServlet的doDispatcher方法,咱們往下走,看到這行代碼:
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
這行代碼包含了Spring MVC獲取對應的View以及選擇合適的ViewResolver解析視圖的邏輯。
@RequestMapping註解
@RequestMapping是一個用來處理請求地址映射的註解,可用於類或方法上。用於類上,表示類中的全部響應請求的方法都是以該地址做爲父路徑。
@RequestMapping經常使用屬性
value屬性
指定控制器的方法URI 。
若是類和方法上都指定value值,那麼方法的最終方法路徑爲:http://localhost:8080/hellospringmvc/say/hello
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping("/hello") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
method屬性
指定請求的method類型,能夠接受GET,POST,PUT,DELETE等.
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping(value = "/hello",method = RequestMethod.GET) public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; } }
注意:當註解有兩個值時,就要有鍵值對對應關係,不能使用默認的值。
@RequestMapping("/hello") //註解有兩個值時使用下面的寫法 @RequestMapping(value = "/hello",method = RequestMethod.GET)
consumes、produces屬性
consumes:指定處理請求的提交內容類型(Content-Type),例如application/json, text/html; produces:指定返回的內容類型,僅當request請求頭中的(Accept)類型中包含該指定類型才返回。
@RequestMapping(value = "/hello.do",consumes = "application/json",produces = "application/json") public void hello(HttpServletRequest request,HttpServletResponse response) throws IOException { response.getWriter().write("Hello-World"); }
報錯:
使用時會報415.The server refused this request because the request entity is in a format not supported by the requested resource for the requested method.
待解決。
params、headers屬性
params:指定request中必須包含某些參數值,才讓該方法處理。
headers:指定request中必須包含某些指定的header值,才能讓該方法處理請求。
params示例:
@RequestMapping(value = "/hello",method = RequestMethod.GET,params = "id=3") public String sayHello() { System.out.println("----------HelloController-----sayHello---------------"); //return "Hello Spring MVP"; return "success"; }
輸出:
headers示例:
@RequestMapping(value = "/hello.do",headers = "Referer=http://www.hello.com/") public void hello(HttpServletRequest request,HttpServletResponse response) throws IOException { response.getWriter().write("Hello"); }
Spring MVC支持對多種類型的請求參數進行封裝
Spring MVC 基本類型封裝
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本類型參數封裝</h2> <form action="http://localhost:8080/hellospringmvc/say/helloParam"> 用戶名:<input type="text" name="name"><br> 年齡:<input type="text" name="age"><br> <input type="submit" value="提交"> </form> </body> </html> @RequestMapping("/helloParam") public String helloParam(String name, Integer age) { System.out.println("用戶名:" + name); System.out.println("年齡:" + age); return "success"; }
輸出:
用戶名:惡龍吟風 年齡:null ------------------------------ 用戶名:惡龍吟風 年齡:365 ------------------------------- 用戶名: 年齡:365
注意:
當接收的基本類型參數不是包裝類時,如 int age,這時候要求age必須有值傳進來,不然報錯HTTP Status 400 -錯誤。The request sent by the client was syntactically incorrect. 若是是用包裝類接收,如Integer age,則沒有傳值時age = null,String name 沒有值默認空字符串 name=""
Spring MVC Post中文亂碼
在Spring MVC表單若是是Post方法提交中文內容時,會出現亂碼 。
這是咱們能夠配置Spring MVC提供字符編碼過濾器來解決問題。
配置字符編碼過濾器
web.xml
<!--字符編碼過濾器--> <!-- 字符編碼過濾器的配置效果是當咱們沒有指定請求響應的編碼格式時,該字符編碼過濾器會 默認以配置的編碼格式去解碼和編碼,如配置的是utf-8--> <filter> <filter-name>characterEncodingFilter</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> <!-- 下面配置是否強制設置編碼格式爲指定的轉換編碼格式:utf-8 若是強制,則因此的請求響應都會按照utf-8來解碼和編碼,當請求的格式是GBK等其餘編碼時, 就會所以而亂碼,因此通常是不配置這個選項的。 <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param>--> </filter> <filter-mapping> <filter-name>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
@RequestParam註解
在SpringMvc後臺進行獲取數據,通常有三種:
其實能夠不使用@RequestParam註解,直接接收,若是不使用該註解要求controller方法中的參數名稱要跟form中name名稱一致,使用該註解只是方便隨意取參數名稱,不過value屬性仍是要與name一致,該註解只適合一些任性的盆友使用 。
使用
@RequestParam做用:將請求參數綁定到你控制器的方法參數上(是springmvc中接收普通參數的註解) 。
在使用SpringMVC接收基本參數類型的時候,咱們發現若是控制器中形參的名稱與表單的name名稱不一致時,沒法接收參數。這是可使用@RequestParam註解解決這個問題。
注意:頁面表單的name和控制器的形參(方法參數)並不一致,可是@RequestParam註解的value值(即接收請求參數的名稱)必須和頁面表單的name保持一致。不然就接收不到參數。
@RequestParam裏name和value的區別:沒有區別。源碼註解的意思就是name的別名是value,value的別名是name。兩者皆可,而且開發中兩個都能得到參數,得到同樣的結果。
@RequestParam註解還有兩個屬性:
實例:
@RequestMapping(value ="/requestParam",method = RequestMethod.GET) public String requestParam(@RequestParam("userName") String name, @RequestParam("userAge")Integer userAge) { System.out.println("用戶名:" + name); System.out.println("年齡:" + userAge); return "success"; } /** * * @param name 默認defaultValue= "大青山",required = true失效,爲false * @param userAge value = "userAge" ,required = false 能夠不傳,不傳時爲null * @return */ @RequestMapping(value ="/requestParam1",method = RequestMethod.GET) public String requestParam1(@RequestParam(value = "userName" ,required = true,defaultValue = "大青山") String name, @RequestParam(value = "userAge" ,required = false)Integer userAge) { System.out.println("用戶名:" + name); System.out.println("年齡:" + userAge); return "success"; }
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本類型參數封裝</h2> <form action="http://localhost:8080/hellospringmvc/say/requestParam1"> 用戶名:<input type="text" name="userName"><br> 年齡:<input type="text" name="userAge"><br> <input type="submit" value="提交"> </form> </body> </html>
Spring MVC Pojo參數封裝
以前咱們接收參數的時候都是定義一個個的基本類型來接收,這樣比較繁瑣,Spring MVC提供了使用Pojo(或者稱爲JavaBean)類型來封裝請求參數。
實例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本類型參數封裝</h2> <%--設置請求類型爲post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamPojo" method="post"> 用戶名:<input type="text" name="userName"><br> 年齡:<input type="text" name="userAge"><br> <input type="submit" value="提交"> </form> </body> </html> /** * method = RequestMethod.POST 能夠不標記,不標記就都能匹配 * @param user * @return */ @RequestMapping(value ="/helloParamPojo" ,method = RequestMethod.POST) public String helloParamPojo(User user) { System.out.println("用戶名:" + user.getUserName()); System.out.println("年齡:" + user.getUserAge()); return "success"; } public class User { private String userName; private Integer userAge; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Integer getUserAge() { return userAge; } public void setUserAge(Integer userAge) { this.userAge = userAge; } }
Spring MVC 包裝參數封裝——Pojo嵌套Pojo對象
在Spring MVC的應用過程當中,咱們在後端通過須要將表單數據封裝在一個包裝Pojo類型中,所謂包裝Pojo類型,就是Pojo對象中包含另外一個Pojo對象。
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本類型參數封裝</h2> <%--設置請求類型爲post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamPojos" method="post"> 用戶名:<input type="text" name="userName"><br> 年齡:<input type="text" name="userAge"><br> <%--封裝用戶的地址信息,name爲address.province這種寫法,這表明把數據封裝到User對象->Address對象的province屬性中。--%> 省份:<input type="text" name="address.province"><br> 城市:<input type="text" name="address.city"><br> <input type="submit" value="提交"> </form> </body> </html> public class User { private String userName; private Integer userAge; private Address address; //...... } public class Address { private String province; private String city; //...... } @RequestMapping(value ="/helloParamPojos" ,method = RequestMethod.POST) public String helloParamPojos(User user) { System.out.println("用戶名:" + user.getUserName()); System.out.println("年齡:" + user.getUserAge()); System.out.println("省份:"+user.getAddress().getProvince()); System.out.println("城市:"+user.getAddress().getCity()); return "success"; }
輸出:
用戶名:艾米 年齡:18 省份:艾米帝國 城市:帝都
Spring MVC List集合參數封裝
咱們是一個Address對象來接收一個地址信息,若是有多個地址信息怎麼呢?這時咱們可使用List集合來封裝。
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本類型參數封裝</h2> <%--設置請求類型爲post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamList" method="post"> 用戶名:<input type="text" name="userName"><br> 年齡:<input type="text" name="userAge"><br> <%--address[0].province,表明給User對象->List<Address>集合->第一個Address對象的province屬性賦值--%> 省份1:<input type="text" name="address[0].province"><br> 城市1:<input type="text" name="address[0].city"><br> 省份2:<input type="text" name="address[1].province"><br> 城市2:<input type="text" name="address[1].city"><br> <input type="submit" value="提交"> </form> </body> </html> public class User { private String userName; private Integer userAge; private List<Address> address; //...... } @RequestMapping(value ="/helloParamList" ,method = RequestMethod.POST) public String helloParamList(User user) { System.out.println("用戶名:" + user.getUserName()); System.out.println("年齡:" + user.getUserAge()); List<Address> address = user.getAddress(); for (Address addressTemp : address) { System.out.println("省份:"+addressTemp.getProvince()); System.out.println("城市:"+addressTemp.getCity()); } return "success"; } 用戶名:許三多 年齡:25 省份:上海 城市:魔都 省份:北京 城市:帝都
Spring MVC Map集合參數封裝
咱們利用List集合來封裝多個地址信息,其實把List集合換成Map集合也是能夠的 。
示例:
index.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC</title> </head> <body> <h2>基本類型參數封裝</h2> <%--設置請求類型爲post--%> <form action="http://localhost:8080/hellospringmvc/say/helloParamMap" method="post"> 用戶名:<input type="text" name="userName"><br> 年齡:<input type="text" name="userAge"><br> <%--這裏的address['a1'].city,a1是賦值給Map的key,city是賦值給Address的city屬性--%> 省份1:<input type="text" name="address['a1'].province"><br> 城市1:<input type="text" name="address['a1'].city"><br> 省份2:<input type="text" name="address['a2'].province"><br> 城市2:<input type="text" name="address['a2'].city"><br> <input type="submit" value="提交"> </form> </body> </html>
注意:這裏的address['a1'].city,a1是賦值給Map的key,city是賦值給Address的city屬性 .
@RequestMapping(value ="/helloParamMap" ,method = RequestMethod.POST) public String helloParamMap(User user) { System.out.println("用戶名:" + user.getUserName()); System.out.println("年齡:" + user.getUserAge()); Map<String, Address> addressMap = user.getAddress(); Set<Map.Entry<String, Address>> entries = addressMap.entrySet(); for (Map.Entry<String, Address> entry : entries) { System.out.println(entry.getKey()+"--"+JSON.toJSONString(entry.getValue())); } return "success"; } public class User { private String userName; private Integer userAge; private Map<String,Address> address; //...... } 用戶名:艾米 年齡:18 a1--{"city":"深圳","province":"粵"} a2--{"city":"金門","province":"閩"}
Spring MVC 自定義類型轉換
Spring MVC默認狀況下能夠對基本類型進行類型轉換,例如能夠將String轉換爲Integer,Double,Float等。可是Spring MVC並不能轉換日期類型(java.util.Date),若是但願把字符串參數轉換爲日期類型,必須自定義類型轉換器。接下來說解如何自定義類型轉換器。
//通常項目不會用上
Spring MVC 使用Servlet API
在Spring MVC應用中,咱們也常常須要使用到原生的Servlet API來知足功能的開發需求。接下來介紹如何在Spring MVC中使用Servlet 相關API。
實例:
@RequestMapping("/leap") public void leap(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException { request.setAttribute("request","take leap of faith"); session.setAttribute("session","take leap of faith"); response.sendRedirect("/hellospringmvc/say/hello"); }
@RequestHeader註解
Spring MVC提供@RequestHeader註解方便咱們獲取請求頭信息。
示例:
@RequestMapping(value ="/helloHeader") public String helloHeader(@RequestHeader("host") String host, @RequestHeader("accept") String accept) { System.out.println("host---"+host); System.out.println("accept---"+accept); return "success"; }
輸出:
host---localhost:8080 accept---text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
@CookieValue註解
Spring MVC提供@CookieValue方便咱們獲取指定Cookie數據。
示例:
@RequestMapping(value ="/helloCookie") public String helloHeader(@CookieValue("JSESSIONID") String sessionId) { System.out.println("JSESSIONID---"+sessionId); return "success"; }
Spring MVC 靜態資源訪問
沒法訪問靜態資源的緣由
當Spring MVC配置的攔截路徑爲 / 或 /* 的時候,咱們項目會沒法訪問靜態資源文件,如:
springmvc.xml配置:
<servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
三種Spring MVC訪問靜態資源的方案
一、經過Tomcat的DefaultServlet配置訪問靜態資源。
在咱們應用的web.xml從新配置DefaultServlet的映射路徑,讓其對特定的靜態資源進行處理。
首先,咱們要明白在Spring MVC應用之因此訪問不了靜態資源,是由於咱們配置的DispathcerServlet映射路徑覆蓋了Tomcat的DefaultServlet的映射路徑。
Tomcat的DefaultServlet配置,在Tomcat根目錄的conf/web.xml
實現方式,在項目的web.xml配置:
<!--從新配置Tomcat的DefaultServlet的映射路徑--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> <url-pattern>*.gif</url-pattern> </servlet-mapping>
二、經過mvc:resources/標籤,把頁面的不一樣請求,轉發到項目內部的某個目錄下
Spring MVC提供了mvc:resources/標籤,該標籤的做用能夠把頁面的不一樣請求,轉發到項目內部的某個目錄下。該標籤配置在hellospringmvc-servlet.xml文件下。 <!--靜態資源處理--> <mvc:resources mapping="/images/**" location="/images/"/> <mvc:resources mapping="/css/**" location="/css/"/> <mvc:resources mapping="/js/**" location="/js/"/>
mapping:表明映射頁面的訪問路徑。
location:表明項目內的具體的物理路徑地址。
三、經過mvc:default-servlet-handler/把全部靜態資源目錄的文件對外映射出去。
第二種方案的使用比較繁瑣,由於須要一個個目錄進行配置,其實有一個更加方便的標籤: mvc:default-servlet-handler/,該標籤至關於一次幫助咱們把全部靜態資源目錄的文件對外映射出去。該標籤配置在hellospringmvc-servlet.xml文件下。 <!--靜態資源處理--> <mvc:default-servlet-handler/>
Model與ModelMap
Spring MVC應用中,咱們常常須要在Controller將數據傳遞到JSP頁面,除了能夠經過HttpServletRequest域傳遞外,Spring MVC還提供了兩個Api,分別爲Model接口和ModelMap類。
Model與ModelMap的關係
Model接口和ModelMap類都有一個共同的子類:BindingAwareModelMap 。而BindingAwareModelMap底層實際上是往HttpServletRequest域存入數據,因此Model接口或者ModelMap的底層也是往request域存入數據!
示例:
show.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>show page</title> </head> <body> <%--能夠直接取也能夠經過requestScope取值--%> <%--獲取Model數據-${requestScope.question}--%> 獲取Model數據-${question} <hr/> 獲取ModelMap數據-${requestScope.answer} </body> </html> @Controller public class ModelController { @RequestMapping("/helloModel") public String helloModel(Model model){ model.addAttribute("question","what do you want?"); return "show"; } @RequestMapping("/helloModelMap") public String helloModelMap(ModelMap modelMap){ modelMap.addAttribute("answer","I want my phone call!"); return "show"; } }
輸出:
@ModelAttribute註解
@ModelAttribute做用
@ModelAttribute註解的做用,將請求參數綁定到Model對象。被@ModelAttribute註釋的方法會在Controller每一個方法執行前被執行(若是在一個Controller映射到多個URL時,要謹慎使用)。
@ModelAttribute註解的使用總結
@ModelAttribute使用位置
在SpringMVC的Controller中使用@ModelAttribute時,其位置包括下面三種:
一、應用在方法上
用在無返回值的方法
在model方法以前會執行setAttribute()方法。所以在setAttribute()方法中,請求傳遞的name參數存入Model對象,該參數值也會隨着model方法帶到JSP頁面中。
實例:
result.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>@ModelAttribute註解的使用</title> </head> <body> ${name} </body> </html> @Controller public class ModelAttributeController { @ModelAttribute public void setAttribute(@RequestParam(value = "userName",required = false) String name, Model model){ model.addAttribute("name",name); } @RequestMapping("/result") public String result(){ return "result"; } }
請求:<http://localhost:8080/hellospringmvc/result?userName=艾米
輸出:
用在帶返回值的方法
帶有返回值的狀況,其實就是自動把方法返回值存入Model對象,@ModelAttribute的value屬性就是Model的key。至關於
model.addAttribute("name",name);
示例:
@Controller public class ModelAttributeController { @ModelAttribute("name") public String setAttribute(@RequestParam(value = "userName",required = false) String name){ return name; } @RequestMapping("/result") public String result(){ return "result"; } }
二、應用在方法的參數上
@ModelAttribute註解應用在方法的參數上,其實就是從Model對象中取出對應的屬性值。
示例:
@Controller public class ModelAttributeController { @ModelAttribute("name") public String setAttribute(@RequestParam(value = "userName",required = false) String name){ return name; } @RequestMapping("/resultPara") public String resultPara(@ModelAttribute("name") String name){ System.out.println("name="+name); return "result"; } }
方法上+@RequestMapping
@ModelAttribute和@RequestMapping同時應用在方法上的時候,有兩層意義:
示例:這種使用方式請求的時候是經過其餘方法調用進來的。
@RequestMapping("/result") @ModelAttribute("name") public String resultMapping(@RequestParam(value = "userName",required = false) String name){ System.out.println("name="+name); return name; }
@SessionAttributes註解
通常不用這個註解,範圍太廣,有其餘代替方法,最簡單的就是用個redis緩存。
@SessionAttributes做用
默認狀況下Spring MVC將模型中的數據存儲到request域中。當一個請求結束後,數據就失效了。若是要跨頁面使用。那麼須要使用到session。而@SessionAttributes註解就可使得模型中的數據存儲一份到session域中。
注意:@SessionAttributes註解只能用在類上!
@SessionAttributes屬性:
示例:
@Controller @SessionAttributes(names = "name",types = String.class) public class SessionAttributeController { @RequestMapping("/showSession") public String showSession(Model model,String name){ model.addAttribute("name",name); return "sessionResult"; } }
sessionResult.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>@SessionAttributes註解的使用</title> </head> <body> request:${requestScope.name}<br/> session:${sessionScope.name}<br/> </body> </html>
輸出:
Spring MVC 控制器返回值
Spring MVC的控制器方法返回值能夠支持多種寫法,每種寫法的場景和效果都不同。下面分別來看看每種返回值的使用。
普通字符串——jsp頁面地址+頁面名稱
返回普通字符串這種狀況比較常見,主要用在咱們處理完業務邏輯後,須要跳轉到應用的其餘頁面。
只能轉發到視圖解析器指定的特定目錄。
/** * 1)字符串 - 普通字符串(表明頁面名稱,不是完整路徑,最後通過視圖解析器的解析) * 優點:寫法簡單 * 劣勢:只能轉發到視圖解析器指定的特定目錄 */ @RequestMapping("/hello") public String sayHello() { return "success"; }
轉發字符串
普通字符串,只能轉發到視圖解析器指定前綴的目錄下的頁面,若是想轉發到視圖解析器目錄之外的頁面,這時可使用轉發字符串的寫法。
forward:完整頁面的路徑 。
示例:能夠傳遞request域對象數據
/** * 2)字符串 - 轉發字符串 * 轉發字符串格式: * forward:完整頁面的路徑 例如:forward:/pages/index.jsp * * 優點:更加靈活,能夠轉到本項目下的任何頁面,能夠傳遞request域對象數據 * 劣勢:寫法稍複雜 */ @RequestMapping("/forward") public String forward(){ return "forward:/index.jsp"; }
重定向字符串
若是但願使用重定向的方式跳轉頁面,這時可使用重定向字符串完成。
示例:不能轉發reques域對象數據
/** * 3)字符串 - 重定向字符串 * 重定向字符串格式: * redirect:完整頁面的路徑 例如:redirect:/pages/index.jsp * * 優點:很靈活,能夠重定向到項目內和項目之外的頁面 * 劣勢:寫法稍複雜,不能轉發reques域對象數據 */ @RequestMapping("/redirect") public String redirect(){ return "redirect:http://www.baidu.com"; }
返回空
通常咱們在文件下載的時候,就不須要控制器方法返回任何內容,因此設置爲void便可。
示例:
/** * 4)返回void * 用於文件下載 */ @RequestMapping("/download") public void download(HttpServletResponse response) { //模擬文件下載 //1.讀取須要下載的文件 File file = new File("e:/car.jpg"); //2.構建文件輸入流 try (InputStream in = new FileInputStream(file); OutputStream out = response.getOutputStream()) { //4.邊讀邊寫 byte[] buf = new byte[1024]; int len = 0; while ((len = in.read(buf)) != -1) { out.write(buf, 0, len); } } catch (Exception e) { e.printStackTrace(); } return; }
ModelAndView
Spring MVC提供了ModelAndView對象,該對象既能夠存儲數據到request域,也能夠設置視圖。其實Spring MVC任何處理器適配器最終執行完控制器後,都會返回ModelAndView對象。因此這是一個比較底層的對象。
示例:
@RequestMapping("/mv") public ModelAndView mv(){ ModelAndView mv = new ModelAndView(); //設置模型數據 值attributeValue能夠是任何對象Object mv.addObject("name","池寒楓"); //設置視圖數據 //設置viewName表明頁面名稱,不是完整路徑,最後通過視圖解析器的解析 mv.setViewName("result"); return mv; }
輸出:
返回Java對象
這裏返回的Java對象,多是普通JavaBean,也能夠是List或Map集合等。通常但願把控制器的返回Java對象轉換爲Json字符串,才須要返回Java對象。
Spring MVC JSON數據轉換
場景:
在開發中後端常常須要接受來自於前端傳遞的Json字符串數據並把把Json字符串轉換爲Java對象 。
後端也常常須要給前端把Java對象數據轉換爲Json字符串返回 。
辦法:
使用@RequestBody和@ResponseBody註解。
Spring MVC默認是沒法實現Json數據轉換功能的,須要額外導入fastjson包來支持Json數據轉換。
編寫JsonController,這裏用到兩個關鍵註解@RequestBody和@ResponseBody。
示例:
<!-- 平時處理json用的 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.29</version> </dependency> <!-- jackson支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> @Controller public class JsonController { @RequestMapping("/json") @ResponseBody public MercenaryUser showJson(@RequestBody MercenaryUser user){ System.out.println("前端發送的數據:"+ JSON.toJSONString(user)); //後臺返回json字符串給前端 user.setId(1); user.setName("艾米"); user.setAge(20); user.setRide("冥牙"); return user; } @RequestMapping("/toJson") public String toJson(){ return "json"; } }
json.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>JSON格式轉換</title> <%--使用jQuery實現ajax異步請求後端Controller,同時發送Json字符串對象--%> <%--<script src="/hellospringmvc/js/jquery-1.7.1.min.js"></script>--%> <%--CDN--%> <script src="http://code.jquery.com/jquery-1.12.0.min.js"></script> </head> <body> <script> //頁面加載完畢 $(function () { //點擊按鈕,發送post請求,傳遞json參數 $("#btn").click(function () { $.ajax({ //設置請求類型 type: 'post', //請求路徑 url: 'http://localhost:8080/hellospringmvc/json', //傳遞json參數 data: '{"id":3,"name":"池傲天","age":21,"ride":"DeathDragon"}', //指定參數類型(若是json參數格式,必須設置爲json類型) contentType: 'application/json;charset=utf-8', //該方法接收後臺返回的數據格式 dataType: 'json', //處理方法 success: function (result) { alert(result.id + '--' + result.name + '--' + result.age + '--' + result.ride); } }); }); }); </script> <input type="button" value="Json字符串與Java對象轉換" id="btn"> </body> </html> public class MercenaryUser { private Integer id; private String name; private Integer age; private String ride; //... }
hellospringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.掃描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 4.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 4.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 4.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.開啓mvc註解驅動--> <!-- 3.建立處理器適配器和處理器映射器--> <!--在Spring中通常採用@RequestMapping註解來完成映射關係, 要想使@RequestMapping註解生效必須向上下文中註冊DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例, 這兩個實例分別在類級別和方法級別處理。而<mvc:annotation-driven/>配置幫助咱們自動完成上述兩個實例的注入。 --> <mvc:annotation-driven/> <!--靜態資源處理--> <!--該標籤至關於一次幫助咱們把全部靜態資源目錄的文件對外映射出去。--> <mvc:default-servlet-handler/> </beans>
輸出:
前端發送的數據:{"age":21,"id":3,"name":"池傲天","ride":"DeathDragon"}
報錯:
一、jquery方法執行不了。json請求頁面無響應。
A:首先要引入jquery-1.7.1.min.js 文件,放到項目目錄上,並經過從項目名開始的路徑引用,或者全路徑,從主機路徑開始,不然會找不到js文件,由於咱們沒有設置相對路徑。 <%--使用jQuery實現ajax異步請求後端Controller,同時發送Json字符串對象--%> <script src="/hellospringmvc/js/jquery-1.7.1.min.js"></script>
二、發起ajax請求時415報錯——不支持的媒體類型(Unsupported media type)
jquery-1.7.1.min.js:2660 POST http://localhost:8080/hellospringmvc/json 415 ()
A:咱們須要一:在hellospringmvc-servlet.xml中配置開啓mvc註解驅動,該配置會建立處理器適配器和處理器映射器,自動註冊DefaultAnnotationHandlerMapping和AnnotationMethodHandlerAdapter兩個bean。 AnnotationMethodHandlerAdapter將會初始化7個轉換器,能夠經過調用AnnotationMethodHandlerAdapter的getMessageConverts()方法來獲取轉換器的一個集合 List<HttpMessageConverter>。 ByteArrayHttpMessageConverter StringHttpMessageConverter ResourceHttpMessageConverter SourceHttpMessageConverter XmlAwareFormHttpMessageConverter Jaxb2RootElementHttpMessageConverter MappingJacksonHttpMessageConverter 對於json的解析就是經過MappingJacksonHttpMessageConverter轉換器完成的。 二:依賴jackson包,這樣才能經過轉換器+jackson解析json數據,@RequestBody須要。 <!-- jackson支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency>
若是仍是報415錯誤,那多是由於在hellospringmvc-servlet.xml顯式配置的處理器和適配器,致使轉換器沒有初始化出來。要註釋掉。以下:
<!--2.建立RequestMappingHandlerMapping--> <!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"/>--> <!--3.建立RequestMappingHandlerAdapter--> <!--<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"/>-->
參考:使用@RequestBody註解處理json時,報出HTTP Status 415的解決方案
注意:在hellospringmvc-servlet.xml配置中,當咱們配置了靜態資源處理時,就必定要開啓mvc註解驅動,不然咱們請求的處理都會被靜態資源處理器處理了,致使請求的頁面報404請求資源不存在。所以在hellospringmvc-servlet.xml配置中,兩個都是必定要配置的,缺一不可。
<!-- 3.開啓mvc註解驅動--> <!-- 3.建立處理器適配器和處理器映射器--> <!--在Spring中通常採用@RequestMapping註解來完成映射關係, 要想使@RequestMapping註解生效必須向上下文中註冊DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例, 這兩個實例分別在類級別和方法級別處理。而<mvc:annotation-driven/>配置幫助咱們自動完成上述兩個實例的注入。 --> <mvc:annotation-driven/> <!--靜態資源處理--> <!--該標籤至關於一次幫助咱們把全部靜態資源目錄的文件對外映射出去。--> <mvc:default-servlet-handler/>
Spring MVC RESTful風格開發
什麼是RESTful風格?
RESTful,也叫REST(英文: Representational State Transfer, 簡稱 REST) 描述了一個架構樣式的網絡系統,好比 web 應用程序。它首次出如今 2000 年 Roy Fielding 的博士論文中,他是 HTTP 規範的主要編寫者之一。在目前主流的三種 Web 服務交互方案中,REST 相比於SOAP(Simple Object Access protocol, 簡單對象訪問協議) 以及 XML-RPC 更加簡單明瞭, 不管是對 URL 的處理仍是對 Payload 的編碼, REST 都傾向於用更加簡單輕量的方法設計和實現。 值得注意的是 REST 並無一個明確的標準, 而更像是一種設計的風格。REST 其核心價值在於如何設計出符合 REST 風格的網絡接口。 基於這個風格設計的軟件能夠更簡潔, 更有層次, 更易於實現緩存等機制。
簡單地說:使用RESTful風格可讓咱們客戶端與服務端訪問的URL更加簡潔方便!
如下給出兩個例子,前者沒有采用RESTful風格,後者採用RESTful風格。
沒有采用RESTful風格的URL:
採用RESTful風格的URL:
對比發現,RESTful風格更加簡潔,RESTful主要依靠不一樣的請求方法來區分不一樣操做類型,這個與傳統URL最大的區別。
Spring MVC開發RESTful應用
前置條件
爲了在前端模擬出不一樣的請求方式,須要在web.xml引入SpringMVC提供的HiddenHttpMethodFilter,這是個配置請求方式轉換過濾器。
<!-- 轉換請求方式的過濾器 --> <filter> <filter-name>hiddenHttpMethodFilter</filter-name> <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class> </filter> <filter-mapping> <filter-name>hiddenHttpMethodFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
restful.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Spring MVC進行RESTful風格開發</title> </head> <body> <!--增長 --> <form action="/hellospringmvc/rest" method="post"> <input type="submit" value="增長"> </form> <!--查詢 --> <form action="/hellospringmvc/rest" method="get"> <input type="submit" value="查詢"> </form> <!--修改 --> <form action="/hellospringmvc/rest/8" method="post"> <input type="hidden" name="_method" value="put"> <input type="submit" value="修改"> </form> <!--刪除 --> <form action="/hellospringmvc/rest/9" method="post"> <input type="hidden" name="_method" value="delete"> <input type="submit" value="刪除"> </form> </body> </html> @Controller @RequestMapping("/rest") public class RestfulController { @RequestMapping(method = RequestMethod.POST) @ResponseBody public String save() { System.out.println("增長..."); return "success"; } @RequestMapping(method = RequestMethod.GET) @ResponseBody public String get() { System.out.println("查詢..."); return "success"; } /* @RequestMapping(value = "/{id}",method = RequestMethod.POST) @ResponseBody public String update(@PathVariable("id") Integer id){ System.out.println("修改...id="+id); return "success"; }*/ @RequestMapping(value = "/{id}", method = RequestMethod.PUT) @ResponseBody public String update(@PathVariable("id") Integer id) { System.out.println("修改...id=" + id); return "success"; } @RequestMapping(value = "/{id}", method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable("id") Integer id) { System.out.println("刪除...id=" + id); return "success"; } }
注意點:
請求:http://localhost:8080/hellospringmvc/restful.jsp
輸出:
增長... 查詢... 修改...id=8 刪除...id=9
報錯:若是不配置轉換請求方式的過濾器HiddenHttpMethodFilter,請求會報錯。
Spring MVC 文件上傳
文件上傳是表現層常見的需求,在Spring MVC中底層使用Apache的Commons FileUpload工具來完成文件上傳,對其進行封裝,讓開發者使用起來更加方便。
文件上傳須要:
注意:
上傳表單注意:
注意:
這裏使用MultipartFile對象接收文件,並把文件存放在項目的upload目錄下,同時還接收了普通參數。
示例:
pom.xml
<!-- commons-fileUpload --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version> </dependency>
hellospringmvc-servlet.xml
<!-- 配置文件上傳解析器 注意:必須配置id,且名稱必須爲multipartResolver--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置限制文件上傳大小 (字節爲單位)--> <property name="maxUploadSize" value="1024000"/> </bean>
success.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Hello Spring MVP</title> </head> <body> <h1>上傳成功!</h1> </body> </html>
upload.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>文件上傳</title> </head> <body> <h3>SpringMVC方式文件上傳</h3> <form action="/hellospringmvc/upload" method="post" enctype="multipart/form-data"> 選擇文件:<input type="file" name="fileName"> <br/> 文件描述:<input type="text" name="desc"> <br/> <input type="submit" value="上傳"> </form> </body> </html> @Controller public class UploadController { @RequestMapping("/upload") public String upload(HttpServletRequest request, MultipartFile fileName, String desc) { //1.獲取網站的upload目錄的路徑: ServletContext對象 //F:\self\hellospringmvc\target\hellospringmvc-1.0-SNAPSHOT\upload String upload = request.getSession().getServletContext().getRealPath("upload"); ///F:/self/hellospringmvc/target/hellospringmvc-1.0-SNAPSHOT/WEB-INF/classes//upload String upload2 = UploadController.class.getResource("/").getFile()+"/upload"; //判斷該目錄是否存在,不存在,本身建立 File file = new File(upload); if (!file.exists()) { file.mkdir(); } //把文件保存到upload目錄 //2.1 原來的文件名 String originalFilename = fileName.getOriginalFilename(); //2.生成隨機文件名稱 String uuId = UUID.randomUUID().toString(); //2.3 獲取文件後綴 如 .jpg String suffix = originalFilename.substring(originalFilename.lastIndexOf(".")); //2.4 最終的文件名 String newName = uuId + suffix; //3.保存 try { //目標文件傳入地址路徑+名稱 fileName.transferTo(new File(upload + "/" + newName)); } catch (IOException e) { e.printStackTrace(); } System.out.println("文件描述:" + desc); //跳轉到上傳成功頁面 return "success"; } }
請求:http://localhost:8080/hellospringmvc/upload.jsp
輸出:上傳成功。
Spring MVC 文件下載
準備下載的文件
示例:
download.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>文件下載</title> </head> <body> <h3>SpringMVC文件下載</h3> <a href="/hellospringmvc/download">下載</a> </body> </html> @Controller public class DownloadController { @RequestMapping("/download") public void download(HttpSession session, HttpServletRequest request, HttpServletResponse response) throws IOException { //InputStream inputStream = session.getServletContext().getResourceAsStream("/download/template.gif"); InputStream inputStream = request.getSession().getServletContext().getResourceAsStream("/download/template.gif"); //2.輸出文件 //設置響應頭 response.setHeader("Content-Disposition","attachment;filename=template.gif"); OutputStream outputStream = response.getOutputStream(); byte[] buff = new byte[1024]; int lenth = 0; while ((lenth= inputStream.read(buff))!= -1){ outputStream.write(buff,0,lenth); } //3.關閉資源 outputStream.close(); inputStream.close(); } }
請求:http://localhost:8080/hellospringmvc/download.jsp
Spring MVC 攔截器
Spring MVC中的攔截器(Interceptor)相似於Servlet中的過濾器(Filter),它主要用於攔截用戶請求並做相應的處理。例如經過攔截器能夠進行權限驗證、記錄請求信息的日誌、判斷用戶是否登陸,session是否超時等。
要使用Spring MVC中的攔截器,就須要對攔截器類進行定義和配置。
一般攔截器類能夠經過兩種方式來定義:
注意:攔截器配置的順序決定了攔截器的執行順序,先配置會先被執行!
注意:一個攔截器和多個攔截器的執行順序看下圖。
一個攔截器的執行順序:
多個攔截器的執行順序:
示例:
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping(value = "/hello", method = RequestMethod.GET) public String sayHello() { //System.out.println("----------HelloController-----sayHello---------------"); System.out.println("3.目標控制器-HelloController"); return "success"; } } public class FirstInterceptor implements HandlerInterceptor { /** *preHandle: 在控制器(目標)的方法以前被執行 * 返回值:控制afterCompletion方法是否被執行 * true: 執行afterCompletion * false: 不執行afterCompletion */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("1.FirstInterceptor的preHandle"); return true; } /** * postHandle: 在控制器(目標)的方法成功執行完成以後(注意:控制器方法失敗不執行) */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("5.FirstInterceptor的postHandle"); } /** * afterCompletion: 在執行完前面全部(攔截器和目標)的方法以後執行(注意: 無論控制器方法執行成功與否都會被執行 ) */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("7.FirstInterceptor的afterCompletion"); } } public class SecondInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("2.SecondInterceptor的preHandle"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("4.SecondInterceptor的postHandle"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("6.SecondInterceptor的afterCompletion"); } }
hellospringmvc-servlet.xml
<!--配置攔截器 :攔截器配置的順序決定了攔截器的執行順序,先配置會先被執行!--> <mvc:interceptors> <mvc:interceptor> <!--要攔截請求路徑--> <mvc:mapping path="/**/*"/> <bean class="com.self.interceptor.FirstInterceptor"/> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/say/hello"/> <!--若是隻這麼寫就是隻攔截路徑爲/hello的,上面的/say/hello是不會被攔截的--> <mvc:mapping path="/hello"/> <bean class="com.self.interceptor.SecondInterceptor"/> </mvc:interceptor> </mvc:interceptors>
請求:http://localhost:8080/hellospringmvc/say/hello
輸出:
1.FirstInterceptor的preHandle 2.SecondInterceptor的preHandle 3.目標控制器-HelloController 4.SecondInterceptor的postHandle 5.FirstInterceptor的postHandle 6.SecondInterceptor的afterCompletion 7.FirstInterceptor的afterCompletion
登陸超時攔截器:
public class RequestSessionTimeOutInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { try{ String uri = request.getRequestURI(); if(uri == null){ return true; } HttpSession session = request.getSession(); if (null == session) { //401:HTTP401錯誤表明用戶沒有訪問權限,須要進行身份認證 response.sendError(HttpServletResponse.SC_UNAUTHORIZED); return false; } return true; } catch (Exception e){ //異常狀況不攔截 logger.error("攔截器配置失敗",e); return true; } } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
Spring MVC 異常處理機制
在控制器的方法發生異常後,默認狀況會顯示Tomcat的500頁面,這種用戶體驗並很差。若是咱們在每一個控制器方法自行捕獲異常,顯然又太繁瑣。有沒有好的異常處理辦法呢?有的,就是Spring MVC的全局異常處理機制。Spring MVC提供了兩種全局異常處理機制:
編寫全局異常處理類
全局異常類編寫方式一
實現HandlerExceptionResolver接口,而後實現resolveException方法,編寫處理異常邏輯。
示例:
@Controller @RequestMapping("/say") public class HelloController { @RequestMapping(value = "/error") public String error() { int i = 100/0; return "success"; } } public class SimpleHandlerExceptionResolver implements HandlerExceptionResolver { @Override public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { ModelAndView mv = new ModelAndView("error"); mv.addObject("errorMsg",ex.getMessage()); return mv; } }
hellospringmvc-servlet.xml
<!--建立自定義異常處理對象--> <bean class="com.self.exceptionhandler.SimpleHandlerExceptionResolver"/>
全局異常類編寫方式二
直接在類上使用@ControllerAdvice,在異常處理方法上添加@ExceptionHandler註解。這種作法底層是AOP思想。
示例:
@ControllerAdvice public class SimpleExceptionHandler { @ExceptionHandler public ModelAndView handlerException(Exception e){ ModelAndView mv = new ModelAndView(); mv.setViewName("error"); mv.addObject("errorMsg",e.getMessage()); return mv; } }
hellospringmvc-servlet.xml
<!--建立自定義異常處理對象--> <bean class="com.self.exceptionhandler.SimpleExceptionHandler"/>
請求:http://localhost:8080/hellospringmvc/say/error
Spring MVC 異常處理機制沒處理前:
HTTP Status 500 - Request processing failed; nested exception is java.lang.ArithmeticException: / by zero
處理後:
注意:若是兩種都配置了,會被面向切面先執行返回了。類上使用@ControllerAdvice,在異常處理方法上添加@ExceptionHandler註解。這種作法底層是AOP思想。
Spring MVC 表單數據驗證
Spring MVC提供了表單數據驗證功能 。
前提:導入數據驗證依賴包。
表單數據驗證的重點是在Pojo類使用相關注解指定每一個屬性的驗證規則。如下爲可使用的註解:
註解名稱 說明
@Null 被註釋的元素必須爲 null
@NotNull 被註釋的元素必須不爲 null
@AssertTrue 被註釋的元素必須爲 true
@AssertFalse 被註釋的元素必須爲 false
@Min(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@Max(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@DecimalMin(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@DecimalMax(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@Size(max, min) 被註釋的元素的大小必須在指定的範圍內(長度大小)
@Digits(integer, fraction) 被註釋的元素必須是一個數字,其值必須在可接受的範圍內
@Past 被註釋的元素必須是一個過去的日期
@Future 被註釋的元素必須是一個未來的日期
@Pattern(value) 被註釋的元素必須符合指定的正則表達式
在Controller中,咱們須要判斷Pojo是否產生了驗證錯誤信息,若是有的話,則把信息轉給JSP頁面顯示。
示例:
pom.xml
<!-- 驗證器所需的包 --> <dependency> <groupId>com.fasterxml</groupId> <artifactId>classmate</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.2.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> public class User { private Integer id; @NotNull @Pattern(regexp = "^([a-zA-Z]*[0-9_-]*$)", message = "只能包含字母、數字、下劃線,且不能以數字或下劃線開頭") @Size(min = 1, max = 110) private String name; @NotNull @Range(min = 1,max = 100,message = "年齡不在合法範圍內") private Integer age; @Pattern(regexp = "^([a-zA-Z]*$)", message = "只能包含字母") private String ride; //... } @Controller public class ValidateController { @RequestMapping("/check") public String check(@Valid User user, BindingResult result, Model model) { //若是表單數據驗證有異常 if (result.hasErrors()) { //取出全部失敗信息 List<FieldError> fieldErrors = result.getFieldErrors(); for (FieldError fieldError : fieldErrors) { //把錯誤信息存入request域,傳遞到JSP頁面顯示 model.addAttribute("ERROR_" + fieldError.getField(), fieldError.getDefaultMessage()); } return "forward:validate.jsp"; } System.out.println("User=" + JSON.toJSONString(user)); return "success"; } }
validate.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>表單數據驗證</title> </head> <body> <form action="/hellospringmvc/check" method="post"> 用戶名:<input type="text" name="name">${ERROR_name}<br/> 年齡:<input type="text" name="age">${ERROR_age}<br/> 坐騎:<input type="text" name="ride">${ERROR_ride}<br/> <input type="submit" value="提交"> </form> </body> </html>
請求:http://localhost:8080/hellospringmvc/validate.jsp
輸出:
Maven單模塊SSM整合
本文講解使用Maven單模塊方式進行Spring MVC+Spring+MyBatis整合。爲了把整合步驟體現地更加清晰,咱們能夠把步驟分爲如下六個部分:
一、準備數據庫環境
CREATE TABLE `t_user` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主鍵', `name` varchar(64) NOT NULL COMMENT '姓名', `dept` varchar(254) NOT NULL COMMENT '部門', `phone` varchar(16) NOT NULL COMMENT '電話', `height` decimal(10,2) DEFAULT NULL COMMENT '身高', `create_emp` bigint(20) NOT NULL COMMENT '建立人', `create_time` datetime DEFAULT NULL COMMENT '建立時間', `modify_emp` bigint(20) DEFAULT NULL COMMENT '修改人', `modify_time` datetime DEFAULT NULL COMMENT '修改時間', PRIMARY KEY (`id`), KEY `idx_name` (`name`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='用戶表';
二、單獨搭建Spring環境
建立Web項目——使用原來的hellospringmvc
SSM相關依賴
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.self</groupId> <artifactId>hellospringmvc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> <!-- SSM整合的基礎依賴 --> <!-- 1.spring相關的依賴 --> <dependencies> <!-- 1.1 ioc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--1.2 aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <!-- 1.3 聲明式事務--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- 1.4 test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- 2. mybatis相關依賴 --> <!-- 2.1 mysql驅動--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!-- 2.2 數據源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!-- 2.3 mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- 3. springmvc相關依賴--> <!-- 3.1 springmvc核心包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--3.2 servlet依賴 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!--3.3 jstl標籤庫--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- 4. log4j日誌 --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.7.2</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>1.2.3</version> </dependency> <!-- 5. spring與mybatis整合包 *** --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.29</version> </dependency> <!-- jackson支持包 --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.5</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.5</version> </dependency> <!-- 驗證器所需的包 --> <dependency> <groupId>com.fasterxml</groupId> <artifactId>classmate</artifactId> <version>1.4.0</version> </dependency> <dependency> <groupId>org.jboss.logging</groupId> <artifactId>jboss-logging</artifactId> <version>3.3.2.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> </dependencies> </project>
設計Pojo
public class User { /** * id */ private int id; /** * 名字 */ private String name; /** * 部門,帝國 */ private String dept; /** * 聯繫號碼 */ private String phone; /** * 身高 */ private BigDecimal height; /** * 建立人 */ private Long createEmp; /** * 建立時間 */ private Date createTime; /** * 修改人 */ private Long modifyEmp; /** * 修改時間 */ private Date modifyTime; //... }
編寫業務接口和實現
public interface UserService { List<User> getALlUsers(); } //給業務實現類加入@Service註解,目的是把該對象放入Spring IOC容器。 @Service("userService") //@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); @Override public List<User> getALlUsers() { logger.error("查詢全部用戶成員..."); return userMapper.getALlUsers(); } }
編寫Spring配置
applicationContext.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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--spring 容器掃描配置--> <context:component-scan base-package="com.self"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> </beans>
Spring環境單元測試
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration("classpath:applicationContext.xml") public class SpringTest { @Autowired private UserService userService; @Test public void test() { userService.getALlUsers(); } }
輸出表示spring環境搭建成功:
查詢全部用戶成員...
三、 單獨搭建Spring MVC環境
Spring MVC核心控制器web.xml配置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置核心控制器 :DispatcherServlet --> <servlet> <servlet-name>hellospringmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- springmvc配置文件加載路徑 1)默認狀況下,讀取WEB-INF下面的default-servlet.xml文件 2)能夠改成加載類路徑下(resources目錄),加上classpath: --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/hellospringmvc-servlet.xml</param-value> <!--<param-value>WEB-INF/simple-servlet.xml</param-value>--> </init-param> <!--init-param必須放在load-on-startup前,不然會報錯:invalid content was found starting with element 'init-param'. One of '{"http://java.sun.com/xml/ns/javaee":run-as, "http://java.sun.com/xml/ns/javaee":security-role-ref}' is expected--> <!-- DispatcherServlet對象建立時間問題 1)默認狀況下,第一次訪問該Servlet時建立對象,默認是訪問時建立,意味着在這個時間纔去加載hellospringmvc-servlet.xml 2)能夠改變爲在項目啓動時候就建立該Servlet,提升用戶訪問體驗。 <load-on-startup>1</load-on-startup> 數值越大,對象建立優先級越低! (數值越低,越先建立) --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>hellospringmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--從新配置Tomcat的DefaultServlet的映射路徑--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> </servlet-mapping> </web-app>
springmvc配置——hellospringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.掃描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.開啓mvc註解驅動--> <mvc:annotation-driven/> </beans>
編寫UserController
@RequestMapping("/user") @Controller public class UserController { /** * 查詢全部用戶 */ @RequestMapping("list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入數據到request域 model.addAttribute("list","用戶數據"); //返回list.jsp頁面 return "userList"; } }
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>顯示用戶數據</title> </head> <body> ${list} </body> </html>
項目部署到Tomcat
請求:http://localhost:8080/user/list
4 、Spring整合Spring MVC
配置Spring監聽器
Spring和Spring MVC融合使用,只要在web.xml配置監聽器,在項目啓動的時候,加載applicationContext.xml文件,把Spring環境啓動便可。
web.xml
<!-- 配置spring監聽器,用於加載applicationContext.xml(初始化SpringIOC容器) --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
在控制層調用業務層,若是Controller成功注入Service,表明Spring與Spring MVC整合成功!
@RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; /** * 查詢全部用戶 */ @RequestMapping("list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入數據到request域 model.addAttribute("list","用戶數據"); //返回list.jsp頁面 return "userList"; } }
輸出:
五、 單獨搭建MyBatis環境
編寫UserDao接口
@Repository public interface UserMapper { List<User> getALlUsers(); }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.self.dao.UserMapper"> <select id="getALlUsers" resultType="User"> select u.create_time createTime,u.id id ,u.name name ,u.dept dept,u.phone phone from `t_user` u where 1 = 1 </select> </mapper>
mybatis-config.xml——該文件是MyBatis核心配置,裏面配置數據源及Dao接口映射等信息。
<?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> <!-- 讀取jdbc.properties --> <properties resource="jdbc.properties"/> <!--1.別名掃描 --> <typeAliases> <package name="com.self.pojo"/> </typeAliases> <!--2.數據庫鏈接 --> <environments default="mysql"> <environment id="mysql"> <transactionManager type="jdbc"></transactionManager> <dataSource type="pooled"> <property name="url" value="${jdbc.url}"/> <property name="driver" value="${jdbc.driver}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </dataSource> </environment> </environments> <!--3.映射關聯 --> <mappers> <package name="com.self.dao"/> </mappers> </configuration>
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/hello_mybatis?characterEncoding=utf8 jdbc.username=root jdbc.password=123456 jdbc.initialSize=3 jdbc.maxActive=10
MyBatis測試類
public class MabatisTest { @Test public void testFindAll() throws IOException { //1.加載SqlMapConfig.xml InputStream in = Resources.getResourceAsStream("mybatis-config.xml"); //2.建立SqlSessionFactory SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(in); //3.建立SqlSession SqlSession sqlSession = factory.openSession(); //4.建立Dao代理對象 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); //5.執行方法 List<User> list = userMapper.getALlUsers(); System.out.println(JSON.toJSONString(list)); //6.釋放資源 sqlSession.close(); in.close(); } }
輸出:
[{"createTime":1585635455000,"dept":"amy empire","id":1,"name":"大青山","phone":"123456"},{"createTime":1585635455000,"dept":"amy empire","id":2,"name":"艾米哈珀","phone":"123456"},{"createTime":1585635455000,"dept":"amy empire","id":3,"name":"池寒楓","phone":"123456"},{"createTime":1585647970000,"dept":"森林矮人王國","id":4,"name":"霍恩斯","phone":"852-253521"}]
參考代碼位置:
6 、MyBatis整合Spring
整合的思路是:Spring依賴IOC容器建立MyBatis所須要的SqlSessionFactory,從而利用SqlSessionFactory完成Dao層的操做。
注意:
由於Spring已經把以前MyBatis的數據源及Dao映射等信息都集成了,因此MyBatis的mybatis-config.xml已經不須要啦,能夠刪除。
applicationContext.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:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--spring 容器掃描配置--> <context:component-scan base-package="com.self"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--載入properties--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 1. 建立數據源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 2. 爲了建立Dao代理對象,先建立SqlSessionFactory對象 --> <!-- SqlSessionFactoryBean: 建立SqlSessionFactory對象的工具 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入數據源 --> <property name="dataSource" ref="dataSource"/> <!--typeAliasesPackage:批量別名處理 經過這些property就能夠把mybatis-config.xml替代掉了--> <property name="typeAliasesPackage" value="com.self.pojo"/> <!-- 全部配置的mapper文件 該配置至關因而mybatis-config.xml裏的mappers配置,在這邊直接掃描獲取了--> <!--<property name="mapperLocations" value="classpath*:com/self/dao/*.xml"/>--> </bean> <!-- 3. 掃描Dao接口所在包,掃描後用於建立Dao代理對象,把代理對象放入IOC容器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- Dao掃描目錄 --> <property name="basePackage" value="com.self.dao"/> <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>--> </bean> <!-- 添加事務支持 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!-- 註冊事務管理驅動 表示支持聲明式事務 @Transactional 註解標註的會被代理實現事務,但要用在有接口的public方法中--> <!--基於註解的方式使用事務配置聲明--> <tx:annotation-driven transaction-manager="transactionManager" /> </beans>
業務層注入持久層對象
//給業務實現類加入@Service註解,目的是把該對象放入Spring IOC容器。 @Service("userService") //@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; private static final Logger logger = LoggerFactory.getLogger(UserServiceImpl.class); @Override public List<User> getALlUsers() { logger.error("查詢全部用戶成員..."); return userMapper.getALlUsers(); } }
編寫測試類
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(value = "classpath:applicationContext.xml") public class SpringMyBatisTest { //從IOC容器中獲取業務實現 @Autowired private UserService userService; @Test public void testFindAll(){ System.out.println(JSON.toJSONString(userService.getALlUsers())); } }
SSM框架已經整合完成。剩下就是把數據顯示到JSP頁面上。
修改UserController類
@RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; /** * 查詢全部用戶 */ @RequestMapping("list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入數據到request域 model.addAttribute("list", users); //model.addAttribute("list","用戶數據"); //返回list.jsp頁面 return "userList"; } }
修改JSP頁面顯示內容
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>顯示用戶數據</title> </head> <body> <h3>用戶列表</h3> <table border="1"> <tr> <td>編號</td> <td>用戶名</td> <td>帝國</td> <td>電話號碼</td> <td>建立時間</td> </tr> <!-- items: 須要須要遍歷的集合 var: 每一個對象的變量名稱 --> <c:forEach items="${list}" var="user"> <tr> <td>${user.id}</td> <td>${user.name}</td> <td>${user.dept}</td> <td>${user.phone}</td> <td>${user.createTime}</td> </tr> </c:forEach> </table> </body> </html>
輸出:
報錯:
一、在經過controller請求到底層service時報錯:springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.self.service.UserService'。
A:這種狀況下通常是UserService沒有註冊到spring容器中,通常分兩種狀況,要麼掃描bean時沒有掃到,因此沒添加,要嘛是UserService實現類(注意不是UserService接口)沒有配置@Service,因此spring沒有把他當成一個組件註冊到容器中。還有就是在配置UserService實現類時配置@Service錯誤,要指定名稱,不然默認是類名首字母小寫後的全稱,所以會找不到bean。
還有就是web.xml缺乏ContextLoaderListener配置,致使spring容器裏的bean沒有被加載。
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
二、啓動項目時沒法啓動成功,userService注入不了dao依賴。
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'userMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userMapper' defined in file [F:\practice\hellospringmvc\target\hellospringmvc-1.0-SNAPSHOT\WEB-INF\classes\com\self\dao\UserMapper.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: org.apache.ibatis.builder.BuilderException: Error parsing Mapper XML. Cause: org.apache.ibatis.builder.BuilderException: Error resolving class. Cause: org.apache.ibatis.type.TypeException: Could not resolve type alias 'User'. Cause: java.lang.ClassNotFoundException: Cannot find class: User <!--A:這是因爲UserMapper.xml的resultType="User",沒有指定全路徑,這時候要嘛指定全路徑,要嘛在applicationContext.xml配置sqlSessionFactory時批量別名處理。 以下: --> <!-- 2. 爲了建立Dao代理對象,先建立SqlSessionFactory對象 --> <!-- SqlSessionFactoryBean: 建立SqlSessionFactory對象的工具 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入數據源 --> <property name="dataSource" ref="dataSource"/> <!--typeAliasesPackage:批量別名處理 經過這些property就能夠把mybatis-config.xml替代掉了--> <property name="typeAliasesPackage" value="com.self.pojo"/> </bean>
Maven多模塊SSM整合
一些中大型項目,我但願採用Maven多模塊構建方式來搭建SSM整合項目。
Maven多模塊構建SSH項目架構圖:
示例:
新建一個noodle-parent的project工程。子項目經過右擊項目名建立新的maven依賴模塊。
總體結構:
一、創建parent工程
配置父工程noodle-parent——pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.self</groupId> <artifactId>noodle-parent</artifactId> <packaging>pom</packaging> <version>1.0-SNAPSHOT</version> <modules> <module>noodle-pojo</module> <module>noodle-dao</module> <module>noodle-service</module> <module>noodle-web</module> </modules> <!-- SSM整合的基礎依賴 --> <!-- 1.spring相關的依賴 --> <dependencies> <!-- 1.1 ioc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--1.2 aop --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency> <!-- 1.3 聲明式事務--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!-- 1.4 test --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <!-- 2. mybatis相關依賴 --> <!-- 2.1 mysql驅動--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> <!-- 2.2 數據源 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.6</version> </dependency> <!-- 2.3 mybatis核心包 --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.5</version> </dependency> <!-- 3. springmvc相關依賴--> <!-- 3.1 springmvc核心包 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.0.2.RELEASE</version> </dependency> <!--3.2 servlet依賴 --> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <!--3.3 jstl標籤庫--> <dependency> <groupId>jstl</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- 4. log4j日誌 --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <!-- 5. spring與mybatis整合包 *** --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.1</version> </dependency> </dependencies> </project>
二、創建pojo工程
編寫Pojo類
public class User { /** * id */ private int id; /** * 名字 */ private String name; /** * 部門,帝國 */ private String dept; /** * 聯繫號碼 */ private String phone; /** * 身高 */ private BigDecimal height; /** * 建立人 */ private Long createEmp; /** * 建立時間 */ private Date createTime; /** * 修改人 */ private Long modifyEmp; /** * 修改時間 */ private Date modifyTime; //... }
三、創建dao工程
依賴domain工程
<dependencies> <dependency> <groupId>com.self</groupId> <artifactId>noodle-pojo</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> public interface UserMapper { List<User> getALlUsers(); }
UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.self.dao.UserMapper"> <select id="getALlUsers" resultType="User"> select u.create_time createTime,u.id id ,u.name name ,u.dept dept,u.phone phone from `t_user` u where 1 = 1 </select> </mapper>
編寫Spring的Dao配置
jdbc.properties
jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/hello_mybatis?characterEncoding=utf8 jdbc.username=root jdbc.password=123456
applicationContext-dao.xml文件只存放與Dao有關的配置 。
<?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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--載入properties--> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- 1. 建立數據源 --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> <!-- 2. 爲了建立Dao代理對象,先建立SqlSessionFactory對象 --> <!-- SqlSessionFactoryBean: 建立SqlSessionFactory對象的工具 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注入數據源 --> <property name="dataSource" ref="dataSource"/> <!--typeAliasesPackage:批量別名處理 經過這些property就能夠把mybatis-config.xml替代掉了--> <property name="typeAliasesPackage" value="com.self.pojo"/> <!-- 全部配置的mapper文件 該配置至關因而mybatis-config.xml裏的mappers配置,在這邊直接掃描獲取了--> <!--<property name="mapperLocations" value="classpath*:com/self/dao/*.xml"/>--> </bean> <!-- 3. 掃描Dao接口所在包,掃描後用於建立Dao代理對象,把代理對象放入IOC容器 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <!-- Dao掃描目錄 --> <property name="basePackage" value="com.self.dao"/> <!--<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>--> </bean> </beans>
四、創建Service工程
依賴Dao工程 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>noodle-parent</artifactId> <groupId>com.self</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>noodle-service</artifactId> <dependencies> <dependency> <groupId>com.self</groupId> <artifactId>noodle-dao</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project> public interface UserService { List<User> getALlUsers(); } //給業務實現類加入@Service註解,目的是把該對象放入Spring IOC容器。 @Service("userService") //@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public List<User> getALlUsers() { System.out.println("查詢全部用戶成員..."); return userMapper.getALlUsers(); } }
編寫Spring的Service配置
applicationContext-service.xml
該配置主要須要掃描Service實現類和配置Spring聲明式事務。
<?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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!--spring 容器掃描配置--> <context:component-scan base-package="com.self"> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!--Spring聲明式事務--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <!--事務通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="get*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="load*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="select*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="find*" isolation="DEFAULT" propagation="SUPPORTS" read-only="true"/> <tx:method name="*" isolation="DEFAULT" propagation="REQUIRED"/> </tx:attributes> </tx:advice> <!--事務切面--> <aop:config> <!--切入點--> <aop:pointcut id="pt" expression="execution(* com.self.service.impl.*ServiceImpl.*(..))"/> <!--切面--> <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/> </aop:config> </beans>
五、創建Web工程——項目爲Web項目
依賴Service工程 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>noodle-parent</artifactId> <groupId>com.self</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>war</packaging> <artifactId>noodle-web</artifactId> <dependencies> <dependency> <groupId>com.self</groupId> <artifactId>noodle-service</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
配置監聽器和核心控制器
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- 配置核心控制器 :DispatcherServlet --> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- springmvc配置文件加載路徑 1)默認狀況下,讀取WEB-INF下面的default-servlet.xml文件 2)能夠改成加載類路徑下(resources目錄),加上classpath: --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:noodlespringmvc-servlet.xml</param-value> <!--<param-value>WEB-INF/simple-servlet.xml</param-value>--> </init-param> <!--init-param必須放在load-on-startup前,不然會報錯:invalid content was found starting with element 'init-param'. One of '{"http://java.sun.com/xml/ns/javaee":run-as, "http://java.sun.com/xml/ns/javaee":security-role-ref}' is expected--> <!-- DispatcherServlet對象建立時間問題 1)默認狀況下,第一次訪問該Servlet時建立對象,默認是訪問時建立,意味着在這個時間纔去加載hellospringmvc-servlet.xml 2)能夠改變爲在項目啓動時候就建立該Servlet,提升用戶訪問體驗。 <load-on-startup>1</load-on-startup> 數值越大,對象建立優先級越低! (數值越低,越先建立) --> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <!--從新配置Tomcat的DefaultServlet的映射路徑--> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>*.html</url-pattern> <url-pattern>*.jpg</url-pattern> <url-pattern>*.css</url-pattern> <url-pattern>*.js</url-pattern> <url-pattern>*.png</url-pattern> </servlet-mapping> <!-- 配置spring監聽器,用於加載applicationContext.xml(初始化SpringIOC容器) --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext-*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 字符編碼過濾器 --> <filter> <filter-name>encodingFilter</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> </filter> <filter-mapping> <filter-name>encodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
注意:
Spring監聽器讀取的路徑爲classpath*:,這個語法指加載當前項目及依賴工程的全部符合條件的文件。由於applicationContext.xml分佈在不一樣的Maven工程,因此必須使用該語法加載!
noodlespringmvc-servlet.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:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 1.掃描Controller的包--> <context:component-scan base-package="com.self" use-default-filters="false"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan> <!-- 2.配置視圖解析器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <!-- 2.1 頁面前綴 --> <property name="prefix" value="/WEB-INF/pages/"/> <!-- 2.2 頁面後綴 --> <property name="suffix" value=".jsp"/> </bean> <!-- 3.開啓mvc註解驅動--> <!--不添加也能使用,高版本spring已經默認實現了。 在Spring中通常採用@RequestMapping註解來完成映射關係,要想使@RequestMapping註解生效必須向上下文中註冊DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例,這兩個實例分別在類級別和方法級別處理。而<mvc:annotation-driven/>配置幫助咱們自動完成上述兩個實例的注入。 --> <mvc:annotation-driven/> <!--<mvc:default-servlet-handler/>--> </beans> @RequestMapping("/user") @Controller public class UserController { @Autowired private UserService userService; /** * 查詢全部用戶 */ @RequestMapping("/list") public String showAll(Model model) { List<User> users = userService.getALlUsers(); //存入數據到request域 model.addAttribute("list", users); //model.addAttribute("list","用戶數據"); //返回list.jsp頁面 return "userList"; } }
userList.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <title>顯示用戶數據</title> </head> <body> <h3>用戶列表</h3> <table border="1"> <tr> <td>編號</td> <td>用戶名</td> <td>帝國</td> <td>電話號碼</td> <td>建立時間</td> </tr> <!-- items: 須要須要遍歷的集合 var: 每一個對象的變量名稱 --> <c:forEach items="${list}" var="user"> <tr> <td>${user.id}</td> <td>${user.name}</td> <td>${user.dept}</td> <td>${user.phone}</td> <td>${user.createTime}</td> </tr> </c:forEach> </table> </body> </html>
輸出:
注意:當咱們配置項目到tomcat上時,在建立artifact時能夠指定項目名稱(不必定要是項目名)做爲請求的路徑,像這樣接在localhost後面,http://localhost:8080/noodle/user/list。若是隻是設置/ (斜槓)則直接在端口後面接請求地址。
疑問
Q:在springmvc容器的配置文件hellospringmvc-servlet.xml中配置開啓mvc註解驅動的做用是什麼?都做用在哪些地方?何時用到?
教程裏的解釋是在Spring中通常採用@RequestMapping註解來完成映射關係,要想使@RequestMapping註解生效必須向上下文中註冊DefaultAnnotationHandlerMapping和一個AnnotationMethodHandlerAdapter實例,這兩個實例分別在類級別和方法級別處理。而mvc:annotation-driven/配置幫助咱們自動完成上述兩個實例的注入。 可是在實踐中咱們就算沒有顯式註冊這兩個bean實例或者在spring mvc配置的hellospringmvc-servlet.xml中加上 mvc:annotation-driven/這句配置也不妨礙咱們使用@RequestMapping註解來完成映射關係,爲何?
<!-- 3.開啓mvc註解驅動--> <mvc:annotation-driven/>
Q:什麼叫Ant風格的路徑匹配功能?
A: ANT通配符有如下三種:
通配符 說明
? 匹配任何單字符
匹配0或者任意數量的字符
** 匹配0或者更多的目錄
例子:
URL路徑 說明
/app/.x 匹配(Matches)全部在app路徑下的.x文件
/app/p?ttern 匹配(Matches) /app/pattern 和 /app/pXttern,可是不包括/app/pttern
/**/example 匹配(Matches) /app/example, /app/foo/example, 和 /example
/app//dir/file. 匹配(Matches) /app/dir/file.jsp, /app/foo/dir/file.html,/app/foo/bar/dir/file.pdf, 和 /app/dir/file.java
/*/.jsp 匹配(Matches)任何的.jsp 文件
屬性: 最長匹配原則(has more characters) 說明,URL請求/app/dir/file.jsp,如今存在兩個路徑匹配模式/*/.jsp和/app/dir/.jsp,那麼會根據模式/app/dir/.jsp來匹配
參考
Q:RequestMappingHandlerMapping會被默認建立麼?在什麼狀況下建立,標記有@RequestMapping("/hello") 註解時仍是掃描Controller時?
A:是在web.xml配置mvc:annotation-driven/時。RequestMappingHandlerMapping和RequestMappingHandlerAdapter會默認註冊。
固然,通常狀況下咱們是不須要配置mvc:annotation-driven/的,默認會註冊,但當咱們web.xml中配置了其餘如BeanNameUrlHandlerMapping處理映射器時,就要加這句,不然不會默認幫咱們註冊,這個須要研究下代碼是怎麼個處理方式。
在不配置HandlerMapping 的狀況下,容器默認會註冊初始化BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping來處理映射。而HandlerAdapter會有三種,分別是HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,RequestMappingHandlerAdapter。
org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
注意:若是有在web.xml中配置指定的HandlerMapping 和 HandlerAdapter 的話,則只註冊配置的處理器。
mvc:annotation-driven的做用
Spring 3.0.x中使用了mvc:annotation-driven後,默認會幫咱們註冊默認處理請求,參數和返回值的類,其中最主要的兩個類:DefaultAnnotationHandlerMapping 和 AnnotationMethodHandlerAdapter ,分別爲HandlerMapping的實現類和HandlerAdapter的實現類,從3.1.x版本開始對應實現類改成了RequestMappingHandlerMapping和RequestMappingHandlerAdapter。
mvc:annotation-driven的做用參考
Q:若是咱們沒有配置HandlerAdapter ,默認是建立什麼類型的HandlerAdapter 來處理咱們的Controller呢?
A:默認不配置SimpleControllerHandlerAdapter, 也能處理Controller類型爲org.springframework.web.servlet.mvc.Controller的接口,SimpleControllerHandlerAdapter會默認註冊.
Q:保存HandlerMethod類型的容器mappingLookup爲何要初始化爲new LinkedHashMap<>();而不是HashMap<>()類型呢?出於什麼考慮?LinkedHashMap和HashMap各類的使用場景和優點缺點是什麼?
A:考慮動態添加的效率?
Q:轉發和重定向的區別?
Q:在目前主流的三種 Web 服務交互方案中,REST 相比於SOAP(Simple Object Access protocol, 簡單對象訪問協議) 以及 XML-RPC 更加簡單明瞭。瞭解下目前主流的Web 服務交互方案。
Q:什麼叫 Payload 的編碼?
Q:通常實踐中的RESTful風格的請求開發是經過請求方式POST、GET等的不一樣來區分的麼?
Q:ApplicationContext和WebApplicationContext有什麼區別?用他們去getBean()是同樣的?
A:Spirng容器只有一個,spring和springmvc的配置能夠互相放在各自的配置xml中,最後都做用在spring容器中。待詳細瞭解。
Q:爲何叫Spring MVC、MyBatis整合Spring?而不是反過來叫Spring MVC整合Spring呢?是隨便叫仍是有什麼區別?
Q:ContextLoaderListener的做用?
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
Q:@Repository註解在mybatis中有什麼用麼?通常不都是經過掃包來得到dao對象麼?
//不須要加註解 //@Repository //@Mapper public interface UserMapper { List<User> getALlUsers(); }
其餘:
一、md刪除線使用:
若是段落上的文字要添加刪除線,只須要在文字的兩端加上兩個波浪線 ~~ 便可 ~~shanchu.com~~
二、DispatcherServlet.properties ——DispatcherServlet初始化默認配置
org.springframework.web.servlet.DispatcherServlet#defaultStrategies jdk1.8 284行 # Default implementation classes for DispatcherServlet's strategy interfaces. # Used as fallback when no matching beans are found in the DispatcherServlet context. # Not meant to be customized by application developers. org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager
三、IDEA的tomcat日誌輸出亂碼問題的解決。
這是由於下載的tomcat8中\apache-tomcat-8.5.55\conf\logging.properties 配置默認編碼是UTF-8.而Windows系統的默認編碼格式是GBK,所以在對輸出的字符打印時由於解碼不對而致使的亂碼。只要對logging.properties中的編碼格式UTF-8配置註釋掉便可。
參考
四、JDK1.8對接口的默認實現。
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } }