文章目錄
- SpringMVC
- 1、回顧MVC
- 1.1、什么是MVC
- 1.2、Model1時代
- 1.3、Model2時代
- 1.4、回顧Servlet
- 2、什么是SpringMVC
- 2.1、概述
- 2.2、中心控制器
- 2.3、SpringMVC執行原理
- 3、第一個MVC程式
- 3.1、配置版
- 3.2、注解版
- 小結
- 4、RestFul和控制器
- 4.1、控制器Controller
- 4.2、實作Controller介面
- 使用注解@Controller
- RequestMapping
- RestFul 風格
- 擴展:小黃鴨除錯法
- 5、結果跳轉方式
- 5.1、ModelAndView
- 5.2、ServletAPI
- 5.3、SpringMVC
- 6、資料處理
- 6.1、處理提交資料
- 6.2、資料顯示到前端
- 6.3、對比
- 7、亂碼問題
- 8、Json互動處理
- 8.1、什么是JSON?
- 8.2、**JSON 和 JavaScript 物件互轉**
- 8.3、Controller回傳JSON資料
- 8.4代碼優化
- 8.5、測驗集合輸出
- 8.6、輸出時間物件
- 8.7、FastJson
- 9、Ajax研究
- 9.1、簡介
- 9.2、偽造Ajax
- 9.3、jQuery.ajax
- 9.4、**Springmvc實作**
- 9.5、注冊提示效果
- 9.6、獲取baidu介面Demo
- 10、攔截器
- 10.1、概述
- 10.2、自定義攔截器
- 10.3、驗證用戶是否登錄 (認證用戶)
- 11、檔案上傳和下載
- 11.1、準備作業
- 11.2、檔案上傳
- 11.3、檔案下載
- 11.3、檔案下載
SpringMVC
1、回顧MVC
1.1、什么是MVC
- MVC是模型(Model)、視圖(View)、控制器(Controller)的簡寫,是一種軟體設計規范,
- 是將業務邏輯、資料、顯示分離的方法來組織代碼,
- MVC主要作用是降低了視圖與業務邏輯間的雙向偶合,
- MVC不是一種設計模式,MVC是一種架構模式,當然不同的MVC存在差異,
**Model(模型):**資料模型,提供要展示的資料,因此包含資料和行為,可以認為是領域模型或JavaBean組件(包含資料和行為),不過現在一般都分離開來:Value Object(資料Dao) 和 服務層(行為Service),也就是模型提供了模型資料查詢和模型資料的狀態更新等功能,包括資料和業務,
**View(視圖):**負責進行模型的展示,一般就是我們見到的用戶界面,客戶想看到的東西,
**Controller(控制器):**接收用戶請求,委托給模型進行處理(狀態改變),處理完畢后把回傳的模型資料回傳給視圖,由視圖負責展示,也就是說控制器做了個調度員的作業,
最典型的MVC就是JSP + servlet + javabean的模式,[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-RvIA8L7I-1613122851049)(SpringMVC課堂筆記.assets/640.png)]

1.2、Model1時代
- 在web早期的開發中,通常采用的都是Model1,
- Model1中,主要分為兩層,視圖層和模型層,
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iqOBGDEs-1613122851051)(SpringMVC課堂筆記.assets/641.png)]

Model1優點:架構簡單,比較適合小型專案開發;
Model1缺點:JSP職責不單一,職責過重,不便于維護;
1.3、Model2時代
Model2把一個專案分成三部分,包括視圖、控制、模型,
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-rdEwr6nt-1613122851052)(SpringMVC課堂筆記.assets/642.webp)]

- 用戶發請求
- Servlet接收請求資料,并呼叫對應的業務邏輯方法
- 業務處理完畢,回傳更新后的資料給servlet
- servlet轉向到JSP,由JSP來渲染頁面
- 回應給前端更新后的頁面
職責分析:
Controller:控制器
- 取得表單資料
- 呼叫業務邏輯
- 轉向指定的頁面
Model:模型
- 業務邏輯
- 保存資料的狀態
View:視圖
- 顯示頁面
Model2這樣不僅提高的代碼的復用率與專案的擴展性,且大大降低了專案的維護成本,Model 1模式的實作比較簡單,適用于快速開發小規模專案,Model1中JSP頁面身兼View和Controller兩種角色,將控制邏輯和表現邏輯混雜在一起,從而導致代碼的重用性非常低,增加了應用的擴展性和維護的難度,Model2消除了Model1的缺點,
1.4、回顧Servlet
-
新建一個Maven工程當做父工程!pom依賴!
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.1.9.RELEASE</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> </dependencies> -
建立一個Moudle:springmvc-01-servlet , 添加Web app的支持!
-
匯入servlet 和 jsp 的 jar 依賴
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>jsp-api</artifactId> <version>2.2</version> </dependency> -
撰寫一個Servlet類,用來處理用戶的請求
package nuc.ss.servlet; //實作Servlet介面 public class HelloServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //取得引數 String method = req.getParameter("method"); if (method.equals("add")){ req.getSession().setAttribute("msg","執行了add方法"); } if (method.equals("delete")){ req.getSession().setAttribute("msg","執行了delete方法"); } //業務邏輯 //視圖跳轉 req.getRequestDispatcher("/WEB-INF/jsp/hello.jsp").forward(req,resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req,resp); } } -
撰寫Hello.jsp,在WEB-INF目錄下新建一個jsp的檔案夾,新建hello.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Kuangshen</title> </head> <body> ${msg} </body> </html> -
在web.xml中注冊Servlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <servlet> <servlet-name>HelloServlet</servlet-name> <servlet-class>com.kuang.servlet.HelloServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HelloServlet</servlet-name> <url-pattern>/user</url-pattern> </servlet-mapping> </web-app> -
配置Tomcat,并啟動測驗
- localhost:8080/user?method=add
- localhost:8080/user?method=delete
MVC框架要做哪些事情
- 將url映射到java類或java類的方法 .
- 封裝用戶提交的資料 .
- 處理請求–呼叫相關的業務處理–封裝回應資料 .
- 將回應的資料進行渲染 . jsp / html 等表示層資料 .
說明:
? 常見的服務器端MVC框架有:Struts、Spring MVC、ASP.NET MVC、Zend Framework、JSF;常見前端MVC框架:vue、angularjs、react、backbone;由MVC演化出了另外一些模式如:MVP、MVVM 等等…
2、什么是SpringMVC
2.1、概述
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-AKI5UwOn-1613122851052)(SpringMVC課堂筆記.assets/1594598769272.png)]

Spring MVC是Spring Framework的一部分,是基于Java實作MVC的輕量級Web框架,
查看官方檔案:https://docs.spring.io/spring/docs/5.2.0.RELEASE/spring-framework-reference/web.html#spring-web
我們為什么要學習SpringMVC呢?
Spring MVC的特點:
- 輕量級,簡單易學
- 高效 , 基于請求回應的MVC框架
- 與Spring兼容性好,無縫結合
- 約定優于配置
- 功能強大:RESTful、資料驗證、格式化、本地化、主題等
- 簡潔靈活
Spring的web框架圍繞DispatcherServlet [ 調度Servlet ] 設計,
DispatcherServlet的作用是將請求分發到不同的處理器,從Spring 2.5開始,使用Java 5或者以上版本的用戶可以采用基于注解形式進行開發,十分簡潔;
正因為SpringMVC好 , 簡單 , 便捷 , 易學 , 天生和Spring無縫集成(使用SpringIoC和Aop) , 使用約定優于配置 . 能夠進行簡單的junit測驗 . 支持Restful風格 .例外處理 , 本地化 , 國際化 , 資料驗證 , 型別轉換 , 攔截器 等等…所以我們要學習 .
最重要的一點還是用的人多 , 使用的公司多 .
2.2、中心控制器
-
Spring的web框架圍繞DispatcherServlet設計,DispatcherServlet的作用是將請求分發到不同的處理器,從Spring 2.5開始,使用Java 5或者以上版本的用戶可以采用基于注解的controller宣告方式,
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-5C6IBAho-1613122851053)(SpringMVC課堂筆記.assets/1594600307868.png)]

Spring MVC框架像許多其他MVC框架一樣, 以請求為驅動 , 圍繞一個中心Servlet分派請求及提供其他功能,DispatcherServlet是一個實際的Servlet (它繼承自HttpServlet 基類),
-
SpringMVC的原理如下圖所示:
當發起請求時被前置的控制器攔截到請求,根據請求引數生成代理請求,找到請求對應的實際控制器,控制器處理請求,創建資料模型,訪問資料庫,將模型回應給中心控制器,控制器使用模型與視圖渲染視圖結果,將結果回傳給中心控制器,再將結果回傳給請求者,
原圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-1LcJHSqU-1613122851055)(SpringMVC課堂筆記.assets/mvc.png)]

中文圖
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-wNm8ZtOs-1613122851056)(SpringMVC課堂筆記.assets/1594603929224.png)]

2.3、SpringMVC執行原理
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-l77Lx03H-1613122851057)(SpringMVC課堂筆記.assets/1594606134497.png)]

圖為SpringMVC的一個較完整的流程圖,實線表示SpringMVC框架提供的技術,不需要開發者實作,虛線表示需要開發者實作,
簡要分析執行流程
-
DispatcherServlet表示前置控制器,是整個SpringMVC的控制中心,用戶發出請求,DispatcherServlet接收請求并攔截請求,
-
我們假設請求的url為 : http://localhost:8080/SpringMVC/hello
-
如上url拆分成三部分:
-
http://localhost:8080 ------> 服務器域名
-
SpringMVC ------> 部署在服務器上的web站點
-
hello ------> 表示控制器
-
通過分析,如上url表示為:請求位于服務器localhost:8080上的SpringMVC站點的hello控制器,
-
-
HandlerMapping為處理器映射,DispatcherServlet呼叫HandlerMapping,HandlerMapping根據請求url查找Handler,
-
HandlerExecution表示具體的Handler,其主要作用是根據url查找控制器,如上url被查找控制器為:hello,
-
HandlerExecution將決議后的資訊傳遞給DispatcherServlet,如決議控制器映射等,
-
HandlerAdapter表示處理器配接器,其按照特定的規則去執行Handler,
-
Handler讓具體的Controller執行,
-
Controller將具體的執行資訊回傳給HandlerAdapter,如ModelAndView,
-
HandlerAdapter將視圖邏輯名或模型傳遞給DispatcherServlet,
-
DispatcherServlet呼叫視圖決議器(ViewResolver)來決議HandlerAdapter傳遞的邏輯視圖名,
-
視圖決議器將決議的邏輯視圖名傳給DispatcherServlet,
-
DispatcherServlet根據視圖決議器決議的視圖結果,呼叫具體的視圖,
-
最終視圖呈現給用戶,
3、第一個MVC程式
3.1、配置版
-
新建一個Moudle , springmvc-02-hello , 添加web的支持!
-
確定匯入了SpringMVC 的依賴!
-
配置web.xml , 注冊DispatcherServlet
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--1.注冊DispatcherServlet--> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!--關聯一個springmvc的組態檔:【servlet-name】-servlet.xml--> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:springmvc-servlet.xml</param-value> </init-param> <!--啟動級別-1--> <load-on-startup>1</load-on-startup> </servlet> <!--/ 匹配所有的請求;(不包括.jsp)--> <!--/* 匹配所有的請求;(包括.jsp)--> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> -
撰寫SpringMVC 的 組態檔!名稱:springmvc-servlet.xml : [servletname]-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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> </beans> -
添加 處理映射器(可省略)
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/> -
添加 處理器配接器(可省略)
<bean class="org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter"/> -
添加 視圖決議器
<!--視圖決議器:DispatcherServlet給他的ModelAndView--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="InternalResourceViewResolver"> <!--前綴--> <property name="prefix" value="/WEB-INF/jsp/"/> <!--后綴--> <property name="suffix" value=".jsp"/> </bean> -
撰寫我們要操作業務Controller ,要么實作Controller介面,要么增加注解;需要回傳一個ModelAndView,裝資料,封視圖;
package nuc.ss.controller; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.Controller; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //注意:這里我們先匯入Controller介面 public class HelloController implements Controller { public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { //ModelAndView 模型和視圖 ModelAndView mv = new ModelAndView(); //封裝物件,放在ModelAndView中,Model mv.addObject("msg","HelloSpringMVC!"); //封裝要跳轉的視圖,放在ModelAndView中 mv.setViewName("hello"); //: /WEB-INF/jsp/hello.jsp return mv; } } -
將自己的類交給SpringIOC容器,注冊bean
<!--Handler--> <bean id="/hello" class="nuc.ss.controller.HelloController"/> -
寫要跳轉的jsp頁面,顯示ModelandView存放的資料,以及我們的正常頁面;
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Kuangshen</title> </head> <body> ${msg} </body> </html> -
配置Tomcat 啟動測驗!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qy5e45Le-1613122851059)(SpringMVC課堂筆記.assets/1595124994780.png)]

可能遇到的問題:訪問出現404,排查步驟:
- 查看控制臺輸出,看一下是不是缺少了什么jar包,
- 如果jar包存在,顯示無法輸出,就在IDEA的專案發布中,添加lib依賴!
- 重啟Tomcat 即可解決!
小結:我們來看個注解版實作,這才是SpringMVC的精髓,
3.2、注解版
-
新建一個Moudle,springmvc-03-hello-annotation ,添加web支持!
-
由于Maven可能存在資源過濾的問題,我們將配置完善
<build> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> </resources> </build> -
在pom.xml檔案引入相關的依賴:主要有Spring框架核心庫、Spring MVC、servlet , JSTL等,我們在父依賴中已經引入了!
-
配置web.xml
注意點:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--1.注冊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-servlet.xml</param-value> </init-param> <!-- 啟動順序,數字越小,啟動越早 --> <load-on-startup>1</load-on-startup> </servlet> <!--所有請求都會被springmvc攔截 --> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> -
/ 和 /* 的區別:
- < url-pattern > / </ url-pattern > 不會匹配到.jsp, 只針對我們撰寫的請求;即:.jsp 不會進入spring的 DispatcherServlet類 ,
- < url-pattern > /* </ url-pattern > 會匹配 *.jsp,會出現回傳 jsp視圖 時再次進入spring的DispatcherServlet 類,導致找不到對應的controller所以報404錯,
-
添加Spring MVC組態檔
在resource目錄下添加springmvc-servlet.xml組態檔,配置的形式與Spring容器配置基本類似,為了支持基于注解的IOC,設定了自動掃描包的功能,具體配置資訊如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 自動掃描包,讓指定包下的注解生效,由IOC容器統一管理 --> <context:component-scan base-package="nuc.ss.controller"/> <!-- 讓Spring MVC不處理靜態資源 --> <mvc:default-servlet-handler /> <!-- 支持mvc注解驅動 在spring中一般采用@RequestMapping注解來完成映射關系 要想使@RequestMapping注解生效 必須向背景關系中注冊DefaultAnnotationHandlerMapping 和一個AnnotationMethodHandlerAdapter實體 這兩個實體分別在類級別和方法級別處理, 而annotation-driven配置幫助我們自動完成上述兩個實體的注入, --> <mvc:annotation-driven /> <!-- 視圖決議器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前綴 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后綴 --> <property name="suffix" value=".jsp" /> </bean> </beans>
在視圖決議器中我們把所有的視圖都存放在/WEB-INF/目錄下,這樣可以保證視圖安全,因為這個目錄下的檔案,客戶端不能直接訪問,
-
讓IOC的注解生效
-
靜態資源過濾 :HTML . JS . CSS . 圖片 , 視頻 …
- MVC的注解驅動
- 配置視圖決議器
-
創建Controller
撰寫一個Java控制類:nuc.ss.controller.HelloController , 注意編碼規范
package nuc.ss.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; @Controller @RequestMapping("/HelloController") public class HelloController { //真實訪問地址 : 專案名/HelloController/hello @RequestMapping("/hello") public String sayHello(Model model){ //向模型中添加屬性msg與值,可以在JSP頁面中取出并渲染 model.addAttribute("msg","hello,SpringMVC"); //web-inf/jsp/hello.jsp return "hello"; } }- @Controller是為了讓Spring IOC容器初始化時自動掃描到;
- @RequestMapping是為了映射請求路徑,這里因為類與方法上都有映射所以訪問時應該是/HelloController/hello;
- 方法中宣告Model型別的引數是為了把Action中的資料帶到視圖中;
- 方法回傳的結果是視圖的名稱hello,加上組態檔中的前后綴變成WEB-INF/jsp/hello.jsp
-
創建視圖層
在WEB-INF/ jsp目錄中創建hello.jsp , 視圖可以直接取出并展示從Controller帶回的資訊;
可以通過EL表示取出Model中存放的值,或者物件;
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>SpringMVC</title> </head> <body> ${msg} </body> </html> -
配置Tomcat運行
配置Tomcat , 開啟服務器 , 訪問 對應的請求路徑!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-gbDzUuZt-1613122851060)(SpringMVC課堂筆記.assets/1594622304382.png)]

OK,運行成功!
小結
實作步驟其實非常的簡單:
- 新建一個web專案
- 匯入相關jar包
- 撰寫web.xml , 注冊DispatcherServlet
- 撰寫springmvc組態檔
- 接下來就是去創建對應的控制類 , controller
- 最后完善前端視圖和controller之間的對應
- 測驗運行除錯.
使用springMVC必須配置的三大件
處理器映射器、處理器配接器、視圖決議器
通常,我們只需要手動配置視圖決議器,而處理器映射器和處理器配接器只需要開啟注解驅動即可,而省去了大段的xml配置
4、RestFul和控制器
4.1、控制器Controller
-
控制器復雜提供訪問應用程式的行為,通常通過介面定義或注解定義兩種方法實作,
-
控制器負責決議用戶的請求并將其轉換為一個模型,
-
在Spring MVC中一個控制器類可以包含多個方法
-
在Spring MVC中,對于Controller的配置方式有很多種
4.2、實作Controller介面
Controller是一個介面,在org.springframework.web.servlet.mvc包下,介面中只有一個方法;
//實作該介面的類獲得控制器功能
public interface Controller {
//處理請求且回傳一個模型與視圖物件
ModelAndView handleRequest(HttpServletRequest var1, HttpServletResponse var2) throws Exception;
}
測驗
-
新建一個Moudle,springmvc-04-controller!
-
- mvc的組態檔只留下 視圖決議器!
-
撰寫一個Controller類,ControllerTest1
//定義控制器 //注意點:不要導錯包,實作Controller介面,重寫方法; public class ControllerTest1 implements Controller { public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception { //回傳一個模型視圖物件 ModelAndView mv = new ModelAndView(); mv.addObject("msg","Test1Controller"); mv.setViewName("test"); return mv; } } -
撰寫完畢后,去Spring組態檔中注冊請求的bean;name對應請求路徑,class對應處理請求的類
<bean name="/t1" class="nuc.ss.controller.ControllerTest1"/> -
撰寫前端test.jsp,注意在WEB-INF/jsp目錄下撰寫,對應我們的視圖決議器
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Kuangshen</title> </head> <body> ${msg} </body> </html> -
配置Tomcat運行測驗,我這里沒有專案發布名配置的就是一個 / ,所以請求不用加專案名,OK!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-xn69Bm6v-1613122851061)(SpringMVC課堂筆記.assets/1595128496794.png)]

說明:
-
實作介面Controller定義控制器是較老的辦法
-
缺點是:一個控制器中只有一個方法,如果要多個方法則需要定義多個Controller;定義的方式比較麻煩;
使用注解@Controller
-
@Controller注解型別用于宣告Spring類的實體是一個控制器(在講IOC時還提到了另外3個注解);
-
Spring可以使用掃描機制來找到應用程式中所有基于注解的控制器類,為了保證Spring能找到你的控制器,需要在組態檔中宣告組件掃描,
<!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 --> <context:component-scan base-package="nuc.ss.controller"/> -
增加一個ControllerTest2類,使用注解實作;
//@Controller注解的類會自動添加到Spring背景關系中 @Controller public class ControllerTest2{ //映射訪問路徑 @RequestMapping("/t2") public String index(Model model){ //Spring MVC會自動實體化一個Model物件用于向視圖中傳值 model.addAttribute("msg", "ControllerTest2"); //回傳視圖位置 return "test"; } } -
運行tomcat測驗
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-E1opAo2b-1613122851062)(SpringMVC課堂筆記.assets/1595128649687.png)]

可以發現,我們的兩個請求都可以指向一個視圖(test),但是頁面結果的結果是不一樣的,從這里可以看出視圖是被復用的,而控制器與視圖之間是弱偶合關系,
注解方式是平時使用的最多的方式!
RequestMapping
@RequestMapping
-
@RequestMapping注解用于映射url到控制器類或一個特定的處理程式方法,可用于類或方法上,用于類上,表示類中的所有回應請求的方法都是以該地址作為父路徑,
-
為了測驗結論更加準確,我們可以加上一個專案名測驗 myweb
-
只注解在方法上面
@Controller public class TestController { @RequestMapping("/h1") public String test(){ return "test"; } }訪問路徑:http://localhost:8080 / 專案名 / h1
-
同時注解類與方法
@Controller @RequestMapping("/admin") public class TestController { @RequestMapping("/h1") public String test(){ return "test"; } }訪問路徑:http://localhost:8080 / 專案名/ admin /h1 , 需要先指定類的路徑再指定方法的路徑;
RestFul 風格
概念
Restful就是一個資源定位及資源操作的風格,不是標準也不是協議,只是一種風格,基于這個風格設計的軟體可以更簡潔,更有層次,更易于實作快取等機制,
功能
資源:互聯網所有的事物都可以被抽象為資源
資源操作:使用POST、DELETE、PUT、GET,使用不同方法對資源進行操作,
分別對應 添加、 洗掉、修改、查詢,
傳統方式操作資源 :通過不同的引數來實作不同的效果!方法單一,post 和 get
? http://127.0.0.1/item/queryItem.action?id=1 查詢,GET
? http://127.0.0.1/item/saveItem.action 新增,POST
? http://127.0.0.1/item/updateItem.action 更新,POST
? http://127.0.0.1/item/deleteItem.action?id=1 洗掉,GET或POST
使用RESTful操作資源 :可以通過不同的請求方式來實作不同的效果!如下:請求地址一樣,但是功能可以不同!
? http://127.0.0.1/item/1 查詢,GET
? http://127.0.0.1/item 新增,POST
? http://127.0.0.1/item 更新,PUT
? http://127.0.0.1/item/1 洗掉,DELETE
學習測驗
-
在新建一個類 RestFulController
@Controller public class RestFulController {} -
在Spring MVC中可以使用 @PathVariable 注解,讓方法引數的值對應系結到一個URI模板變數上,
@Controller public class RestFulController { //映射訪問路徑 @RequestMapping("/add/{p1}/{p2}") public String index(@PathVariable int p1, @PathVariable int p2, Model model){ int result = p1+p2; //Spring MVC會自動實體化一個Model物件用于向視圖中傳值 model.addAttribute("msg", "結果:"+result); //回傳視圖位置 return "test"; } } -
我們來測驗請求查看下
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-fqjEWtDc-1613122851063)(SpringMVC課堂筆記.assets/1595129216809.png)]

-
思考:使用路徑變數的好處?
-
使路徑變得更加簡潔;
-
獲得引數更加方便,框架會自動進行型別轉換,
-
通過路徑變數的型別可以約束訪問引數,如果型別不一樣,則訪問不到對應的請求方法,如這里訪問是的路徑是/add/1/a,則路徑與方法不匹配,而不會是引數轉換失敗,
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-SHBV02h4-1613122851063)(SpringMVC課堂筆記.assets/1595129271494.png)]

-
-
我們來修改下對應的引數型別,再次測驗
//映射訪問路徑 @RequestMapping("/add/{p1}/{p2}") public String index(@PathVariable int p1, @PathVariable String p2, Model model){ String result = p1+p2; //Spring MVC會自動實體化一個Model物件用于向視圖中傳值 model.addAttribute("msg", "結果:"+result); //回傳視圖位置 return "test"; }[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-3gVukMxl-1613122851063)(SpringMVC課堂筆記.assets/1595129577077.png)]

使用method屬性指定請求型別
用于約束請求的型別,可以收窄請求范圍,指定請求謂詞的型別如GET, POST, HEAD, OPTIONS, PUT, PATCH, DELETE, TRACE等
我們來測驗一下:
-
增加一個方法
//映射訪問路徑,必須是POST請求 @RequestMapping(value = "/hello",method = {RequestMethod.POST}) public String index2(Model model){ model.addAttribute("msg", "hello!"); return "test"; } -
我們使用瀏覽器地址欄進行訪問默認是Get請求,會報錯405:
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-yu3bqIg5-1613122851064)(SpringMVC課堂筆記.assets/1595129829057.png)]

-
如果將POST修改為GET則正常了;
//映射訪問路徑,必須是Get請求 @RequestMapping(value = "/hello",method = {RequestMethod.GET}) public String index2(Model model){ model.addAttribute("msg", "hello!"); return "test"; }[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-tbzf4pRk-1613122851064)(SpringMVC課堂筆記.assets/1595129889298.png)]

小結:
Spring MVC 的 @RequestMapping 注解能夠處理 HTTP 請求的方法, 比如 GET, PUT, POST, DELETE 以及 PATCH,
所有的地址欄請求默認都會是 HTTP GET 型別的,
方法級別的注解變體有如下幾個:組合注解
@GetMapping
@PostMapping
@PutMapping
@DeleteMapping
@PatchMapping
@GetMapping 是一個組合注解,平時使用的會比較多!
它所扮演的是 @RequestMapping(method =RequestMethod.GET) 的一個快捷方式,
擴展:小黃鴨除錯法
場景一:我們都有過向別人(甚至可能向完全不會編程的人)提問及解釋編程問題的經歷,但是很多時候就在我們解釋的程序中自己卻想到了問題的解決方案,然后對方卻一臉茫然,
場景二:你的同行跑來問你一個問題,但是當他自己把問題說完,或說到一半的時候就想出答案走了,留下一臉茫然的你,
其實上面兩種場景現象就是所謂的小黃鴨除錯法(Rubber Duck Debuging),又稱橡皮鴨除錯法,它是我們軟體工程中最常使用除錯方法之一,

此概念據說來自《程式員修煉之道》書中的一個故事,傳說程式大師隨身攜帶一只小黃鴨,在除錯代碼的時候會在桌上放上這只小黃鴨,然后詳細地向鴨子解釋每行代碼,然后很快就將問題定位修復了,
5、結果跳轉方式
5.1、ModelAndView
設定ModelAndView物件 , 根據view的名稱 , 和視圖決議器跳到指定的頁面 .
頁面 : {視圖決議器前綴} + viewName +{視圖決議器后綴}
<!-- 視圖決議器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<!-- 前綴 -->
<property name="prefix" value="/WEB-INF/jsp/" />
<!-- 后綴 -->
<property name="suffix" value=".jsp" />
</bean>
對應的controller類
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//回傳一個模型視圖物件
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
5.2、ServletAPI
ServletAPI
通過設定ServletAPI , 不需要視圖決議器 .
-
通過HttpServletResponse進行輸出
-
通過HttpServletResponse實作重定向
-
通過HttpServletResponse實作轉發
@Controller public class ResultGo { @RequestMapping("/result/t1") public void test1(HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.getWriter().println("Hello,Spring BY servlet API"); } @RequestMapping("/result/t2") public void test2(HttpServletRequest req, HttpServletResponse rsp) throws IOException { rsp.sendRedirect("/index.jsp"); } @RequestMapping("/result/t3") public void test3(HttpServletRequest req, HttpServletResponse rsp) throws Exception { //轉發 req.setAttribute("msg","/result/t3"); req.getRequestDispatcher("/WEB-INF/jsp/test.jsp").forward(req,rsp); } }
5.3、SpringMVC
通過SpringMVC來實作轉發和重定向 - 無需視圖決議器;
測驗前,需要將視圖決議器注釋掉
- 默認為forward轉發(也可以加上)
- redirect轉發需特別加
@Controller
public class ResultSpringMVC {
@RequestMapping("/rsm/t1")
public String test1(){
//轉發
return "/index.jsp";
}
@RequestMapping("/rsm/t2")
public String test2(){
//轉發二
return "forward:/index.jsp";
}
@RequestMapping("/rsm/t3")
public String test3(){
//重定向
return "redirect:/index.jsp";
}
}
通過SpringMVC來實作轉發和重定向 - 有視圖決議器;
重定向 , 不需要視圖決議器 , 本質就是重新請求一個新地方嘛 , 所以注意路徑問題.
可以重定向到另外一個請求實作 .
- 默認為forward轉發(不可以加上)
- redirect轉發需特別加
@Controller
public class ResultSpringMVC2 {
@RequestMapping("/rsm2/t1")
public String test1(){
//轉發
return "test";
}
@RequestMapping("/rsm2/t2")
public String test2(){
//重定向
return "redirect:/index.jsp";
//return "redirect:hello.do"; //hello.do為另一個請求/
}
}
6、資料處理
6.1、處理提交資料
1、提交的域名稱和處理方法的引數名一致
提交資料 : http://localhost:8080/hello?name=kuangshen
處理方法 :
@RequestMapping("/hello")
public String hello(String name){
System.out.println(name);
return "hello";
}
后臺輸出 : kuangshen
2、提交的域名稱和處理方法的引數名不一致
提交資料 : http://localhost:8080/hello?username=kuangshen
處理方法 :
//@RequestParam("username") : username提交的域的名稱 .
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name){
System.out.println(name);
return "hello";
}
后臺輸出 : kuangshen
3、提交的是一個物件
要求提交的表單域和物件的屬性名一致 , 引數使用物件即可
-
物體類
public class User { private int id; private String name; private int age; //構造 //get/set //tostring() } -
提交資料 : http://localhost:8080/mvc04/user?name=kuangshen&id=1&age=15
-
處理方法 :
@RequestMapping("/user") public String user(User user){ System.out.println(user); return "hello"; }
后臺輸出 : User { id=1, name=‘kuangshen’, age=15 }
說明:如果使用物件的話,前端傳遞的引數名和物件名必須一致,否則就是null,
6.2、資料顯示到前端
第一種 : 通過ModelAndView
我們前面一直都是如此 . 就不過多解釋
public class ControllerTest1 implements Controller {
public ModelAndView handleRequest(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
//回傳一個模型視圖物件
ModelAndView mv = new ModelAndView();
mv.addObject("msg","ControllerTest1");
mv.setViewName("test");
return mv;
}
}
第二種 : 通過ModelMap
ModelMap
@RequestMapping("/hello")
public String hello(@RequestParam("username") String name, ModelMap modelMap){
//封裝要顯示到視圖中的資料
//相當于req.setAttribute("name",name);
modelMap.addAttribute("name",name);
System.out.println(name);
return "hello";
}
第三種 : 通過Model
Model
@RequestMapping("/ct2/hello")
public String hello(@RequestParam("username") String name, Model model){
//封裝要顯示到視圖中的資料
//相當于req.setAttribute("name",name);
model.addAttribute("msg",name);
System.out.println(name);
return "test";
}
6.3、對比
就對于新手而言簡單來說使用區別就是:
Model 只有寥寥幾個方法只適合用于儲存資料,簡化了新手對于Model物件的操作和理解;
ModelMap 繼承了 LinkedMap ,除了實作了自身的一些方法,同樣的繼承 LinkedMap 的方法和特性;
ModelAndView 可以在儲存資料的同時,可以進行設定回傳的邏輯視圖,進行控制展示層的跳轉,
當然更多的以后開發考慮的更多的是性能和優化,就不能單單僅限于此的了解,
請使用80%的時間打好扎實的基礎,剩下18%的時間研究框架,2%的時間去學點英文,框架的官方檔案永遠是最好的教程,
7、亂碼問題
測驗步驟:
-
我們可以在首頁撰寫一個提交的表單
<form action="/e/t" method="post"> <input type="text" name="name"> <input type="submit"> </form> -
后臺撰寫對應的處理類
@Controller public class Encoding { @RequestMapping("/e/t") public String test(Model model,String name){ model.addAttribute("msg",name); //獲取表單提交的值 return "test"; //跳轉到test頁面顯示輸入的值 } } -
輸入中文測驗,發現亂碼
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-HxFI7CDF-1613122851066)(SpringMVC課堂筆記.assets/1595131750549.png)]

不得不說,亂碼問題是在我們開發中十分常見的問題,也是讓我們程式猿比較頭大的問題!
以前亂碼問題通過過濾器解決 , 而SpringMVC給我們提供了一個過濾器 , 可以在web.xml中配置 .
修改了xml檔案需要重啟服務器!
filter>
<filter-name>encoding</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>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意:這里寫/*,寫/的話過濾不了jsp頁面,不能解決亂碼
但是我們發現 , 有些極端情況下.這個過濾器對get的支持不好 .
處理方法 :
-
修改tomcat組態檔 :設定編碼!
<Connector URIEncoding="utf-8" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> -
自定義過濾器(萬能解決)
package com.kuang.filter; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Map; /** * 解決get和post請求 全部亂碼的過濾器 */ public class GenericEncodingFilter implements Filter { @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //處理response的字符編碼 HttpServletResponse myResponse=(HttpServletResponse) response; myResponse.setContentType("text/html;charset=UTF-8"); // 轉型為與協議相關物件 HttpServletRequest httpServletRequest = (HttpServletRequest) request; // 對request包裝增強 HttpServletRequest myrequest = new MyRequest(httpServletRequest); chain.doFilter(myrequest, response); } @Override public void init(FilterConfig filterConfig) throws ServletException { } } //自定義request物件,HttpServletRequest的包裝類 class MyRequest extends HttpServletRequestWrapper { private HttpServletRequest request; //是否編碼的標記 private boolean hasEncode; //定義一個可以傳入HttpServletRequest物件的建構式,以便對其進行裝飾 public MyRequest(HttpServletRequest request) { super(request);// super必須寫 this.request = request; } // 對需要增強方法 進行覆寫 @Override public Map getParameterMap() { // 先獲得請求方式 String method = request.getMethod(); if (method.equalsIgnoreCase("post")) { // post請求 try { // 處理post亂碼 request.setCharacterEncoding("utf-8"); return request.getParameterMap(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } else if (method.equalsIgnoreCase("get")) { // get請求 Map<String, String[]> parameterMap = request.getParameterMap(); if (!hasEncode) { // 確保get手動編碼邏輯只運行一次 for (String parameterName : parameterMap.keySet()) { String[] values = parameterMap.get(parameterName); if (values != null) { for (int i = 0; i < values.length; i++) { try { // 處理get亂碼 values[i] = new String(values[i] .getBytes("ISO-8859-1"), "utf-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); } } } } hasEncode = true; } return parameterMap; } return super.getParameterMap(); } //取一個值 @Override public String getParameter(String name) { Map<String, String[]> parameterMap = getParameterMap(); String[] values = parameterMap.get(name); if (values == null) { return null; } return values[0]; // 取回引數的第一個值 } //取所有值 @Override public String[] getParameterValues(String name) { Map<String, String[]> parameterMap = getParameterMap(); String[] values = parameterMap.get(name); return values; } }一般情況下,SpringMVC默認的亂碼處理就已經能夠很好的解決了!
然后在web.xml中配置這個過濾器即可!
亂碼問題,需要平時多注意,在盡可能能設定編碼的地方,都設定為統一編碼 UTF-8!
8、Json互動處理
8.1、什么是JSON?
- JSON(JavaScript Object Notation, JS 物件標記) 是一種輕量級的資料交換格式,目前使用特別廣泛,
- 采用完全獨立于編程語言的文本格式來存盤和表示資料,
- 簡潔和清晰的層次結構使得 JSON 成為理想的資料交換語言,
- 易于人閱讀和撰寫,同時也易于機器決議和生成,并有效地提升網路傳輸效率,
在 JavaScript 語言中,一切都是物件,因此,任何JavaScript 支持的型別都可以通過 JSON 來表示,例如字串、數字、物件、陣列等,看看他的要求和語法格式:
- 物件表示為鍵值對,資料由逗號分隔
- 花括號保存物件
- 方括號保存陣列
JSON 鍵值對是用來保存 JavaScript 物件的一種方式,和 JavaScript 物件的寫法也大同小異,鍵/值對組合中的鍵名寫在前面并用雙引號 “” 包裹,使用冒號 : 分隔,然后緊接著值:
{"name": "QinJiang"}
{"age": "3"}
{"sex": "男"}
很多人搞不清楚 JSON 和 JavaScript 物件的關系,甚至連誰是誰都不清楚,其實,可以這么理解:
JSON 是 JavaScript 物件的字串表示法,它使用文本表示一個 JS 物件的資訊,本質是一個字串,
var obj = {a: 'Hello', b: 'World'}; //這是一個物件,注意鍵名也是可以使用引號包裹的
var json = '{"a": "Hello", "b": "World"}'; //這是一個 JSON 字串,本質是一個字串
8.2、JSON 和 JavaScript 物件互轉
要實作從JSON字串轉換為JavaScript 物件,使用 JSON.parse() 方法:
var obj = JSON.parse('{"a": "Hello", "b": "World"}');
//結果是 {a: 'Hello', b: 'World'}
要實作從JavaScript 物件轉換為JSON字串,使用 JSON.stringify() 方法:
var json = JSON.stringify({a: 'Hello', b: 'World'});
//結果是 '{"a": "Hello", "b": "World"}'
代碼測驗
-
新建一個module ,springmvc-05-json , 添加web的支持
-
在web目錄下新建一個 json-1.html , 撰寫測驗內容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>JSON_秦疆</title> </head> <body> <script type="text/javascript"> //撰寫一個js的物件 var user = { name:"秦疆", age:3, sex:"男" }; //將js物件轉換成json字串 var str = JSON.stringify(user); console.log(str); //將json字串轉換為js物件 var user2 = JSON.parse(str); console.log(user2.age,user2.name,user2.sex); </script> </body> </html> -
在IDEA中使用瀏覽器打開,查看控制臺輸出!
8.3、Controller回傳JSON資料
-
Jackson應該是目前比較好的json決議工具了
-
當然工具不止這一個,比如還有阿里巴巴的 fastjson 等等,
-
我們這里使用Jackson,使用它需要匯入它的jar包;
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.8</version> </dependency> -
配置SpringMVC需要的配置
-
(web.xml)
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <!--1.注冊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-servlet.xml</param-value> </init-param> <!-- 啟動順序,數字越小,啟動越早 --> <load-on-startup>1</load-on-startup> </servlet> <!--所有請求都會被springmvc攔截 --> <servlet-mapping> <servlet-name>SpringMVC</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> <filter> <filter-name>encoding</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>encoding</filter-name> <url-pattern>/</url-pattern> </filter-mapping> </web-app> -
springmvc-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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 --> <context:component-scan base-package="com.kuang.controller"/> <!-- 視圖決議器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前綴 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后綴 --> <property name="suffix" value=".jsp" /> </bean> </beans> -
我們隨便撰寫一個User的物體類,然后我們去撰寫我們的測驗Controller;
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String name; private int age; } -
這里我們需要兩個新東西,一個是@ResponseBody,一個是ObjectMapper物件,我們看下具體的用法
撰寫一個Controller;
@Controller public class UserController { @RequestMapping("/j1") @ResponseBody//他就不會走視圖決議器,會直接回傳一個 字串 public String json1() throws JsonProcessingException { //jackson,ObjectMapper ObjectMapper mapper = new ObjectMapper(); //創建一個物件 User user = new User(1, "秦疆一號", 12); //System.out.println(user); String str = mapper.writeValueAsString(user); return str; } -
此時輸入中文會產生亂碼
//produces:指定回應體回傳型別和編碼 @RequestMapping(value = "/json1",produces = "application/json;charset=utf-8") -
配置Tomcat , 啟動測驗一下!http://localhost:8080/json1
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-O7hQvSsC-1613122851066)(SpringMVC課堂筆記.assets/1595133634951.png)]

-
【注意:使用json記得處理亂碼問題】
8.4代碼優化
亂碼統一解決
上一種方法比較麻煩,如果專案中有許多請求則每一個都要添加,可以通過Spring配置統一指定,這樣就不用每次都去處理了!
我們可以在springmvc的組態檔上添加一段訊息StringHttpMessageConverter轉換配置!
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<constructor-arg value="UTF-8"/>
</bean>
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
<property name="failOnEmptyBeans" value="false"/>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
回傳json字串統一解決
-
@ResponseBody解決(每個方法都得加,不建議使用)
@Controller public class UserController { //produces:指定回應體回傳型別和編碼 @RequestMapping(value = "/json1") @ResponseBody public String json1() throws JsonProcessingException { //創建一個jackson的物件映射器,用來決議資料 ObjectMapper mapper = new ObjectMapper(); //創建一個物件 User user = new User(1, "秦疆一號", 12); //將我們的物件決議成為json格式 String str = mapper.writeValueAsString(user); //由于@ResponseBody注解,這里會將str轉成json格式回傳;十分方便 return str; } } -
@RestController(直接加到類上即可)
@RestController
public class UserController {
@RequestMapping(value = "/j1")
public String json1() throws JsonProcessingException {
//創建一個jackson的物件映射器,用來決議資料
ObjectMapper mapper = new ObjectMapper();
//創建一個物件
User user = new User(1, "秦疆一號", 12);
//將我們的物件決議成為json格式
String str = mapper.writeValueAsString(user);
return str;
}
}
8.5、測驗集合輸出
增加一個新的方法
@RequestMapping("/j2")
public String json2() throws JsonProcessingException {
//創建一個jackson的物件映射器,用來決議資料
ObjectMapper mapper = new ObjectMapper();
//創建一個物件
User user1 = new User(1, "秦疆1號", 12);
User user2 = new User(2, "秦疆2號", 12);
User user3 = new User(3, "秦疆3號", 12);
User user4 = new User(4, "秦疆4號", 12);
User user5 = new User(5, "秦疆5號", 12);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
list.add(user5);
//將我們的物件決議成為json格式
String str = mapper.writeValueAsString(list);
return str;
}
運行結果 : 十分完美,沒有任何問題!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-v14sPycX-1613122851066)(SpringMVC課堂筆記.assets/1595133587875.png)]

8.6、輸出時間物件
-
增加一個新的方法
@RequestMapping("/j3") public String json3() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); //創建時間一個物件,java.util.Date Date date = new Date(); //將我們的物件決議成為json格式 String str = mapper.writeValueAsString(date); return str; } -
運行結果 :
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-DvI4u73m-1613122851068)(SpringMVC課堂筆記.assets/1595134256420.png)]

-
默認日期格式會變成一個數字,是1970年1月1日到當前日期的毫秒數!
-
Jackson 默認是會把時間轉成timestamps形式
解決方案:取消timestamps形式 , 自定義時間格式
@RequestMapping("/j3")
public String json4() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
//不使用時間戳的方式
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
//自定義日期格式物件
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//指定日期格式
mapper.setDateFormat(sdf);
Date date = new Date();
String str = mapper.writeValueAsString(date);
return str;
}
運行結果 : 成功的輸出了時間!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-qkVbrdmu-1613122851068)(SpringMVC課堂筆記.assets/1595134398126.png)]

抽取為工具類
如果要經常使用的話,這樣是比較麻煩的,我們可以將這些代碼封裝到一個工具類中;我們去撰寫下
public class JsonUtils {
public static String getJson(Object object) {
return getJson(object,"yyyy-MM-dd HH:mm:ss");
}
public static String getJson(Object object, String dateFormat) {
ObjectMapper mapper = new ObjectMapper();
//java自定義日期格式
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
//sdf.format(date)
// 使用ObjectMapper 來格式化輸出
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
mapper.setDateFormat(sdf);
try {
//ObjectMapper,時間決議后的默認格式為:TImestamp.時間戳
return mapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
}
我們使用工具類,代碼就更加簡潔了!
@RequestMapping("/j3")
public String json3(){
Date date = new Date();
return JsonUtils.getJson(date,"yyyy-MM-dd HH:mm:ss");
}
}
大功告成!完美!
8.7、FastJson
- fastjson.jar是阿里開發的一款專門用于Java開發的包,
- 實作json物件與JavaBean物件的轉換,
- 實作JavaBean物件與json字串的轉換,
- 實作json物件與json字串的轉換,
- 實作json的轉換方法很多,最后的實作結果都是一樣的,
fastjson 的 pom依賴!
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
fastjson 三個主要的類:
- JSONObject 代表 json 物件
- JSONObject實作了Map介面, 猜想 JSONObject底層操作是由Map實作的,
- JSONObject對應json物件,通過各種形式的get()方法可以獲取json物件中的資料,也可利用諸如size(),isEmpty()等方法獲取"鍵:值"對的個數和判斷是否為空,其本質是通過實作Map介面并呼叫介面中的方法完成的,
- JSONArray 代表 json 物件陣列
- 內部是有List介面中的方法來完成操作的,
- JSON代表 JSONObject和JSONArray的轉化
- JSON類原始碼分析與使用
- 仔細觀察這些方法,主要是實作json物件,json物件陣列,javabean物件,json字串之間的相互轉化,
代碼測驗,我們新建一個FastJsonDemo 類
@RequestMapping("/j4")
//@ResponseBody//他就不會走視圖決議器,會直接回傳一個 字串
public String json4(){
User user1 = new User(1, "秦疆1號", 12);
User user2 = new User(2, "秦疆2號", 12);
User user3 = new User(3, "秦疆3號", 12);
User user4 = new User(4, "秦疆4號", 12);
User user5 = new User(5, "秦疆5號", 12);
List<User> list = new ArrayList<User>();
list.add(user1);
list.add(user2);
list.add(user3);
list.add(user4);
list.add(user5);
System.out.println("*******Java物件 轉 JSON字串*******");
String str1 = JSON.toJSONString(list);
System.out.println("JSON.toJSONString(list)==>"+str1);
String str2 = JSON.toJSONString(user1);
System.out.println("JSON.toJSONString(user1)==>"+str2);
System.out.println("\n****** JSON字串 轉 Java物件*******");
User jp_user1=JSON.parseObject(str2,User.class);
System.out.println("JSON.parseObject(str2,User.class)==>"+jp_user1);
System.out.println("\n****** Java物件 轉 JSON物件 ******");
JSONObject jsonObject1 = (JSONObject) JSON.toJSON(user2);
System.out.println("(JSONObject) JSON.toJSON(user2)==>"+jsonObject1.getString("name"));
System.out.println("\n****** JSON物件 轉 Java物件 ******");
User to_java_user = JSON.toJavaObject(jsonObject1, User.class);
System.out.println("JSON.toJavaObject(jsonObject1, User.class)==>"+to_java_user);
return JSON.toJSONString(list);
}
這種工具類,我們只需要掌握使用就好了,在使用的時候在根據具體的業務去找對應的實作,和以前的commons-io那種工具包一樣,拿來用就好了!
9、Ajax研究
9.1、簡介
-
AJAX = Asynchronous JavaScript and XML(異步的 JavaScript 和 XML),
-
AJAX 是一種在無需重新加載整個網頁的情況下,能夠更新部分網頁的技術,
-
Ajax 不是一種新的編程語言,而是一種用于創建更好更快以及互動性更強的Web應用程式的技術,
-
在 2005 年,Google 通過其 Google Suggest 使 AJAX 變得流行起來,Google Suggest能夠自動幫你完成搜索單詞,
-
Google Suggest 使用 AJAX 創造出動態性極強的 web 界面:當您在谷歌的搜索框輸入關鍵字時,JavaScript 會把這些字符發送到服務器,然后服務器會回傳一個搜索建議的串列,
-
就和國內百度的搜索框一樣!
-
傳統的網頁(即不用ajax技術的網頁),想要更新內容或者提交一個表單,都需要重新加載整個網頁,
-
使用ajax技術的網頁,通過在后臺服務器進行少量的資料交換,就可以實作異步區域更新,
-
使用Ajax,用戶可以創建接近本地桌面應用的直接、高可用、更豐富、更動態的Web用戶界面,
9.2、偽造Ajax
我們可以使用前端的一個標簽來偽造一個ajax的樣子,iframe標簽
-
新建一個module :sspringmvc-06-ajax , 匯入web支持!
-
撰寫一個 ajax-frame.html 使用 iframe 測驗,感受下效果
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title>kuangshen</title> </head> <body> <script type="text/javascript"> window.onload = function(){ var myDate = new Date(); document.getElementById('currentTime').innerText = myDate.getTime(); }; function LoadPage(){ var targetUrl = document.getElementById('url').value; console.log(targetUrl); document.getElementById("iframePosition").src = targetUrl; } </script> <div> <p>請輸入要加載的地址:<span id="currentTime"></span></p> <p> <input id="url" type="text" value="https://www.baidu.com/"/> <input type="button" value="提交" onclick="LoadPage()"> </p> </div> <div> <h3>加載頁面位置:</h3> <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe> </div> </body> </html> -
使用IDEA開瀏覽器測驗一下!
利用AJAX可以做:
- 注冊時,輸入用戶名自動檢測用戶是否已經存在,
- 登陸時,提示用戶名密碼錯誤
- 洗掉資料行時,將行ID發送到后臺,后臺在資料庫中洗掉,資料庫洗掉成功后,在頁面DOM中將資料行也洗掉,
- …等等
9.3、jQuery.ajax
-
純JS原生實作Ajax我們不去講解這里,直接使用jquery提供的,方便學習和使用,避免重復造輪子,有興趣的同學可以去了解下JS原生XMLHttpRequest !
-
Ajax的核心是XMLHttpRequest物件(XHR),XHR為向服務器發送請求和決議服務器回應提供了介面,能夠以異步方式從服務器獲取新資料,
-
jQuery 提供多個與 AJAX 有關的方法,
-
通過 jQuery AJAX 方法,您能夠使用 HTTP Get 和 HTTP Post 從遠程服務器上請求文本、HTML、XML 或 JSON – 同時您能夠把這些外部資料直接載入網頁的被選元素中,
-
jQuery 不是生產者,而是大自然搬運工,
-
jQuery Ajax本質就是 XMLHttpRequest,對他進行了封裝,方便呼叫!
jQuery.ajax(...)
部分引數:
url:請求地址
type:請求方式,GET、POST(1.9.0之后用method)
headers:請求頭
data:要發送的資料
contentType:即將發送資訊至服務器的內容編碼型別(默認: "application/x-www-form-urlencoded; charset=UTF-8")
async:是否異步
timeout:設定請求超時時間(毫秒)
beforeSend:發送請求前執行的函式(全域)
complete:完成之后執行的回呼函式(全域)
success:成功之后執行的回呼函式(全域)
error:失敗之后執行的回呼函式(全域)
accepts:通過請求頭發送給服務器,告訴服務器當前客戶端可接受的資料型別
dataType:將服務器端回傳的資料轉換成指定型別
"xml": 將服務器端回傳的內容轉換成xml格式
"text": 將服務器端回傳的內容轉換成普通文本格式
"html": 將服務器端回傳的內容轉換成普通文本格式,在插入DOM中時,如果包含JavaScript標簽,則會嘗試去執行,
"script": 嘗試將回傳值當作JavaScript去執行,然后再將服務器端回傳的內容轉換成普通文本格式
"json": 將服務器端回傳的內容轉換成相應的JavaScript物件
"jsonp": JSONP 格式使用 JSONP 形式呼叫函式時,如 "myurl?callback=?" jQuery 將自動替換 ? 為正確的函式名,以執行回呼函式
我們來個簡單的測驗,使用最原始的HttpServletResponse處理 , .最簡單 , 最通用
-
配置web.xml 和 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:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd"> <!-- 自動掃描指定的包,下面所有注解類交給IOC容器管理 --> <context:component-scan base-package="com.kuang.controller"/> <!--靜態資源過濾--> <mvc:default-servlet-handler /> <!--注解驅動配--> <mvc:annotation-driven /> <!-- 視圖決議器 --> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" id="internalResourceViewResolver"> <!-- 前綴 --> <property name="prefix" value="/WEB-INF/jsp/" /> <!-- 后綴 --> <property name="suffix" value=".jsp" /> </bean> </beans> -
撰寫一個AjaxController
@Controller public class AjaxController { @RequestMapping("/a1") public void ajax1(String name , HttpServletResponse response) throws IOException { if ("admin".equals(name)){ response.getWriter().print("true"); }else{ response.getWriter().print("false"); } } } -
匯入jquery , 可以使用在線的CDN , 也可以下載匯入
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script> -
撰寫index.jsp測驗
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> <%--<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>--%> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script> <script> function a1(){ $.post({ url:"${pageContext.request.contextPath}/a1", data:{'name':$("#txtName").val()}, success:function (data,status) { alert(data); alert(status); } }); } </script> </head> <body> <%--onblur:失去焦點觸發事件--%> 用戶名:<input type="text" id="txtName" οnblur="a1()"/> </body> </html> -
啟動tomcat測驗!打開瀏覽器的控制臺,當我們滑鼠離開輸入框的時候,可以看到發出了一個ajax的請求!是后臺回傳給我們的結果!測驗成功!
9.4、Springmvc實作
-
物體類user(使用了lombok插件,可以自己寫實作類方法)
@Data @AllArgsConstructor @NoArgsConstructor public class User { private String name; private int age; private String sex; } -
我們來獲取一個集合物件,展示到前端頁面
@RequestMapping("/a2") public List<User> ajax2(){ List<User> list = new ArrayList<User>(); list.add(new User("秦疆1號",3,"男")); list.add(new User("秦疆2號",3,"男")); list.add(new User("秦疆3號",3,"男")); return list; //由于@RestController注解,將list轉成json格式回傳 } -
前端頁面
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> <script src="${pageContext.request.contextPath}/static/js/jquery-3.4.1.js"></script> <script> $(function () { $("#btn").click(function () { // console.log('點擊事件成功') // $.post(url,param,[可以省略],success) $.post("${pageContext.request.contextPath}/a2",function (data) { console.log(data[0].name); let html = ""; for (let i = 0; i < data.length; i++) { html += `<tr> <td>${"${data[i].name}"}</td> <td>${"${data[i].age}"}</td> <td>${"${data[i].sex}"}</td> </tr>` } $("#content").html(html) console.log(html) }) }) }) </script> </head> <body> <input type="button" value="加載資料" id="btn"> <table> <thead> <tr> <td>姓名</td> <td>年齡</td> <td>性別</td> </tr> </thead> <tbody id="content"> <%--資料:后臺--%> </tbody> </table> </body> </html>
成功實作了資料回顯!可以體會一下Ajax的好處!
9.5、注冊提示效果
-
我們寫一個Controller
@RequestMapping("/a3") public String ajax3(String name,String pwd){ String msg = ""; //模擬資料庫中存在資料 if (name!=null){ if ("admin".equals(name)){ msg = "OK"; }else { msg = "用戶名輸入錯誤"; } } if (pwd!=null){ if ("123456".equals(pwd)){ msg = "OK"; }else { msg = "密碼輸入有誤"; } } return msg; //由于@RestController注解,將msg轉成json格式回傳 } -
前端頁面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>ajax</title> <script src="${pageContext.request.contextPath}/statics/js/jquery-3.1.1.min.js"></script> <script> function a1(){ $.post({ url:"${pageContext.request.contextPath}/a3", data:{'name':$("#name").val()}, success:function (data) { if (data.toString()=='OK'){ $("#userInfo").css("color","green"); }else { $("#userInfo").css("color","red"); } $("#userInfo").html(data); } }); } function a2(){ $.post({ url:"${pageContext.request.contextPath}/a3", data:{'pwd':$("#pwd").val()}, success:function (data) { if (data.toString()=='OK'){ $("#pwdInfo").css("color","green"); }else { $("#pwdInfo").css("color","red"); } $("#pwdInfo").html(data); } }); } </script> </head> <body> <p> 用戶名:<input type="text" id="name" οnblur="a1()"/> <span id="userInfo"></span> </p> <p> 密碼:<input type="text" id="pwd" οnblur="a2()"/> <span id="pwdInfo"></span> </p> </body> </html> -
記得處理json亂碼問題
<!--JSON亂碼問題配置--> <mvc:annotation-driven> <mvc:message-converters register-defaults="true"> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"> <property name="objectMapper"> <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"> <property name="failOnEmptyBeans" value="false"/> </bean> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> -
測驗一下效果,動態請求回應,區域重繪,就是如此!
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-y0pMKeXD-1613122851068)(SpringMVC課堂筆記.assets/1595137816208.png)]

9.6、獲取baidu介面Demo
-
JSONP.html
<!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>JSONP百度搜索</title> <style> #q{ width: 500px; height: 30px; border:1px solid #ddd; line-height: 30px; display: block; margin: 0 auto; padding: 0 10px; font-size: 14px; } #ul{ width: 520px; list-style: none; margin: 0 auto; padding: 0; border:1px solid #ddd; margin-top: -1px; display: none; } #ul li{ line-height: 30px; padding: 0 10px; } #ul li:hover{ background-color: #f60; color: #fff; } </style> <script> // 2.步驟二 // 定義demo函式 (分析介面、資料) function demo(data){ var Ul = document.getElementById('ul'); var html = ''; // 如果搜索資料存在 把內容添加進去 if (data.s.length) { // 隱藏掉的ul顯示出來 Ul.style.display = 'block'; // 搜索到的資料回圈追加到li里 for(var i = 0;i<data.s.length;i++){ html += '<li>'+data.s[i]+'</li>'; } // 回圈的li寫入ul Ul.innerHTML = html; } } // 1.步驟一 window.onload = function(){ // 獲取輸入框和ul var Q = document.getElementById('q'); var Ul = document.getElementById('ul'); // 事件滑鼠抬起時候 Q.onkeyup = function(){ // 如果輸入框不等于空 if (this.value != '') { // ☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆JSONPz重點☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆☆ // 創建標簽 var script = document.createElement('script'); //給定要跨域的地址 賦值給src //這里是要請求的跨域的地址 我寫的是百度搜索的跨域地址 script.src = 'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd='+this.value+'&cb=demo'; // 將組合好的帶src的script標簽追加到body里 document.body.appendChild(script); } } } </script> </head> <body> <input type="text" id="q" /> <ul id="ul"> </ul> </body> </html> -
測驗
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MrxGsetk-1613122851070)(SpringMVC課堂筆記.assets/1595138107341.png)]

10、攔截器
10.1、概述
- SpringMVC的處理器攔截器類似于Servlet開發中的過濾器Filter,用于對處理器進行預處理和后處理,
- 開發者可以自己定義一些攔截器來實作特定的功能,
**過濾器與攔截器的區別:**攔截器是AOP思想的具體應用,
過濾器
- servlet規范中的一部分,任何javaweb工程都可以使用
- 在url-pattern中配置了/*之后,可以對所有要訪問的資源進行攔截
攔截器
- 攔截器是SpringMVC框架自己的,只有使用了SpringMVC框架的工程才能使用
- 攔截器只會攔截訪問的控制器方法, 如果訪問的是jsp/html/css/image/js是不會進行攔截的
10.2、自定義攔截器
-
新建一個Moudule , springmvc-Interceptor , 添加web支持
-
配置web.xml 和 springmvc-servlet.xml 檔案
-
撰寫一個攔截器(必須實作 HandlerInterceptor 介面)
package nuc.ss.config; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class MyInterceptor implements HandlerInterceptor { //return true; 執行下一個攔截器,放行 //return false; 不執行下一個攔截器,攔截 public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("===========處理前==========="); return true; } //日志 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("===========處理后==========="); } //日志 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("===========清理==========="); } } -
在springmvc的組態檔中配置攔截器
<!--攔截器配置--> <mvc:interceptors> <mvc:interceptor> <!--包括這個請求下面的所有請求--> <mvc:mapping path="/**"/> <bean class="nuc.ss.config.MyInterceptor"/> </mvc:interceptor> </mvc:interceptors> -
撰寫一個Controller,接收請求
package nuc.ss.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class TestController { @GetMapping("/t1") public String test() { System.out.println("TestController.test"); return "ok"; } } -
啟動tomcat 測驗一下!(http://localhost:8888/t1)
10.3、驗證用戶是否登錄 (認證用戶)
實作思路
-
有一個登陸頁面,需要寫一個controller訪問頁面,
-
登陸頁面有一提交表單的動作,需要在controller中處理,判斷用戶名密碼是否正確,如果正確,向session中寫入用戶資訊,回傳登陸成功,
-
攔截用戶請求,判斷用戶是否登陸,如果用戶已經登陸,放行, 如果用戶未登陸,跳轉到登陸頁面
測驗:
-
撰寫一個登陸頁面 login.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>登錄</title> </head> <body> <%--在web-inf下面的所有頁面或者資源,只能通過controller或者Servlet進行訪問--%> <h1>登錄頁面</h1> <form action="${pageContext.request.contextPath}/user/login" method="post"> 用戶名:<input type="text" name="username"> 密碼:<input type="text" name="password"> <input type="submit" value="提交"> </form> </body> </html> -
撰寫一個Controller處理請求
@Controller @RequestMapping("/user") public class LoginController { @RequestMapping("/main") public String main() { return "main"; } @RequestMapping("/goLogin") public String login() { return "login"; } @RequestMapping("/login") public String login(HttpSession session, String username, String password, Model model) { //把用戶的資訊存在session中 session.setAttribute("userLoginInfo",username); model.addAttribute("password",password); model.addAttribute("username",username); return "main"; } @RequestMapping("/goOut") public String goOut(HttpSession sessionl) { sessionl.removeAttribute("userLoginInfo"); return "login"; } } -
撰寫一個登陸成功的頁面 main.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>首頁</title> </head> <body> <h1>首頁</h1> <span>${password}</span> <span>${username}</span> <p> <a href="${pageContext.request.contextPath}/user/goOut">注銷</a> </p> </body> </html> -
在 index 頁面上測驗跳轉!啟動Tomcat 測驗,未登錄也可以進入主頁!
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>index</title> </head> <body> <h1><a href="${pageContext.request.contextPath}/user/goLogin">登錄頁面</a></h1> <h1><a href="${pageContext.request.contextPath}/user/main">首頁</a></h1> </body> </html> -
撰寫用戶登錄攔截器
package nuc.ss.config; import org.springframework.web.servlet.HandlerInterceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; public class LoginInterceptor implements HandlerInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { HttpSession session = request.getSession(); //放行:判斷什么情況下登錄 //登錄頁面也會放行 if (request.getRequestURI().contains("goLogin")) { return true; } if (request.getRequestURI().contains("login")) { return true; } if (session.getAttribute("userLoginInfo") != null) { return true; } //判斷什么情況下沒有登錄 request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request,response); return false; } } -
在Springmvc的組態檔中注冊攔截器
<!--關于攔截器的配置--> <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**"/> <bean id="loginInterceptor" class="com.kuang.interceptor.LoginInterceptor"/> </mvc:interceptor> </mvc:interceptors> -
再次重啟Tomcat測驗!
OK,測驗登錄攔截功能無誤.
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-sEIVidON-1613122851070)(SpringMVC課堂筆記.assets/1595139309383.png)]

11、檔案上傳和下載
11.1、準備作業
- 檔案上傳是專案開發中最常見的功能之一 ,springMVC 可以很好的支持檔案上傳,
- SpringMVC背景關系中默認沒有裝配MultipartResolver,因此默認情況下其不能處理檔案上傳作業,如果想使用Spring的檔案上傳功能,則需要在背景關系中配置MultipartResolver,
- 前端表單要求:為了能上傳檔案,必須將表單的method設定為POST,并將enctype設定為multipart/form-data,只有在這樣的情況下,瀏覽器才會把用戶選擇的檔案以二進制資料發送給服務器;
對表單中的 enctype 屬性做個詳細的說明:
- application/x-www=form-urlencoded:默認方式,只處理表單域中的 value 屬性值,采用這種編碼方式的表單會將表單域中的值處理成 URL 編碼方式,
- multipart/form-data:這種編碼方式會以二進制流的方式來處理表單資料,這種編碼方式會把檔案域指定檔案的內容也封裝到請求引數中,不會對字符編碼,
- text/plain:除了把空格轉換為 “+” 號外,其他字符都不做編碼處理,這種方式適用直接通過表單發送郵件,
<form action="" enctype="multipart/form-data" method="post">
<input type="file" name="file"/>
<input type="submit">
</form>
一旦設定了enctype為multipart/form-data,瀏覽器即會采用二進制流的方式來處理表單資料,而對于檔案上傳的處理則涉及在服務器端決議原始的HTTP回應,在2003年,Apache Software Foundation發布了開源的Commons FileUpload組件,其很快成為Servlet/JSP程式員上傳檔案的最佳選擇,
- Servlet3.0規范已經提供方法來處理檔案上傳,但這種上傳需要在Servlet中完成,
- 而Spring MVC則提供了更簡單的封裝,
- Spring MVC為檔案上傳提供了直接的支持,這種支持是用即插即用的MultipartResolver實作的,
- Spring MVC使用Apache Commons FileUpload技術實作了一個MultipartResolver實作類:
- CommonsMultipartResolver,因此,SpringMVC的檔案上傳還需要依賴Apache Commons FileUpload的組件,
11.2、檔案上傳
-
匯入檔案上傳的jar包,commons-fileupload , Maven會自動幫我們匯入他的依賴包 commons-io包;
<!--檔案上傳--> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.3</version> </dependency> <!--servlet-api匯入高版本的--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency> -
配置bean:multipartResolver
【注意!!!這個bena的id必須為:multipartResolver , 否則上傳檔案會報400的錯誤!在這里栽過坑,教訓!】
<!--檔案上傳配置--> <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- 請求的編碼格式,必須和jSP的pageEncoding屬性一致,以便正確讀取表單的內容,默認為ISO-8859-1 --> <property name="defaultEncoding" value="utf-8"/> <!-- 上傳檔案大小上限,單位為位元組(10485760=10M) --> <property name="maxUploadSize" value="10485760"/> <property name="maxInMemorySize" value="40960"/> </bean>CommonsMultipartFile 的 常用方法:
- String getOriginalFilename():獲取上傳檔案的原名
- InputStream getInputStream():獲取檔案流
- void transferTo(File dest):將上傳檔案保存到一個目錄檔案中
我們去實際測驗一下
-
撰寫前端頁面
<form action="/upload" enctype="multipart/form-data" method="post"> <input type="file" name="file"/> <input type="submit" value="upload"> </form> -
Controller
package nuc.ss.controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.commons.CommonsMultipartFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.net.URLEncoder; @RestController public class FileController { //@RequestParam("file") 將name=file控制元件得到的檔案封裝成CommonsMultipartFile 物件 //批量上傳CommonsMultipartFile則為陣列即可 @RequestMapping("/upload") public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request) throws IOException { //獲取檔案名 : file.getOriginalFilename(); String uploadFileName = file.getOriginalFilename(); //如果檔案名為空,直接回到首頁! if ("".equals(uploadFileName)){ return "redirect:/index.jsp"; } System.out.println("上傳檔案名 : "+uploadFileName); //上傳路徑保存設定 String path = request.getServletContext().getRealPath("/upload"); //如果路徑不存在,創建一個 File realPath = new File(path); if (!realPath.exists()){ realPath.mkdir(); } System.out.println("上傳檔案保存地址:"+realPath); InputStream is = file.getInputStream(); //檔案輸入流 OutputStream os = new FileOutputStream(new File(realPath,uploadFileName)); //檔案輸出流 //讀取寫出 int len=0; byte[] buffer = new byte[1024]; while ((len=is.read(buffer))!=-1){ os.write(buffer,0,len); os.flush(); } os.close(); is.close(); return "redirect:/index.jsp"; } /* * 采用file.Transto 來保存上傳的檔案 */ @RequestMapping("/upload2") public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException { //上傳路徑保存設定 String path = request.getServletContext().getRealPath("/upload"); File realPath = new File(path); if (!realPath.exists()){ realPath.mkdir(); } //上傳檔案地址 System.out.println("上傳檔案保存地址:"+realPath); //通過CommonsMultipartFile的方法直接寫檔案(注意這個時候) file.transferTo(new File(realPath +"/"+ file.getOriginalFilename())); return "redirect:/index.jsp"; } @RequestMapping(value="/download") public String downloads(HttpServletResponse response , HttpServletRequest request) throws Exception{ //要下載的圖片地址 String path = request.getServletContext().getRealPath("/upload"); String fileName = "bg1.jpg"; //1、設定response 回應頭 response.reset(); //設定頁面不快取,清空buffer response.setCharacterEncoding("UTF-8"); //字符編碼 response.setContentType("multipart/form-data"); //二進制傳輸資料 //設定回應頭 response.setHeader("Content-Disposition", "attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8")); File file = new File(path,fileName); //2、 讀取檔案--輸入流 InputStream input=new FileInputStream(file); //3、 寫出檔案--輸出流 OutputStream out = response.getOutputStream(); byte[] buff =new byte[1024]; int index=0; //4、執行 寫出操作 while((index= input.read(buff))!= -1){ out.write(buff, 0, index); out.flush(); } out.close(); input.close(); return null; } } -
測驗上傳檔案,OK!
采用file.Transto 來保存上傳的檔案
-
撰寫Controller
/* * 采用file.Transto 來保存上傳的檔案 */ @RequestMapping("/upload2") public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException { //上傳路徑保存設定 String path = request.getServletContext().getRealPath("/upload"); File realPath = new File(path); if (!realPath.exists()){ realPath.mkdir(); } //上傳檔案地址 System.out.println("上傳檔案保存地址:"+realPath); //通過CommonsMultipartFile的方法直接寫檔案(注意這個時候) file.transferTo(new File(realPath +"/"+ file.getOriginalFilename())); return "redirect:/index.jsp"; } -
前端表單提交地址修改
-
訪問提交測驗,OK!
11.3、檔案下載
檔案下載步驟:
-
設定 response 回應頭
-
讀取檔案 – InputStream
-
寫出檔案 – OutputStream
-
執行操作
-
關閉流 (先開后關)
代碼實作:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下載的圖片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "基礎語法.jpg";
//1、設定response 回應頭
response.reset(); //設定頁面不快取,清空buffer
response.setCharacterEncoding("UTF-8"); //字符編碼
response.setContentType("multipart/form-data"); //二進制傳輸資料
//設定回應頭
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 讀取檔案--輸入流
InputStream input=new FileInputStream(file);
//3、 寫出檔案--輸出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、執行 寫出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
前端
<a href="/download">點擊下載</a>
測驗,檔案下載OK
ring fileName = “bg1.jpg”;
//1、設定response 回應頭
response.reset(); //設定頁面不快取,清空buffer
response.setCharacterEncoding("UTF-8"); //字符編碼
response.setContentType("multipart/form-data"); //二進制傳輸資料
//設定回應頭
response.setHeader("Content-Disposition",
"attachment;fileName="+ URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 讀取檔案--輸入流
InputStream input=new FileInputStream(file);
//3、 寫出檔案--輸出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、執行 寫出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
}
5. 測驗上傳檔案,OK!
**采用file.Transto 來保存上傳的檔案**
1. 撰寫Controller
```java
/*
* 采用file.Transto 來保存上傳的檔案
*/
@RequestMapping("/upload2")
public String fileUpload2(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
//上傳路徑保存設定
String path = request.getServletContext().getRealPath("/upload");
File realPath = new File(path);
if (!realPath.exists()){
realPath.mkdir();
}
//上傳檔案地址
System.out.println("上傳檔案保存地址:"+realPath);
//通過CommonsMultipartFile的方法直接寫檔案(注意這個時候)
file.transferTo(new File(realPath +"/"+ file.getOriginalFilename()));
return "redirect:/index.jsp";
}
-
前端表單提交地址修改
-
訪問提交測驗,OK!
11.3、檔案下載
檔案下載步驟:
-
設定 response 回應頭
-
讀取檔案 – InputStream
-
寫出檔案 – OutputStream
-
執行操作
-
關閉流 (先開后關)
代碼實作:
@RequestMapping(value="/download")
public String downloads(HttpServletResponse response ,HttpServletRequest request) throws Exception{
//要下載的圖片地址
String path = request.getServletContext().getRealPath("/upload");
String fileName = "基礎語法.jpg";
//1、設定response 回應頭
response.reset(); //設定頁面不快取,清空buffer
response.setCharacterEncoding("UTF-8"); //字符編碼
response.setContentType("multipart/form-data"); //二進制傳輸資料
//設定回應頭
response.setHeader("Content-Disposition",
"attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));
File file = new File(path,fileName);
//2、 讀取檔案--輸入流
InputStream input=new FileInputStream(file);
//3、 寫出檔案--輸出流
OutputStream out = response.getOutputStream();
byte[] buff =new byte[1024];
int index=0;
//4、執行 寫出操作
while((index= input.read(buff))!= -1){
out.write(buff, 0, index);
out.flush();
}
out.close();
input.close();
return null;
}
前端
<a href="/download">點擊下載</a>
測驗,檔案下載OK
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/259211.html
標籤:其他
上一篇:JAVA的三大框架之Spring復習,理解Spring原理,Spring實踐案例
下一篇:HTTP
