文章目錄
Spring MVC引言
面試官:簡單談談什麼是Spring MVC?
Spring MVC是java開源框架Spring Framework的一個獨立的模塊
MVC框架,在項目中開闢MVC層次架構
對控制器中的功能 包裝 簡化 擴展踐行工廠模式
- Spring MVC框架主要是操作MVC層面中的C,也就是控制器
MVC架構
MVC: Model View Controller
模型 視圖 控制器
模型:即業務模型,負責完成業務中的數據通信處理,對應項目中的service和dao
視圖:渲染數據,生成頁面.對應項目中的JSP
控制器:直接對接請求,控制MVC流程,調度模型,選擇視圖.對應項目中的servlet
MVC是線下軟件開發中最流行的代碼結構形態
人們根據負責的不同邏輯,將項目中的代碼分成M V C3個層次
層次內部職責單一,層次之間耦合度低
符合低耦合 高內聚的設計理念.也實際有利於項目的長期維護
開發流程
導入依賴
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.1.3.RELEASE</version>
</dependency>
配置核心(前端)控制器
作爲一個MVC框架,首先要解決的是:如何能夠收到請求!
所以MVC框架大都會設計一款前端控制器,選型在Servlet或Filter兩者之一,在框架最前沿率先工作,接收所以請求
此控制器在接收到請求後,還會負責SpringMVC的核心調度管理,所以既是前端又是核心.
在web.xml中配置前端控制器
<servlet>
<servlet-name>mvc_leiyu</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!-- 可選配置 懶漢式加載 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc_leiyu</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
後端控制器
等價於之前定義的servlet
package per.leiyu.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author 雷雨
* @date 2020/6/24 8:50
*/
@Controller //聲明這個類是一個後端控制器
@RequestMapping("/hello") //這個類的訪問路徑是一個 /hello
public class HelloController {
@RequestMapping("/hello1")
public String hello1(){ //相當於之前的doget 和dopost方法
System.out.println("hello1");
return null;
}
//之前我們的servlet中只能定義一個方法,也就是訪問了servlet的路徑就是訪問那唯一的方法
//但是在我們的後端控制器中,一個servlet中可以定義多個方法,每個訪問有自己單獨的訪問路徑,這樣servlet就不會造成浪費
}
- 之前我們的servlet中只能定義一個方法,也就是訪問了servlet的路徑就是訪問那唯一的方法
- 但是在我們的後端控制器中,一個servlet中可以定義多個方法,每個訪問有自己單獨的訪問路徑,這樣servlet就不會造成浪費
配置文件
爲MVC的成功成功運行配置文件
在資源文件中創建mvc.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-3.0.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">
<!--註解掃描 -->
<context:component-scan base-package="per.leiyu.web"/>
<!--註解驅動
讓註解能正常的運行-->
<mvc:annotation-driven></mvc:annotation-driven>
</beans>
- 注意要在web.xml(前端控制器)中對剛纔的配置文件進行註冊
前端(核心)控制器:
- 前端,接收所以參數
- 啓動Spring MVC工廠時需要用到mvc,xml
- 負責SpringMVC 的流程調度
<servlet>
<servlet-name>mvc_leiyu</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:mvc.xml</param-value>
</init-param>
<!-- 可選配置 懶漢式加載 -->
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc_leiyu</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
- 這樣在創建Springmvc工廠時就會加載mvc.xml的配置,啓動註解驅動,掃描註解所在的包,
最終把後端控制器也創建出來
測試運行
配置Tomcat,並運行訪問我們的後端控制器方法
正常輸出 |
---|
但是我們的頁面卻是404 |
---|
這是爲什麼?
原因是我們沒有配置視圖解析器
視圖解析器作用:(對比下面的xml)
- 捕獲後端控制器的返回值=“index”
- 因此這時後端控制器的方法中不能返回null,而應該返回index
- 解析:在返回值的前後拼接 ==>"/index.jsp"
<!--mvc.xml -->
<!-- 配置視圖解析器
作用:
1.捕獲後端控制器的返回值="index"
2.解析:在返回值的前後拼接 ==>"/index.jsp"
-->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
總結一下
項目分爲創建工廠----和運行項目兩個階段
工廠的創建過程:
前端控制器啓動—>加載後端控制器---->後端控制器中的註解驅動和註解所在的包以及所對應的後端控制器的路徑和方法路徑都被前端控制器掃描到
運行項目:
當發送一個請求時-----先被前端控制器接收處理---->處理到一定程度會交給後端控制器(通過路徑匹配定義爲某一個方法),執行這個方法,這個方法的返回值---->返回值會被視圖解析器捕獲到(拼接前綴和後綴)----->跳轉到JSP----JSP把內容輸出給瀏覽器
接收請求參數
通過控制器中方法的形參 接收請求參數
基本類型參數
請求參數和方法形參 同名即可
Spring MVC默認可以識別的日期字符串格式爲:YYYY/MM/dd HH:mm:ss
通過@DataTimeFormat可以修改日誌格式
package per.leiyu.web;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Date;
/**
* @author 雷雨
* @date 2020/6/24 11:41
*/
@Controller
@RequestMapping("/param")
public class ParmController {
//Spring 中定義參數可以直接在參數列表中直接定義
//怎麼接受呢?
//只要請求參數名和方法的參數名同名,那麼就會用方法的參數名來接收請求的參數
//2020/12/12這種格式是Spring MVC能夠自動識別的日期類型的參數,在方法中可以直接定義Data的類型來接收
//http://xxxx/param/test1?id=1&name=leiyu&gendertrue&birthday=2020/12/12 12:13:20
@RequestMapping("/test1")
public String test1(Integer id, String name, Boolean gender, Date birthday){
System.out.println("test1");
//測試打印我們傳遞的請求參數
System.out.println("id="+id+"name="+name+"gender="+gender+"birthday="+birthday);
return "index";
}
}
- 不建議在方法的參數位置寫太多的參數,不利於管理
- 建議使用實體類來將參數包裝在傳遞
實體收參
在方法參數位置是一個
實體類的對象
那麼不像傳遞普通參數那樣:要求方法的參數和請求參數直接同名
而是要求:
請求參數和實體類的屬性同名
//將參數封裝爲實體類的對象
@RequestMapping("/test2")
public String test2(User user){
System.out.println(user);
return "index";
}
接收參數和實體類對象的對應關係 |
---|
數組收參
@RequestMapping("test3")
public String test3(String[] hobby){
System.out.println("test3");
for(String str: hobby){
System.out.println(str);
}
return "index";
}
集合收參
//UserList類中封裝了User的對象,但是提供了獲取對象的方法getUsers
@RequestMapping("test4")
public String test4(UserList userList){
System.out.println("test4");
for(User user: userList.getUsers()){
System.out.println(user);
}
return "index";
}
路徑收參
//將{name路徑匹配到的值賦值給username參數}
@RequestMapping("test4/{id}/{name}")
public String test4(@PathVariable Integer id,@PathVariable("name") String username){
System.out.println("id"+id);
System.out.println("username"+username);
return "index";
}
中文亂碼
首先頁面中字符集統一
JSP : <%@page pageEncoding="utf-8" %>
HTML: <meta charset="UTF-8">
其次,tomcat中字符集設置,對get請求中,中文參數亂碼問題有效
Tomcat配置: URIEncoding=utf-8
最後,設置filter,對post請求中,中文亂碼問題有效
沒用Spring MVC之前,我們在獲取頁面的內容時第一步就是設置字符集,但是在Spring MVC中我們沒有機會設置,因此使用過濾器來過濾所有的頁面,設置其字符集編碼格式爲utf-8
<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>
跳轉
跳轉關鍵字
forward:
redirect:
原理是在我們的視圖解析器中如果有關鍵
forward:
redirect:
就不會自動爲我們拼接,但是如果沒有就會爲我們自動拼接
轉發
請求轉發 關鍵字:
forward
@RequestMapping("test1")
public String test1(){
System.out.println("請求轉發的一種方式,return相當於forward:");
//return "index";
return "forward:/index.jsp";
}
@RequestMapping("test2")
public String test2(){
System.out.println("請求轉發路徑的寫法有兩種");
return "forward:test1";//相對路徑,轉發到了本類中的其他方法
//retuen "forward:jump/test1"; 和上面的作用是相同的
//需要注意的是如果是在不同的類的方法中進行轉發需要指定完整路徑(絕對路徑)
}
請求重定向
請求重定向 關鍵字:
redirect
@RequestMapping("test3")
public String test3(){
System.out.println("請求重定向到頁面");
return "redirect:index.jsp";
}
@RequestMapping("test4")
public String test4(){
System.out.println("請求重定向的路徑的兩種寫法:決定和相對路徑");
return "redirect:test1";
//return "redirect:/jump/test1";
}
跳轉細節
- 在增刪改之後,爲了防止請求的重複提交重定向跳轉(如果用戶點擊刷新,如果是轉發的話,那麼就又會執行一遍)
- 在查詢之後,可以做轉發跳轉(這裏做成轉發是因爲我們希望的是在用戶查詢之後,刷新頁面的話,會幫用戶再查詢一次)
傳值
C(控制器)得到數據後,跳轉到,並向V(視圖)傳遞數據.進而V(視圖)中可以渲染數據,讓用戶可以看到含有數據的頁面
轉發跳轉:Request作用域
重定向跳轉:Session作用域
request和session
需要導入相關的依賴
//使用原生的servlet的request和session來進行傳值
//要導入相關的依賴
//要存入的域的參數是可選的
//存入的方式setAttribute和原來的方式相同
@RequestMapping("test1")
public String test1(HttpServletRequest request, HttpSession session){
System.out.println("test1");
request.setAttribute("name","張三");
session.setAttribute("age",18);
return "index";
}
在JSP中取值
使用的是EL JSEL表達式
${requestScope.name}
${sessinScope.age}
Model(建議使用)
使用Model來存值
Model可以直接和request域對應
使用的是鍵值對的方式存值
//使用Model來存值
//Model可以直接和request域對應
//使用的是鍵值對的方式存值
@RequestMapping("test2")
public String test2(Model model){
model.addAttribute("name","李四");
model.addAttribute("age",17);
return "index";
}
ModelAndView
使用ModelAndView來存值
- 注意:存的值是在request域中
- 兩個重要的方法,一個決定視圖,一個決定數據
//使用MVC本土化的對象ModelAndView(用來做視圖整合的對象來傳值)
//它是將數據存入到request域中
@RequestMapping("test4")
public ModelAndView test4(){
//新建ModelAndView對象
ModelAndView modelAndView = new ModelAndView();
//設置視圖名,即如何轉跳
modelAndView.setViewName("forward:/index.jsp");
//添加數據
modelAndView.addObject("name","雷雨");
return modelAndView;
}
@SessionAttributes
在類上面定義這個註解,表示有這樣的Session域
- @SessionAttributes(value={“name”,“age”})
- @@SessionAttributes(names={“name”,“age”})
這兩個註解表示的意義是相同的
- 參數names和value都可以使用
- 如果有多個參數用大括號括起來
配合Model一起使用
- 如果沒有在類的上Ian定義對應的session域,那麼就當做request域來存值
- 如果有對應的session域那麼優先以session爲準
@Controller
@RequestMapping("data")
@SessionAttributes(value = {"age"})//model中的age會存入到session域中
public class DataConroller {
//使用Model來存值
//Model可以直接和request域對應
//使用的是鍵值對的方式存值
@RequestMapping("test2")
public String test2(Model model){
model.addAttribute("name","李四");
model.addAttribute("age",17);
return "index";
}
}
//
能夠通過
SessionStatus
移除session中的數據
//清除Session域中的所有數據
@RequestMapping("test3")
public String test3(SessionStatus status){
status.setComplete();
return "index";
}
我是雷雨,一個
普本科
的學生,主要專注於Java後端和大數據開發
如果這篇文章有幫助到你,希望你給我一個
大大的贊
如果有什麼問題,希望你能留言
和我一起研究
,學習靠自覺,分享靠自願