一、什么是springmvc?
我們知道三層架構的思想,并且如果你知道ssh的話,就會更加透徹地理解這個思想,struts2在web層,spring在中間控制,hibernate在dao層與數據庫打交道,而前面剛寫的mybatis跟hibernate一樣,與數據庫打交道在dao層的另一個框架,而今天所要講解的springmvc是在web層的另一個框架。
springmvc全名是spring web mvc,springmvc是spring的一個模塊,并且看名字即可知道,springmvc是一個基于mvc設計模式的前端web框架。
mvc:m(model模型)、v(view視圖)、c(control控制)
mvc的運用概念圖
二、springmvc的入門程序
通過這個來快速了解springmvc大概的開發流程,其實通過上面的mvc分析圖,差不多就知道了如何開發了。重點就是三步。
- 1、在web.xml中配置一個serlvet,用來控制,
- 2、編寫一個handler(controller)類,用來做業務處理。
- 3、編寫jsp或者別的視圖,用來展示數據
思路已經有了,那么就開始編寫吧。
問題描述:使用springmvc來完成前端請求的處理
2.1、創建web工程
2.2、添加jar包
2.3、編程步驟
前面三步只是通過mvc圖的分析出最關鍵的三步,其中實現的時候步驟應該更多,比如spring的配置文件,但關鍵的重點還是那三個。
- 1、創建po類
- 2、配置前端控制器,DispatcherServlet
- 3、創建springmvc的配置文件
- 4、開發handler(controller)
- 5、在springmvc的配置文件中(取名為springmvc.xml)配置handler
- 6、開發jsp或者別的視圖
- 8、部署測試
2.4、創建po類
2.5、配置前端控制器
1 <!-- springmvc 的前端控制器 -->
2 <servlet>
3 <servlet-name>springmvc</servlet-name>
4 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
5 <!-- 指定springmvc的配置文件的地址 -->
6 <init-param>
7 <param-name>contextConfigLocation</param-name>
8 <param-value>classpath:springmvc.xml</param-value>
9 </init-param>
10 </servlet>
11 <servlet-mApping>
12 <servlet-name>springmvc</servlet-name>
13 <!-- 這里有三種配置url-pattern方案
14 1、*.do:后綴為.do的請求才能夠訪問到該servlet[用這個]
15 2、/ :所有請求都能夠訪問到該servlet(除jsp),包括靜態請求(處理會有問題,不用)
16 3、/* :有問題,因為訪問jsp也會到該servlet,而訪問jsp時,我們不需要這樣,也不用
17 -->
18 <url-pattern>*.do</url-pattern>
19 </servlet-mapping>
2.6、創建springmvc的配置文件
在config目錄下,創建springmvc.xml文件
<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"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd ">
</beans>
2.7、開發handler(controller)類,也就是處理業務邏輯的類,
2.8、在springmvc.xml中配置handler類,也就是spring幫我們創建該類的實例,所以需要配置。
注意:2.7和2.8一起講解,因為開發handler類講解三種方式,所以配置也連在一起講解,以免分開來,看不清楚
Springmvc開發handler有多種方式,我們只講解三種:實現HttpRequestHandler接口、實現Controller接口、使用注解開發(掌握)
實現HttpRequestHandler接口
1 package com.wuhao.springmvc.controller;
2
3 import JAVA.io.IOException;
4 import java.util.ArrayList;
5 import java.util.List;
6
7 import javax.servlet.ServletException;
8 import javax.servlet.http.HttpServletRequest;
9 import javax.servlet.http.HttpServletResponse;
10
11 import org.springframework.web.HttpRequestHandler;
12
13 import com.wuhao.springmvc.domain.Items;
14
15 public class ItemController implements HttpRequestHandler {
16
17 @Override
18 public void handleRequest(HttpServletRequest request, HttpServletResponse response)
19 throws ServletException, IOException {
20 //獲取商品列表(用靜態數據模擬)
21 List<Items> itemsList = new ArrayList<Items>();
22
23 Items items_1 = new Items();
24 items_1.setName("聯想筆記本 HttpRequestHandler");
25 items_1.setPrice(6000f);
26 items_1.setDetail("ThinkPad T430 聯想筆記本電腦!");
27
28 Items items_2 = new Items();
29 items_2.setName("蘋果手機");
30 items_2.setPrice(5000f);
31 items_2.setDetail("iphone6蘋果手機!");
32
33 itemsList.add(items_1);
34 itemsList.add(items_2);
35
36 //把商品數據放到request域中
37 request.setAttribute("itemsList", itemsList);
38 //指定視圖
39 request.getRequestDispatcher("/WEB-INF/jsp/items/itemsList.jsp").forward(request, response);
40
41 }
42
43 }
springmvc.xml中配置該處理器
通過localhost:8080/項目名/queryItems01.do 就能夠訪問到DispatcherSerlvet,該servlet就會幫我們找到你對應的處理器(依據就是通過下面的這行配置,queryItems01對應了一個處理器的class,也就能夠找到)
1 <!-- 配置實現HttpRequestHander接口的處理器 -->
2 <bean name="/queryItems01.do" class="com.wuhao.springmvc.controller.ItemController"></bean>
實現Controller接口
1 package com.wuhao.springmvc.controller;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import javax.servlet.http.HttpServletRequest;
7 import javax.servlet.http.HttpServletResponse;
8
9 import org.springframework.web.servlet.ModelAndView;
10 import org.springframework.web.servlet.mvc.Controller;
11
12 import com.wuhao.springmvc.domain.Items;
13
14 public class ItemController02 implements Controller {
15
16 @Override
17 public ModelAndView handleRequest(HttpServletRequest request,
18 HttpServletResponse response) throws Exception {
19 //獲取商品列表(用靜態數據模擬)
20 List<Items> itemsList = new ArrayList<Items>();
21
22 Items items_1 = new Items();
23 items_1.setName("聯想筆記本 Controller");
24 items_1.setPrice(6000f);
25 items_1.setDetail("ThinkPad T430 聯想筆記本電腦!");
26
27 Items items_2 = new Items();
28 items_2.setName("蘋果手機");
29 items_2.setPrice(5000f);
30 items_2.setDetail("iphone6蘋果手機!");
31
32 itemsList.add(items_1);
33 itemsList.add(items_2);
34
35 //實現Controller接口的話,就必須使用MoldeAndView對象來將數據裝載到對應的jsp視圖上,然后返回該對象即可
36 //所以需要兩步,將數據給該對象,將指定的視圖在交給該對象,最后返回該對象即可。
37 ModelAndView mv = new ModelAndView();
38 //類似于request.setAttribute("itemsList", itemsList);
39 mv.addObject("itemsList", itemsList);
40
41 //指定視圖
42 mv.setViewName("/WEB-INF/jsp/items/itemsList.jsp");
43
44 return mv;
45
46 }
47
48 }
配置該handler類
<!-- 配置實現Controller接口的處理器 -->
<bean name="/queryItems02.do" class="com.wuhao.springmvc.controller.ItemController02"></bean>
使用注解開發
注解的配置,就是配置一個掃描器,掃描使用了注解的地方
<!-- 使用注解的handle,則需要配置組件掃描器,加載handler
base-package:指定要掃描的包
-->
<context:component-scan
base-package="com.wuhao.springmvc.controller"
></context:component-scan>
2.9、開發jsp
在WEB-INF/jsp/items/下創建jsp:itemsList.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>查詢商品列表</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/item/queryItem.action" method="post">
查詢條件:
<table width="100%" border=1>
<tr>
<td><input type="submit" value="查詢"/></td>
</tr>
</table>
商品列表:
<table width="100%" border=1>
<tr>
<td>商品名稱</td>
<td>商品價格</td>
<td>生產日期</td>
<td>商品描述</td>
<td>操作</td>
</tr>
<c:forEach items="${itemsList }" var="item">
<tr>
<td>${item.name }</td>
<td>${item.price }</td>
<td><fmt:formatDate value="${item.createtime}" pattern="yyyy-MM-dd HH:mm:ss"/></td>
<td>${item.detail }</td>
<td><a href="${pageContext.request.contextPath }/editItems.do?id=${item.id}">修改</a></td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
2.10、部署測試
測試上面三種采用不同的方式編寫的處理類。能夠成功訪問即成功
三、springmvc框架原理圖分析
前面了解了springmvc的mvc設計模式的運用并且還編寫了一個簡單的實例,關鍵點就幾個,配置DispatcherServlet,編寫處理類以及配置,jsp,就mvc的三個關鍵點,但是這也是粗略的使用一下springmvc,并不知道其中運行的原理,比如
- springmvc是如何找到處理器的?
- springmvc如何執行處理器的?
- springmvc如何查找到視圖對象的?
看圖即可
- 1、發起請求到前端控制器(DispatcherServlet),該控制器中就會過濾出你哪些請求可以訪問該servlet哪些不可以,就是url-pattern的作用,并且會加載springmvc.xml配置文件
- 2、前端控制器會找到HandlerMapping(處理器映射器),通過HandlerMapping完成url到controller映射的組件,通俗點講,就是將在springmvc.xml中配置的或者注解的url與對應的處理類找到并進行存儲,實際上是用一個map集合來保存這種映射關系,map<url,handler>; 這樣,就將所有的這種映射關系都記錄保存了下來
- 3、通過HandlerMapping有了這些映射關系,并且找到了url對應的處理器,HandlerMapping就會將其處理器(圖中紅色標明的handler)返回,在其返回之前,再加上很多的攔截器,其作用后面
- 進行講解,這里知道在返回的處理器前會有很多的攔截器即可。
- 4、DispatcherServlet拿到了handler之后,找到HandlerAdapter(處理器適配器),通過它來訪問處理器,并且執行處理器。
這里會有人會有疑惑,為什么需要處理器適配器,我們都獲得了處理類了,直接調用不就行了嗎?
不行,因為我們只知道處理類在哪里,并不知道執行處理類中的哪個方法,其實也就是不知道處理類是通過哪種方式創建出來的,實現HttpRequestHandler?還是注解方式,或者是 其他方式,我們不知道,所以需要HandlerAdapter來幫我們確認調用哪個方法。
- 5、執行處理器
- 6、處理器會返回一個ModelAndView對象給HandlerAdapter
- 7、通過HandlerAdapter將ModelAndView對象返回給前端控制器(DispatcherServlet)
- 8、前端控制器請求視圖解析器(ViewResolver)去進行視圖解析,根據邏輯視圖名解析成真正的視圖(jsp),其實就是將ModelAndView對象中存放視圖的名稱進行查找,找到對應的頁面形成視圖對象
- 9、返回視圖對象到前端控制器。
- 10、視圖渲染,就是將ModelAndView對象中的數據放到request域中,用來讓頁面加載數據的。
- 11、通過第8步,通過名稱找到了對應的頁面,通過第10步,request域中有了所需要的數據,那么就能夠進行視圖渲染了。最后將其返回即可。
通過上面的圖和分析過程,就能夠完美解答上面的三個問題了。理解了圖,那么springmvc就會用了。很簡單吧,跟struts2差不多,記住原理圖即可。
四、組件分析(默認組件和手動配置組件)
通過圖可以看到
- 前端控制器:對其他組件進行解耦,這樣就增加了組件的可擴展性 無需開發直接配置
- 處理器映射器:無需開發,直接用,作用見上面
- 處理器適配器:無需開發,
- 處理器:需要開發,方式很多
- 視圖解析器:無需開發
- 視圖:需要開發
就這么點東西,真正需要寫的就兩個(處理器+視圖)和一個配置(前端控制器),就是mvc中的三個重點,在第二小節中就是這樣編寫的,第三小結就是解釋其中的原理。
處理器映射器、處理器適配器、視圖解析器這三個是默認配置的,在下面位置中可以查看
DispatchServlet.properties
BeanNameUrlHandlerMapping:映射器
4.1、非注解的處理器映射器和處理器適配器 [看看即可]
BeanNameUrlHandlerMapping:映射器
在springmvc配置文件中,配置BeanNameUrlHandlerMapping
他的作用是找到在springmvc.xml中配置的url和處理器的bean
HttpRequestHandlerAdapter:適配執行實現了HttpRequestHandler接口的處理類的方法
在springmvc配置文件中,配置HttpRequestHandlerAdapter
它的作用就是適配實現了HttpRequestHandler接口的處理類,也就是找到該處理類對應的方法
如何適配,就是需要看源碼了,可以百度一下講解該適配器的源碼。
SimpleControllerHandlerAdapter:適配執行實現了Controller接口的處理類的方法
在springmvc配置文件中,配置
SimpleControllerHandlerAdapter
總結:這就是非注解的組件的配置方式,很簡單,注意
- 處理器映射器和處理器適配器可以配置多個
- 處理器映射器和處理器適配器可以混用
4.2、配置注解的處理器映射器和適配器(掌握)
- org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping 是在spring3.1之前使用的注解映射器
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping是在spring3.1之后使用的注解映射器
- org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter 是在spring3.1之前使用的注解適配器
- org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter是在spring3.1之后使用的注解配置器
注意:
1、注解方式的映射器和適配器在3.1版本前后是不一樣的,使用3.1之后的
2、注解方式的處理器映射器和處理器適配器必須配對使用,不能與非注解的處理器映射器和適配器混用(用了注解的就不能在配置非注解的,二選一)
配置方式有兩種:
1、使用bean標簽配置
2、使用mvc標簽(推薦)
4.3、視圖解析器
4.3.1、JSP視圖解析器(默認的就是使用該解析器)
其中兩個配置的意思是:prefix:前綴 suffix:后綴 。 配置之后在指定視圖時,就不用寫這前綴和后綴了,直接寫關鍵代碼即可。看下圖
雖然指定視圖只寫 items/itemsList 但是會幫我們加上我們配置的前綴和后綴,也就是變為了
/WEB-INF/jsp/items/itemsList.jsp
4.3.2 Freemarker視圖解析器
org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver
等什么時候使用到了在學習把。
五、requestMapping注解的三種功能
requestMapping有三種功能:映射請求url、窄化請求、限制請求方法
5.1、映射請求url
也就是寫在方法上,上面我們已經用過了這種功能,這里詳細講解一下
@RequestMapping(value="/item,/user")或@RequestMapping("/item”) value是數組,可以將多個url映射到同一個方法上,用逗號隔開即可。如果value中只有一個屬性,則可以省去value,就像這樣:@RequestMapping(value="/item ")寫成@RequestMapping("/item”)
5.2、窄化請求
在class上面加上requestmapping注解,可以對url進行分類管理,這樣也實現了請求的窄化
加在class上
加在方法上
訪問路徑為:
http://localhost:8080/xxx/items/queryItems.do
5.3、限制請求方法
限制訪問該方法必須是get或者post方式,相當于對請求進行過濾。
限定GET方法,也就是只能允許get請求方式過來的請求訪問
@RequestMapping(method = RequestMethod.GET)
如果post請求方式的過來訪問,則報錯 HTTP Status 405 - Request method 'POST' not supported
限定post方法。
@RequestMapping(method = RequestMethod.POST)
可以通過response指定響應結果,例如響應json數據如下
get、post都可以@RequestMapping(method={RequestMethod.GET,RequestMethod.POST})
六、controller類中的方法返回值問題
同樣有三種:ModelAndView對象、void、String
6.1、返回ModelAndView對象
controller方法中定義ModelAndView對象并返回,對象中可添加model數據、指定view。 然后通過視圖解析器對其進行解析。上面用的就是這個。不用再過多地解釋了
6.2、void
如果返回值為void的時候,可以在controller方法形參上定義request和response,使用request或response指定響應結果(這里在形參上定義request和response,還沒講到。但是可以這樣用,相當于controller方法上默認有這兩個形參。加上去就可以使用)
使用request轉向頁面,如下
request.getRequestDispatcher("頁面路徑").forward(request, response)
通過response頁面重定向
response.sendRedirect("url")
可以通過response指定響應結果,例如響應json數據如下
response.setCharacterEncoding("utf-8");
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("json串");
6.3、String
使用一:返回邏輯視圖
解釋:形參中有Model對象,該對象也是默認形參,只要聲明了,就可以拿過來用,該Model對象的作用就是添加屬性到request作用域中的,就跟ModelAndView對象添加值到request作用域中一樣,只是model對象不能夠指定視圖。正好其model就是modelAndView的一半,很好理解。 其次,因為沒有采用modelAndView對象,所以不能夠指定視圖,但是可以直接返回視圖地址即可,效果是跟使用modelAndView對象一樣的。
使用二:請求轉發