SpringMVC第一天 1. SpringMVC概述 1.1. 什麼是Spring MVC SpringMVC是Spring框架內置的MVC的實現.SpringMVC就是一個Spring內置的MVC框架. MVC框架,它解決WEB開發中常見的問題(參數接收、文件上傳、表單驗證、國際化、等等),而且 ...
SpringMVC第一天
1. SpringMVC概述
1.1. 什麼是Spring MVC
SpringMVC是Spring框架內置的MVC的實現.SpringMVC就是一個Spring內置的MVC框架.
MVC框架,它解決WEB開發中常見的問題(參數接收、文件上傳、表單驗證、國際化、等等),而且使用簡單,與Spring無縫集成。 支持 RESTful風格的 URL 請求 。
採用了鬆散耦合可插拔組件結構,比其他 MVC 框架更具擴展性和靈活性。
1.2. SpringMVC的作用
MVC模式:(Model-View-Controller):為瞭解決頁面代碼和後臺代碼的分離.
2. SpringMVC底層實現
在沒有使用SpringMVC之前我們都是使用的Servlet在做Web開發。但是使用Servlet開發在接受請求數據參數,數據共用,頁面跳轉等操作相對比較複雜。
SpringMVC底層就是的Servlet,SpringMVC就是對Servlet進行更深層次的封裝
2.1. 回顧MVC模式
回顧什麼是mvc模式
模型model(javabean), 視圖view(jsp/img) 控制器Controller(Action/servlet) C存在的目的.就是為了保證M和V的一致性
當M發生改變時,C可以把M中的新內容更新到V中.
2.1.1. 原始MVC 模式
MVC模式最早開始是在CS 架構上面 20世紀70+年代
下面為原始的mvc模式.
目前web應用中,99%的項目都會使用mvc模式開發.
2.1.2. WEB開發的MVC
WEB開發從20世紀90+年代開始,也是使用MVC模式。在最原始的MVC上有一些改進
優秀的框架改變了這種模式,將model更廣泛的使用,這樣會比原始的mvc好多了.
像現在一些優秀的mvc的框架,如Struts2,springMVC
在客戶端提交也使用了模型來請求參數
spring MVC 也實現的相關的功能
3. 入門案例 -xml 配置
3.1. 準備工作
創建動態Web項目 |
|
3.2. 步驟
3.3. 準備jar包
|
3.4. SpringMVC開發相關jar包
spring-web-4.3.3.RELEASE.jar spring 對web項目的支持。
spring-webmvc-4.3.2RELEASE.jar spring mvc核心包。
|
3.5. 編寫Controller控制器(與以前servlet類似)
public class HelloController implements Controller { @Override public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { ModelAndView mv = new ModelAndView(); mv.addObject("username", "師姐"); mv.setViewName("/WEB-INF/hello/hello.jsp"); return mv; } } |
3.6. 在springmvc.xml配置 Controller
<!-- name : 給當前控制器取的一個名字,相當於Servlet中的資源名稱,以便瀏覽器訪問,必須以斜杠/開頭 建議使用 name屬性,不要使用id,因為早期版本 id 不支持特殊字元 如 /斜杠 --> <bean name="/hello" class="cn.zj.springmvc.HelloController"/> |
3.7. 配置spring mvc核心(前端)控制器,並且初始化spring容器。 web.xml配置.
<!-- 配置前端控制器 :所有的請求都會經過此控制器,讓後通過此控制器分發到各個控制器(總控) 總控其實就是Servlet,SpringMVC底層就是使用Servlet編寫的 --> <servlet> <servlet-name>springMVC</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- 讀取SpringMVC的配置文件 --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc.xml</param-value> </init-param> <!-- 初始化容器 --> <load-on-startup>1</load-on-startup> </servlet>
<servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> |
3.8. 啟動項目
|
3.9. 訪問項目
|
4. SpringMVC的全註解開發
4.1. Spring中IOC 註解
註解 |
說明 |
@Component |
通用組件註解(一般配置其他非三層相關的類) |
@Controller |
表現層(控制層) |
@Service |
業務邏輯層(服務Service) |
@Resposotory |
數據持久層(DAO) |
4.2. SpringMVC使用註解步驟
4.2.1. Spring mvc 採用註解方式(需要導入aop的包)
|
4.2.2. 通過註解方式註冊控制器,配置需要掃描的根目錄
<context:component-scan base-package="cn.zj.springmvc"/>
4.2.3. 支持所有mvc註解支持。支持json
<mvc:annotation-driven/>
4.2.4. 在核心類上添加@Controller 註解
4.2.5. 在方法上添加@RequestMapping("/hello")註解
4.3. 案例代碼
@Controller public class AnnotationController { //@RequestMapping(value= {"/method1","/method2"}) @RequestMapping("method1") public ModelAndView mehtod1() { ModelAndView mv = new ModelAndView(); mv.addObject("username", "喬峰"); mv.setViewName("/WEB-INF/anno/index.jsp"); return mv; } } |
5. SpringMVC執行流程和原理
SpringMVC流程: 01、用戶發送出請求到前端控制器DispatcherServlet。 02、DispatcherServlet收到請求調用HandlerMapping(處理器映射器)。 03、HandlerMapping找到具體的處理器(可查找xml配置或註解配置),生成處理器對象及處理器攔截器(如果有),再一起返回給DispatcherServlet。 04、DispatcherServlet調用HandlerAdapter(處理器適配器)。 05、HandlerAdapter經過適配調用具體的處理器(Handler/Controller)。 06、Controller執行完成返回ModelAndView對象。 07、HandlerAdapter將Controller執行結果ModelAndView返回給DispatcherServlet。 08、DispatcherServlet將ModelAndView傳給ViewReslover(視圖解析器)。 09、ViewReslover解析後返回具體View(視圖)。 10、DispatcherServlet根據View進行渲染視圖(即將模型數據填充至視圖中)。 11、DispatcherServlet響應用戶。
|
|
涉及組件分析: 1、前端控制器DispatcherServlet(不需要程式員開發),由框架提供,在web.xml中配置。 作用:接收請求,響應結果,相當於轉發器,中央處理器。
2、處理器映射器HandlerMapping(不需要程式員開發),由框架提供。 作用:根據請求的url查找Handler(處理器/Controller),可以通過XML和註解方式來映射。
3、處理器適配器HandlerAdapter(不需要程式員開發),由框架提供。 作用:按照特定規則(HandlerAdapter要求的規則)去執行Handler。
4、處理器Handler(也稱之為Controller,需要工程師開發) 註意:編寫Handler時按照HandlerAdapter的要求去做,這樣適配器才可以去正確執行Handler。 作用:接受用戶請求信息,調用業務方法處理請求,也稱之為後端控制器。
5、視圖解析器ViewResolver(不需要程式員開發),由框架提供 作用:進行視圖解析,把邏輯視圖名解析成真正的物理視圖。 SpringMVC框架支持多種View視圖技術,包括:jstlView、freemarkerView、pdfView等。
6、視圖View(需要工程師開發) 作用:把數據展現給用戶的頁面 View是一個介面,實現類支持不同的View技術(jsp、freemarker、pdf等) |
具體組件的配置相關,請查閱 spring-webmvc-4.3.2.RELEASE.jar 包 下麵 /org/springframework/web/servlet/DispatcherServlet.properties 的相關配置 |
HanderMapping 請求映射處理器 |
作用:根據不同的請求選擇最合適的處理器(自己編寫的控制器),請求映射處理器可以配置多個,誰最先匹配就執行誰。 Spring MVC預設:/org/springframework/web/servlet/DispatcherServlet.properties org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.do.annotation.DefaultAnnotationHandlerMapping BeanNameUrlHandlerMapping:處理通過<bean name="/xxx">註冊的控制器。控制器需要實現Controller介面。
DefaultAnnotationHandlerMapping:處理通過註解@Controller(類標簽) 及@RequestMapping(方法標簽) 註冊的控制器。 該請求映射處理器已經在Spring 3.2 版本過時,替換為RequestMappingHandlerMapping。
spring 中提供的映射處理器: org.springframework.web.servlet.handler.SimpleUrlHandlerMapping 簡單url請求映射處理器。 <bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping"> <property name="mappings"> <value> /helloworld=helloworldController /helloworld002=helloworldController </value> </property> </bean> org.springframework.web.servlet.do.method.annotation.RequestMappingHandlerMapping 採用註解方式請求映射處理器。 |
HandlerAdapter 處理器適配 |
HandlerAdapter 處理器適配: 作用: 支持多種類型的處理器,如何來執行"處理器(控制器)“; Spring MVC預設: org.springframework.web.servlet.HandlerAdapter= org.springframework.web.servlet.do.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.do.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.do.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.do.HttpRequestHandlerAdapter 處理實現了HttpRequestHandler對應的控制器。 核心代碼: public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
((HttpRequestHandler) handler).handleRequest(request, response); return null; }
org.springframework.web.servlet.do.SimpleControllerHandlerAdapter 處理實現了Controller對應的控制器。
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return ((Controller) handler).handleRequest(request, response); }
org.springframework.web.servlet.do.annotation.AnnotationMethodHandlerAdapter 處理通過註解方式的控制器。 3.2中已過時,替換為org.springframework.web.servlet.do.method.annotation.RequestMappingHandlerAdapter |
ViewResolver 視圖解析器 |
作用:根據不同的視圖,響應不同的結果,比如普通的jsp或json. Spring mvc預設: org.springframework.web.servlet.ViewResolver= org.springframework.web.servlet.view.InternalResourceViewResolver
InternalResourceViewResolver : 支持預設視圖,採用forward,redirect。 視圖名: 不寫首碼預設為"轉發" 視圖名字元串首碼: forward:/xxx.jsp 採用轉發。 redirect:/xxx.jsp 採用重定向。
new ModelAndView("forward:/userList"); new ModelAndView("redirect:/userList");
註冊視圖解析器: <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/" /> <property name="suffix" value=".jsp" /> </bean> |
6. 對靜態資源訪問
我們這樣的配置有這樣一個問題 在Web根路徑添加index.html,然後不能訪問,原因是什麼呢?為什麼此時在配置前端控制器的URL模式(<url-pattern>)寫成 / 就不行呢?
|
原因: Tomcat中處理靜態資源訪問的servlet(default)的映射路徑為/. 在啟動項目的時候,在Tomcat中的web.xml是先載入的,項目的web.xml是後載入的,如果配置了相同的映射路徑,後面的會覆蓋前者. 也就是說,SpringMVC中的DispatcherServlet的映射路徑覆蓋了Tomcat預設對靜態資源的處理的路徑。 如果SpringMVC要配置為/,那麼就得設置Dispatcherservlet對靜態資源進行支持。
|
Tomcat 根/confg/web.xml 103行 <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>false</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
|
解決方案:需要在SpringMVC的配置文件中添加對靜態資源的訪問 <mvc:default-servlet-handler/> ----------------------------------------------------------------------------------------- <mvc:default-servlet-handler/> 將在 SpringMVC 上下文中定義一個 DefaultServletHttpRequestHandler,它會對進入 DispatcherServlet 的請求進行篩查,如果發現是沒有經過映射的請求,就將該請求交由 Tomcat預設的 Servlet 處理,如果不是靜態資源的請求,才由 DispatcherServlet 繼續處理 ----------------------------------------------------------------------------------------- /和/*的區別: / 會匹配url請求/index等 ,也會匹配靜態資源*.js,*.html等, 不會匹配*.jsp文件。 /* 會匹配url請求/index等 ,也會匹配靜態資源*.js,*.html等, 會匹配*.jsp文件。 實際開發中一般推薦使用 *.尾碼 如 *.do *.action *.do |
<servlet-mapping> <servlet-name>springMVC</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> |
7. Spring請求響應
7.1. @RequestMapping
@RequestMapping註解主要是設置SpringMVC請求的映射路徑
所謂的映射路徑,就是匹配請求路徑和執行方法關係的路徑.
請求路徑:http://localhost:8080/springmvc/method1.do
映射路徑:@RequestMapping(value="/method1")
@RequestMapping 用於貼在控制器的類上或者方法上面
如果是貼在控制器的類上面,那麼在訪問這個類的方法之前必須先加上類上的對應的名稱
類似於 項目下麵的 模塊名稱
如果貼在方法上面,就是訪問此方法的資源名稱
@Controller @RequestMapping("/request") //訪問時候必須加上,類似模塊名稱 public class RequestController { @RequestMapping(value="/method1") //資源名稱 public void method1() { } } |
訪問地址 : http://localhost:8080/springmvc/request/method1.do
7.2. 兩種限制
SpringMVC支持對請求的限制.如果不滿足限制的條件,就不讓訪問執行方法.
這樣做,大大提高了執行方法的安全性.
主要的限制有兩種:(method)方法限制,參數限制
7.2.1. 方法限制
就是設置請求的method類型.如果發送過來的請求與方法設置的method不一樣,就不能訪問執行方法.
請求method : GET , POST
<form action="${pageContext.request.contextPath }/login.do" method="get"> <input type="submit" value="登錄"> </form> |
/** * 接收的請求,必須是POST * @return */ @RequestMapping(value="login",method=RequestMethod.POST) public String login(){ System.out.println("-登錄-"); return "/login.jsp"; } |
前臺發送的是GET請求,而方法限制是POST請求,所以請求無法執行方法
方法限制可以配置多個參數
@RequestMapping(value="login",method={RequestMethod.GET,RequestMethod.POST}) public String login(){ System.out.println("-登錄-"); return "/login.jsp"; } |
7.2.2. 參數限制
1.就是請求裡面必須包括哪些參數,或不包括哪些哪些.
2.參數包括哪些值,不包括哪些值
限制參數格式:
1.參數必須包括:params={"username","password"}
2.參數不能包括:params={"!userid"}
3參數值必須是指定的值:params={"username=zhangsan"})
4.參數值必須不是指定的值:params={"userid!=123"})
請求:沒有後臺方法指定的參數
<h4>登錄頁面</h4> <form action="${pageContext.request.contextPath}/request/method1.do" method="post"> 賬號:<input name="username"><br> 密碼:<input type="password" name="pwd"><br> <button type="submit">登錄</button> </form> |
後臺代碼
/** * 需求:登錄時必須包括用戶名,密碼 * @return */ @RequestMapping(value="login2",params={"username","password"}) public String login2(){ System.out.println("-登錄-"); return "/login.jsp"; } |
如果前臺請求沒有指定後臺要求的參數,會報錯.
7.3. Spring方法參數可以註入的類型
SpringMVC的方法預設可以註入 JavaWeb開發常用的數據共用對象
HttpServletRequest
HttpServletResponse
HttpSession
獲取這些共用對象以後,就可以向之前的Servlet一樣,做任何數據共用以及頁面跳轉操作
/* * Spring的方法預設可以註入 JavaWeb開發常用的數據共用對象 HttpServletRequest HttpServletResponse * HttpSession 以後開發 按需註入 */ @RequestMapping(value = "/method0") public void method0(HttpServletRequest req, HttpServletResponse resp, HttpSession session) { //TODO } |
8. 數據綁定
8.1. 數據綁定是什麼
SpringMVC裡面,所謂的數據綁定就是將請求帶過來的表單數據綁定到執行方法的參數變數.
實際開發中,SpringMVC作為表現層框架,肯定會接受前臺頁面傳遞過來的參數,SpringMVC提供了豐富的接受參數的方法
8.2. 原始方式request.getParameter() 瞭解
SpringMVC可以註入HttpServletRequest對象,直接使用getParameter參數接受
<!-- 原始方式request.getParameter() --> <fieldset> <legend> 原始方式request.getParameter()</legend> <form action="${pageContext.request.contextPath}/request/method1.do" method="get"> 賬號: <input name="username"><br> 年齡: <input name="age"><br> <button type="submit">提交</button> </form> </fieldset> |
@RequestMapping(value="/method1",method=RequestMethod.POST) //資源名稱 public void method1(HttpServletRequest req,HttpServletResponse resp,HttpSession session) { //原始方式request.getParameter() String username = req.getParameter("username"); String age = req.getParameter("age"); System.out.println(username); System.out.println(age); } |
8.3. 方法形參與前臺參數同名
在請求方法形參上,聲明和表單欄位名相同的參數名(可以自動同名匹配,然後進行封裝)
<fieldset> <legend>方法形參與前臺參數同名</legend> <form action="${pageContext.request.contextPath}/request/method2.do" method="post"> 賬號: <input name="username"><br> 年齡: <input name="age"><br> <button type="submit">提交</button> </form> </fieldset> |
//方法形參與前臺參數同名 @RequestMapping(value="/method2",method=RequestMethod.POST) public ModelAndView method2(String username,String age) { System.out.println(username); System.out.println(age); return null; } |
8.4. 方法形參與前臺參數不同名
<fieldset> <legend>方法形參與前臺參數不同名</legend> <form action="${pageContext.request.contextPath}/request/method3.do" method="post"> 賬號: <input name="name"><br> 年齡: <input name="age"><br> <button type="submit">提交</button> </form> </fieldset> |
// 方法形參與前臺參數不同同名 // 解決方案使用 : @RequestParam("前臺表單對應的名") @RequestMapping(value = "/method3", method = RequestMethod.POST) public ModelAndView method3(@RequestParam("name") String username, String age) { System.out.println(username); System.out.println(age); return null; } |
8.5. 接受數組
<fieldset> <legend>接收數組或集合</legend> <form action="${pageContext.request.contextPath}/request/method4.do" method="post"> 賬號: <input name="name"><br> 年齡: <input name="age"><br> 愛好: <input type="checkbox" name="hobbys" value="java">java <input type="checkbox" name="hobbys" value="html">html<br> <button type="submit">提交</button> </form> </fieldset> |
// 接受數組 @RequestMapping(value = "/method4", method = RequestMethod.POST) public ModelAndView method4(String[] hobbys) { System.out.println(Arrays.toString(hobbys)); return null; } |
8.6. 對象傳參
後臺並不能直接接受集合參數,需要將集合設置到對應的JavaBean中,通過JavaBean接受集合參數 |
Pojo對象 |
public class User { private String username; private String password; private String email; private String phone; private String[] hobby; } |
<fieldset> <legend>接受對象,表單參數名必須和後臺pojo對象對應的屬性名相同</legend> <form action="${pageContext.request.contextPath}/request/method5.do" method="get"> 賬號: <input name="username"><br> 密碼: <input type="password" name="password"><br> 郵箱: <input name="email"><br> 電話: <input name="phone"><br> 愛好:<input type="checkbox" name="hobby" value="java">java <input type="checkbox" name="hobby" value="C">C <input type="checkbox" name="hobby" value="C++">C++<br/> <button type="submit">提交</button> </form> </fieldset> |
// 對象傳參->對象中有集合 @RequestMapping(value = "/method5", method = RequestMethod.POST) public ModelAndView method4(User user) { System.out.println(user); return null; } |
8.7. 接受參數封裝成Map集合
<fieldset> <legend>接受參數封裝成Map集合</legend> <form action="${pageContext.request.contextPath}/request/method6.do" method="post"> 賬號: <input name="username"><br> 密碼: <input name="password"><br> 郵箱: <input name="email"><br> 電話: <input name="phone"><br> </form> </fieldset> |
// 接受參數封裝成Map集合 @RequestMapping(value = "/method6", method = RequestMethod.POST) public ModelAndView method6(@RequestParam Map<String,Object> map) { System.out.println("map:"+map); return null; } |
8.8. RESTful風格支持
8.8.1. RESTFUL 風格介紹
REST(英文:Representational State Transfer,簡稱