目錄
一、什么是Spring MVC
?二、Spring MVC項目的創建和使用
1、實現客戶端和服務器端之間的連接
1.1、RequsestMapping注解
1.2、@RequestMapper的簡單使用?
1.3、使用@GetMapping和@POSTMapping注解來實現HTTP連接
三、獲取參數
1、實現獲取單個參數
2、實現獲取對象
3、后端參數重命名(@RequestParam參數映射)
?4、@RequestParam參數必傳設置
?5、接收JSON對象(@RequestBody)
6、獲取URL中參數(@PathVariable)
?7、上傳文件(@RequestPart)
8、獲取Cookie/Session/header
四、返回數據
1、返回一個靜態頁面
?2、返回一個數據
?3、返回text/html
4、請求轉發和請求重定向
一、什么是Spring MVC
官方的描述為:Spring Web MVC是基于Servlet API的原始Web框架,從一開始就包含在Spring框架中。它的正式名稱“Spring Web MVC”來自它的源模塊(Spring -webmvc)的名稱,但它更常被稱為“Spring MVC”。
?理解Web框架
Web框架(Web framework)是用來進行Web應用開發的一個軟件架構。主要用于動態網絡開發,Web應用框架提供了一套開發和部署網站的方式。開發者基于框架實現自己的業務邏輯。使用Web框架很多的業務邏輯的功能不需要自己去完善,而是使用框架已有的功能就可以。
?什么是MVC?
MVC是Model View Controller的縮寫,它是軟件工程中的一種軟件件架構模式,他將一個項目分為三部分:View(試圖),Controller(控制器),Model(模型)。MVC是一種思想。
- Model(模型):項目中用于處理程序數據邏輯的部分,負責在數據庫中查找和存儲數據。
- View(試圖):是項目中將得到的數據進行處理之后,顯示給用戶一個界面的部分。
- Controller(控制器):是項目中處理用戶交互的部分,負責讀取用戶的請求,向模型提價請求,讀取模型的響應,將數據交給View部分。
?MVC和Spring MVC的關系
MVC是一種思想,Spring MVC是對MVC思想的具體實現。
Spring MVC是一個實現了MVC模式,并繼承了Servlwt API的Web框架。
?二、Spring MVC項目的創建和使用
Spring MVC項目的創建步驟和Spring Boot的創建步驟是相同的,我們之前創建的Spring Boot項目就相當于是一個Spring Web項目,我們在添加Spring Boot框架的時候,已經引入了Spring MVC。
下圖中spring-boot-starter-web表示的就是Spring MVC框架。
1、實現客戶端和服務器端之間的連接
1.1、RequsestMapping注解
@ResquestMapping是Spring Web應用程序中最常用到的注解之一,他是用來注冊接口的的路由映射的。
路由映射:所謂的路由隱射指的就是,當用戶訪問一個URL時,將用戶的請求對應到程序中某個類的某個方法的過程就叫做路由映射。
? @RequestMapping注解的參數
- value:指定請求的實際訪問地址,value屬性是@RequestMapping注解的默認屬性,如果只有唯一一個屬性,則可以省略value字段,如果參數中有多個屬性,則必須寫上value屬性名。
- path:與value同義,他們在源碼中相互引用,value和path都是用來作為映射使用的。
- method:用來指定請求的類型,當在一個方法的注解@RequestMapping的參數中寫道method = RequestMethod.GET表示這個方法只支持GET請求。
- params:該屬性指定,請求中必須包含params屬性指定的參數時,才能執行該請求。
- headers:該屬性指定,請求中必須包含某些指定的header值,才能夠讓該方法處理請求。
- consumes:指定處理請求的提交內容類型(Content-Type),才能讓該方法處理請求
- produces:指定返回的內容類型,返回的內容類型必須時request請求頭中所包含的類型。這個屬性還可以指定返回值的編碼。
1.2、@RequestMapper的簡單使用?
- @RequestMapping既可以修飾類,也可以修飾方法,當同時修飾類和方法時,類上的@ResquestMapping注解的參數value/path,表示的是URL中的一級路由,方法上的參數的value/path表示的是URL的二級路由。
- @RequestMapper注解默認情況下支持GET和POST請求。
🍂下面我們創建一個類,來實現客戶端和Spring程序的連接,使用postman模擬客戶端發送請求。驗證@RequsetMapper注解既可以修飾類也可以修飾方法和@RequestMapper注解默認支持GET和POST請求。
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class TestController {@RequestMapping("/sayHi")public String sayHi(){return "你好 Spring MVC";}
}
?我們使用URL為127.0.0.1:8080/test/sayHi
1??我們使用POST請求,可以收到響應。
?2??我們使用GET方法發送請求,也可以收到響應
?🍂當然我們可以設置@RequestMapping注解的Method屬性值為RequeatMethod.POST,表示這個方法只支持POST請求
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class TestController {//當這個注解中的參數有多個的時候,就需要添加屬性名稱@RequestMapping(value = "/sayHi",method = RequestMethod.POST)public String sayHi(){return "你好 Spring MVC";}
}
?
?🍂@RequestMapper支持設置多級目錄
@RequestMapping("/sayHi/mvc")
?
1.3、使用@GetMapping和@POSTMapping注解來實現HTTP連接
@GetMapping注解只能實現GET請求的連接,@POSTMapping注解只能實現POST請求的連接。
🍂@GetMapping注解
package com.example.demo.controller;import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class TestController {@GetMapping("sayhi2")public String sayHi2(){return "你好,世界";}
}
?
?🍂@PostMapping注解
package com.example.demo.controller;import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test")
public class TestController {@PostMapping("sayhello")public String sayHi2(){return "你好,世界";}
}
?
?
三、獲取參數
1、實現獲取單個參數
1??使用servlet的寫法(getParameter)來實現獲取單個參數
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;@RestController
@RequestMapping("/test2")
public class TestController2 {@RequestMapping("/getname")public String getName(HttpServletRequest request){return "Name:"+ request.getParameter("name");}
}
?2??使用更簡單的獲取單個參數的方法
package com.example.demo.controller;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/test2")
public class TestController2 {@RequestMapping("/getname2")public String getName2(String name){return "Name: "+name;}
}
?
2、實現獲取對象
上面獲取單個參數的方式,當參數個數固定的時候可以使用,但是如果參數個數不確定,隨時都需要添加參數的時候,我們這個時候可以使用獲取對象的方式獲取參數,前端沒有對象的概念,傳遞的都是對象的屬性,后端代碼中需要創建一個(用戶)類的對象,用來接收前端傳過來的屬性的值。
package com.example.demo.model;import lombok.Data;@Data
public class User {private int id;private String name;private String password;private int age;
}package com.example.demo.controller;import com.example.demo.model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/add")public User add(User user){return user;}
}
?當前端的屬性和后端中類的屬性對應不全的時候,如果后端沒有相應的屬性,那么前端的屬性賦值不到后端的代碼中,如果前端沒有相應的后端代碼中的屬性,那么后端中類的屬性的值就是默認值。
3、后端參數重命名(@RequestParam參數映射)
特殊情況下,前端傳遞的參數key和我們后端接收的key可以不一致,比如前端傳遞了一個n給后端,而后端使用的時name參數來接收的,這個時候就會出現參數接收不到的問題,我們可以使用@RequestParam注解來重命名前后端的參數。
import com.example.demo.model.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequestMapping("/user")
public class UserController {@RequestMapping("/name")public String name(@RequestParam ("n") String name){return name;}
}
?4、@RequestParam參數必傳設置
使用@RequestParam注解之后,那么這個屬性就變成了必傳的參數了,不傳這個參數就會報錯,原因是因為@RequestParam注解中有一個required屬性等于true,表示這個參數為必傳的,我們只需要設置這個屬性為false即可解決必傳的問題。
?
@RequestMapping("/name")public String name(@RequestParam (value="n",required = false) String name){return name;}
?5、接收JSON對象(@RequestBody)
這里只需要使用@RequestBody就可以拿到前端傳遞的JSON對象
@RequestMapping("/add_json")public User addByJson(@RequestBody User user){return user;}
?
6、獲取URL中參數(@PathVariable)
之前我們是通過URL中的查詢字符串的部分獲取的參數,也就是name="xxx"&id=123的部分。但是有點網站不是通過這樣的方式傳遞參數的,就像掘金一樣。訪問它的有些頁面時URL是這樣的https://juejin.cn/user/61228381386487。他沒有通過查詢字符串的方式傳遞。
1??從前端獲取一個參數
@RequestMapping("/detial/{id}")public Integer detail(@PathVariable("id") Integer id){return id;}
?這里表示前端要傳遞的參數為id,所以這里需要使用一個{}將這個參數括起來
2??表示從前端獲取多參數
@RequestMapping("/detial/{id}/{name}")public String detail(@PathVariable("id") Integer id,@PathVariable("name") String name){return "id: "+id+" "+"name: "+name;}
?7、上傳文件(@RequestPart)
@RequestPart用于將multiparty/form-data類型的數據映射到控制器處理方法的參數中。
@RequestMapping("/upload")public String upload(@RequestPart("myfile") MultipartFile file) throws IOException {String path = "D:/img.png";file.transferTo(new File(path));return path;}
}
這里@RequestPart("file")表示從請求中獲取名為"file"的文件,長傳的文件將被存儲在file對象中,我們可以是以哦那個file對象的方法類處理上傳的文件。
?在D盤中獲取到了這個圖片文件,并將圖片名字改為了img
但是這樣編寫的后端代碼存在問題,就是客戶端每次訪問服務器程序,服務器返回的圖片名字都是一樣的,那么在D盤中,后面獲取的圖片會將之前獲取的覆蓋掉,這是不完善的,如果在客戶端點擊上傳的圖片不同,最終服務器將不同的圖片名字改成一樣的,兩張不同的照片只能保存其中一個。
?下面我們來解決這個問題
這里將路徑中的文件名通過生成一個全球唯一id得到的,文件類型是截取原文件的。
@RequestMapping("/upload")public String upload(@RequestPart("myfile") MultipartFile file) throws IOException {//1、生成一個唯一的id(UUID就是全球唯一ID,他是由MAC地址+隨機數+加密算法組成的,保證生成的id是全球唯一ID)String name = UUID.randomUUID().toString().replace("-","");//2、得到源文件的后綴名name += file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));String path = "D:/"+name;//將文件保存在path路徑中file.transferTo(new File(path));return path;}
可以看見每次獲取的文件名稱都是不一樣的,也不會將之前獲取的文件覆蓋掉。
?
8、獲取Cookie/Session/header
?通過@CookieValue獲取Cookie
@RequestMapping("/getcookie")public String getCookie(@CookieValue("java")String ck){return ck;}
?通過@CookieValue注解類獲取Session
@RequestMapping("/getsess")//這里的value指的是session的名字public String getSess(@SessionAttribute(value="username",required = false) String username){return username;}
通過@RequestHeader獲取Header
// @RequestHeader 獲取 header
@RequestMapping("/header")
public String header(@RequestHeader("User-Agent") String userAgent) {return "User-Agent: " + userAgent;
}
四、返回數據
1、返回一個靜態頁面
在項目中創建一個靜態的html頁面。使用@Controller注解默認的是返回一個頁面。
package com.example.demo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;@Controller
public class TestController3 {@RequestMapping("/hello")public String index(){return "hello.html";}}
?
?2、返回一個數據
使用@ResponseBody和@Controller注解搭配使用,讓返回的值是一個數據,也可以使用組合注解@RestController注解
package com.example.demo.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
@ResponseBody
public class TestController3 {@RequestMapping("/hello")public String index(){return "hello.html";}
}
?3、返回text/html
可以使用組合注解@RestController也可以使用@Controller和@ResponseBody搭配使用
@RestController
public class TestController3 {@RequestMapping("method")public String method(){return "<h1>hello,world!</h1>";}
4、請求轉發和請求重定向
return不僅可以返回一個試圖,還可以實現跳轉,跳轉的方式有兩種:
- forward是請求轉發;
- redirect是請求重定向。
// 請求重定向
@RequestMapping("/index1")
public String index1() {return "redirect:/index.html";
}
// 請求轉發
@RequestMapping("/index2")
public String index2() {return "forward:/index.html";
}
?請求重定向和請求轉發的區別
- 請求轉發是一種服務器行為,客戶端只有一次請求,服務器接收到客戶端的請求之后,會先將請求轉發給目標地址,在將目標地址返回的結果轉發給客戶端。客戶端對這一切毫無感知。這就像A找B借錢,B沒有,B向C借到之后,將錢給了A,整個過程A就直借了一次錢。B向C借錢A不知道。
- 請求重定向是指服務器端接收到客戶端的請求之后,會給客戶端返回一個臨時相應頭,這個響應頭中記錄了,客戶端需要再次發送請求(重定向)的URL地址,客戶端收到地址之后,會將請求發送到新的地址上,這就是請求重定向。就像A找B借錢,B沒有,但是B知道C有,B對A說C有,讓A 去C哪里借,然后A去找C去借,這個過程就是請求重定向。