JavaEE學習之Spring MVC框架
一、Spring MVC 簡介
-
簡介
Spring Web MVC是一種基於Java的實現了Web MVC設計模式的請求驅動型別的輕量級Web框架,即使用了MVC架構模式的思想,將web層進行職責解耦,基於請求驅動指的就是使用請求-響應模型,框架的目的就是幫助我們簡化開發,Spring Web MVC也是要簡化我們日常Web開發的。
-
模型封裝了應用程式資料,並且通常它們由 POJO 組成。
-
檢視主要用於呈現模型資料,並且通常它生成客戶端的瀏覽器可以解釋的 HTML 輸出。
-
控制器主要用於處理使用者請求,並且構建合適的模型並將其傳遞到檢視呈現。
DispatcherServlet
Spring Web 模型-檢視-控制(MVC)框架是圍繞 DispatcherServlet 設計的,DispatcherServlet 用來處理所有的 HTTP 請求和響應。Spring Web MVC DispatcherServlet 的請求處理的工作流程如下圖所示:
-
收到一個 HTTP 請求後,DispatcherServlet
-
控制器接受請求,並基於使用的 GET 或 POST 方法來呼叫適當的 service 方法。Service 方法將設定基於定義的業務邏輯的模型資料,並返回檢視名稱到 DispatcherServlet 中。
-
DispatcherServlet 會從 ViewResolver 獲取幫助,為請求檢取定義檢視。
-
一旦確定檢視,DispatcherServlet 將把模型資料傳遞給檢視,最後呈現在瀏覽器中。
-
-
Spring MVC和Spring的關係
二、Spring MVC 入門程式
-
匯入jar包
-
配置web.xml檔案
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>
contextConfigLocation
</param-name>
<param-value>
classpath:spring-mvc.xml
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
-
配置springmvc核心配置檔案
<?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:p="http://www.springframework.org/schema/p"
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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<!--配置後端控制器(controller) -->
<bean name="/hello" class="cn.qn.controller.HomeController"></bean>
<!--配置處理器對映器 -->
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>
<!--配置處理器介面卡 -->
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter">
</bean>
<!-- 配置檢視解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
-
新建後端控制器(HomeController)
public class HomeController extends AbstractController{
-
配置tomcat,啟動專案
三、Spring MVC 註解使用
-
使用註解的後端處理控制器
-
開啟註解掃描(此處附處理器對映器和介面卡的其他配置方式)
<?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">
<!-- 處理器對映器和處理器介面卡的配置可以省略
springMVC框架已經做了處理
-->
<!-- 配置處理器對映器 -->
<!-- <bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"></bean>-->
<!-- 使用最新版的 處理器對映器
若使用最新版的,則處理器對映器和處理器介面卡都要配置最新版的
-->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping"></bean>-->
<!-- 配置處理器介面卡 -->
<!-- <bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"></bean>-->
<!--使用新版的處理器介面卡 -->
<!-- <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"></bean>-->
<!-- springmvc自動配置最新的處理器對映器和處理器介面卡 -->
<mvc:annotation-driven></mvc:annotation-driven>
<!-- 配置後端控制器(controller) -->
<!-- <bean name="/hello" class="cn.edu.dgut.controller.HelloController"></bean>-->
<!-- 開啟掃描 -->
<context:component-scan base-package="cn.edu.dgut.controller"></context:component-scan>
<!-- 配置檢視解析器 若在控制器類寫了完整路徑,則不用配置 -->
<!--<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"></property>
<property name="suffix" value=".jsp"></property>
</bean>-->
</beans>
四、Spring MVC 引數繫結
-
預設支援普通servlet的方式
-
Spring 的 BeanFactory 容器
這是一個最簡單的容器,它主要的功能是為依賴注入 (DI) 提供支援,這個容器介面在 org.springframework.beans.factory.BeanFactor 中被定義。BeanFactory 和相關的介面,比如BeanFactoryAware、DisposableBean、InitializingBean,仍舊保留在 Spring 中,主要目的是向後相容已經存在的和那些 Spring 整合在一起的第三方框架。
-
Spring ApplicationContext 容器
Application Context 是 BeanFactory 的子介面,也被成為 Spring 上下文。
Application Context 是 spring 中較高階的容器。和 BeanFactory 類似,它可以載入配置檔案中定義的 bean,將所有的 bean 集中在一起,當有請求的時候分配 bean。 另外,它增加了企業所需要的功能,比如,從屬性檔案中解析文字資訊和將事件傳遞給所指定的監聽器。這個容器在 org.springframework.context.ApplicationContext interface 介面中定義。
ApplicationContext 包含 BeanFactory 所有的功能,一般情況下,相對於 BeanFactory,ApplicationContext 會更加優秀。當然,BeanFactory 仍可以在輕量級應用中使用,比如移動裝置或者基於 applet 的應用程式。
-
Bean
被稱作 bean 的物件是構成應用程式的支柱也是由 Spring IoC 容器管理的。bean 是一個被例項化,組裝,並通過 Spring IoC 容器所管理的物件。
-
Bean 的作用域
當在 Spring 中定義一個 bean 時,你必須宣告該 bean 的作用域的選項。例如,為了強制 Spring 在每次需要時都產生一個新的 bean 例項,你應該宣告 bean 的作用域的屬性為 prototype。同理,如果你想讓 Spring 在每次需要時都返回同一個bean例項,你應該宣告 bean 的作用域的屬性為 singleton。
作用域 描述 singleton 在spring IoC容器僅存在一個Bean例項,Bean以單例方式存在,預設值 prototype 每次從容器中呼叫Bean時,都返回一個新的例項,即每次呼叫getBean()時,相當於執行newXxxBean() request 每次HTTP請求都會建立一個新的Bean,該作用域僅適用於WebApplicationContext環境 session 同一個HTTP Session共享一個Bean,不同Session使用不同的Bean,僅適用於WebApplicationContext環境 global-session 一般用於Portlet應用環境,該運用域僅適用於WebApplicationContext環境
-
簡單型別(引數名要與jsp中name屬性值對應)
-
實體物件(jsp中name屬性名要與實體中屬性對應)
五、Spring MVC 控制器返回值
-
ModelAndView
modelAndView.addObject("itemList", list); //指定返回頁面的資料 modelAndView.setViewName("itemList"); //指定返回的頁面
-
String(推薦使用)
返回普通字串,就是頁面去掉副檔名的名稱, 返回給頁面資料通過Model來完成
-
普通跳轉(jsp頁面)
@RequestMapping(value="/updateProduct") public String updateProduct(Product product,Model model) throws ServletException { productservice.update(product); model.addAttribute("xxx",”xxxx”); return " productItem "; }
-
請求轉發(請求)
@RequestMapping(value="/updateProduct") public String updateProduct(Product product,Model model) throws ServletException { productservice.update(product); model.addAttribute("msg","今天天氣不錯呀"); return "forward:list"; }
-
重定向(請求)
@RequestMapping(value="/updateProduct") public String updateProduct(Product product,Model model) throws ServletException { productservice.update(product); model.addAttribute("msg","今天天氣不錯呀"); //return "forward:list"; return "redirect:list"; }
-
-
void(破壞了springMvc的結構,不建議使用)
-
可以使用request.setAttribut 來給頁面返回資料
-
可以使用request.getRquestDispatcher().forward()來指定返回的頁面
-
如果controller返回值為void則不走springMvc的元件,所以要寫頁面的完整路徑名稱
-
六、Spring MVC 亂碼問題
-
解決post亂碼問題(在web.xml中加入過濾器配置)
<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> </filter> <filter-mapping> <filter-name>CharacterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
-
get亂碼問題
-
修改tomcat配置檔案新增編碼與工程編碼一致,如下:
<Connector URIEncoding="utf-8" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
-
也可以對引數進行重新編碼
String username= new String(request.getParamter("userName").getBytes("ISO8859-1"),"utf-8");
-
七、Spring MVC 自定義轉換器
-
編寫自定義轉換器類
public class CustomerConveter implements Converter<String, Date>{ @Override public Date convert(String source) { try { Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(source); return date; } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } }
-
在springmvc.xml中配置自定義轉換器
<!--配置自定義轉換器 --> <bean name="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean"> <property name="converters"> <set> <bean class="com.shop.conveter.CustomerConveter"></bean> </set> </property> </bean>
-
將配置好的自定義轉換器掛載(springmvc.xml)
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
八、Spring MVC 檔案上傳
-
準備jar包
-
jsp客戶端準備
-
提供一個File上傳表單控制元件
-
指定表單型別
!-- 上傳圖片是需要指定屬性 enctype="multipart/form-data" --> <form id="itemForm" action="${pageContext.request.contextPath}/updateProduct" method="post" enctype="multipart/form-data">
-
-
配置SpringMVC檔案上傳
<!-- 配置檔案上傳 --> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 配置上傳圖片最大上限 5M --> <property name="maxUploadSize"> <value>5242880</value> </property> </bean>
-
上傳後臺程式碼實現
@RequestMapping(value="/updateProduct") public ModelAndView updateProduct(MultipartFile pictureFile,Product product) throws IllegalStateException, IOException { if(!pictureFile.isEmpty()) { // 獲取圖片的完整路徑 String fileName = pictureFile.getOriginalFilename(); // 使用隨機生成的字串 + 原圖片的副檔名 組成 String NewFileName = UUID.randomUUID().toString()+fileName.substring(fileName.lastIndexOf(".")); // 將圖片儲存在伺服器 (硬碟) pictureFile.transferTo(new File("D:\\images\\"+NewFileName)); // 儲存在資料庫 product.setPic(NewFileName); } //product.setCreatetime(new Date()); //執行修改功能 productservice.update(product); ModelAndView mv = new ModelAndView(); mv.setViewName("test"); return mv; }
九、Spring MVC json資料互動
-
匯入jar包
-
配置json轉換器(如果使用
<mvc:annotation-driven />
則不用配置以下的內容)<!--註解介面卡 --> <bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter"> <property name="messageConverters"> <list> <bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"></bean> </list> </property> </bean>
-
編寫前端
-
匯入jquery檔案
<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.4.4.min.js"></script>
-
編寫Ajax方法
<script type="text/javascript"> //請求json響應json function sendjson() { $.ajax({ type:"post", url:"${pageContext.request.contextPath}/sendjson", contentType:"application/json;charset=utf-8", data:'{"name":"iphoneX爆款手機","price":8000.9}', success:function(data){ alert(data); } }); } </script> <input type="button" value="傳送json" onclick="sendjson()">
-
-
controller編寫
@RequestMapping(value="/sendjson") @ResponseBody //將物件轉成json格式 public Product sendjson(@RequestBody Product product) { System.out.println("product:"+product); return product; }
十、Spring MVC RESTful支援
-
RESTful概念
Representational State Transfer,即表述性轉移,是一種軟體架構的風格(一個規範),不是一門技術。
-
REST和傳統方式對比
-
傳統方式
https://movie.douban.com/subject?id=26416062
-
restful風格
https://movie.douban.com/subject/26416062
-
-
REST風格好處
-
使用傳統url方式進行引數引數的時候,如果需要傳遞引數,那麼中文亂碼很頭疼
-
n 傳統url方式,對於各大搜索引擎的收錄,並不是很友好,但是rest風格方式,搜尋引擎就更加酷愛
-
-
RESTful使用
<%-- <td><a href="${pageContext.request.contextPath }/itemEdit?id=${item.id}">修改</a></td> --%> <td><a href="${pageContext.request.contextPath }/itemEdit/${item.id}">修改</a></td>
@RequestMapping(value="/itemEdit/{id}") public ModelAndView getProductById(@PathVariable("id")Integer aa,HttpServletRequest req, HttpServletResponse response, HttpSession ss) { //String id = req.getParameter("id"); //Product product = productservice.getProductById(Integer.parseInt(id)); Product product = productservice.getProductById(aa); ...
十一、Spring MVC 異常處理(自定義異常)
-
新建一個自定義異常類
public class MyException extends Exception{ private String msg; public MyException(String msg) { super(); this.msg = msg; } public MyException() { super(); // TODO Auto-generated constructor stub } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } }
-
定義異常處理器
public class GoableException implements HandlerExceptionResolver{ @Override public ModelAndView resolveException(HttpServletRequest req, HttpServletResponse response, Object handler, Exception exception) { String res = "出bug了,請聯絡管理員"; if(exception instanceof MyException) { res = ((MyException)exception).getMsg(); } ModelAndView mv = new ModelAndView(); mv.addObject("msg", res); mv.setViewName("error"); return mv; } }
-
測試方法
@RequestMapping(value="/list") public void getList(HttpServletRequest req,HttpServletResponse response) throws ServletException, IOException, MyException { if(true) { throw new MyException("您沒有找到一些商品哈哈哈"); } // 製造異常情況 int i = 1/0; List<Product> list = productservice.getProductList();
十二、Spring MVC 攔截器
Spring Web MVC 的處理器攔截器類似於Servlet 開發中的過濾器Filter,用於對處理器進行預處理和後處理。
-
定義攔截器
Public class HandlerInterceptor1 implements HandlerInterceptor{ /** * controller執行前呼叫此方法 * 返回true表示繼續執行,返回false中止執行 * 這裡可以加入登入校驗、許可權攔截等 */ @Override Public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // TODO Auto-generated method stub Return false; } /** * controller執行後但未返回檢視前呼叫此方法 * 這裡可在返回使用者前對模型資料進行加工處理,比如這裡加入公用資訊以便頁面顯示 */ @Override Public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } /** * controller執行後且檢視返回後呼叫此方法 * 這裡可得到執行controller時的異常資訊 * 這裡可記錄操作日誌,資源清理等 */ @Override Public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
-
配置攔截器(springmvc.xml)
-
針對某種mapping配置攔截器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"> <property name="interceptors"> <list> <ref bean="handlerInterceptor1"/> <ref bean="handlerInterceptor2"/> </list> </property> </bean> <bean id="handlerInterceptor1" class="springmvc.intercapter.HandlerInterceptor1"/> <bean id="handlerInterceptor2" class="springmvc.intercapter.HandlerInterceptor2"/>
-
針對所有mapping配置全域性攔截器
<!--攔截器 --> <mvc:interceptors> <!--多個攔截器,順序執行 --> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.shop.springmvc.filter.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**"/> <bean class="com.shop.springmvc.filter.HandlerInterceptor2"></bean> </mvc:interceptor> </mvc:interceptors>
-
本文是學習spring mvc的筆記總結,歡迎大家批評指正,有什麼問題可以評論區交流。