在之前的文章中我們已經學習了Spring的基本內容,SpringMVC隸屬於Spring的一部分內容
但由於SpringMVC完全針對於服務層使用,所以我們在介紹時常常把SpringMVC單獨當作一個大章節來學習
溫馨提醒:在學習SpringMVC前請確保已學習Spring內容
首先我們先來簡單瞭解一下SpringMVC:
在未學習SpringMVC之前,我們的伺服器端開發通常採用Servlet:
package com.itheima.web.servlet.old;
import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import com.itheima.service.impl.BrandServiceImpl;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.List;
//@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
private BrandService brandService = new BrandServiceImpl();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 接收品牌資料
BufferedReader br = request.getReader();
String params = br.readLine();//json字串
//轉為Brand物件
Brand brand = JSON.parseObject(params, Brand.class);
//2. 呼叫service新增
brandService.add(brand);
//3. 響應成功的標識
response.getWriter().write("success");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
我們可以注意到其過程非常繁瑣,因為我們需要獲取引數並進行型別轉換,包括新增至Service等過程
但是SpringMVC秉承著簡化程式碼的原則,將大部分內容轉化為Java程式碼進行封裝,大大減少了繁瑣的過程
接下來我們來介紹SpringMVC版:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>springmvc_01_quickstart</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<!-- servlet座標-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- SpringMVC座標-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<!--Tomcat設定-->
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
//定義表現層控制器bean
@Controller
public class UserController {
//設定對映路徑為/save,即外部存取路徑
@RequestMapping("/save")
//設定當前操作返回結果為指定json資料(本質上是一個字串資訊)
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
//設定對映路徑為/delete,即外部存取路徑
@RequestMapping("/delete")
@ResponseBody
public String delete(){
System.out.println("user save ...");
return "{'info':'springmvc'}";
}
}
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//springmvc設定類,本質上還是一個spring設定類
@Configuration
@ComponentScan("com.itheima.controller")
public class SpringMvcConfig {
}
/*
我們服務層的實際操作都是放置於Servlet容器中
我們設定的SpringMVC和Spring環境都是用於服務層,所以我們需要把相關Config載入僅Servlet容器中
*/
package com.itheima.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
// web容器設定類
// AbstractDispatcherServletInitializer是SpringMVC為我們設定好的類,繼承並實現相關方法即可
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//載入springmvc設定類,產生springmvc容器(本質還是spring容器)
protected WebApplicationContext createServletApplicationContext() {
//初始化WebApplicationContext物件
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
//載入指定設定類
ctx.register(SpringMvcConfig.class);
return ctx;
}
//設定由springmvc控制器處理的請求對映路徑
protected String[] getServletMappings() {
return new String[]{"/"};
}
//載入spring設定類
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
我們對上述新的內容進行解析:
@Controller
名稱:@Controller
型別:類註解
位置:SpringMVC控制類定義上方
作用:設定SpringMVC的核心控制器Bean
@RequestMapping
名稱:@RequestMapping
型別:方法註解
位置:SpringMVC控制器方法定義上方
作用:設定當前控制器方法請求存取路徑
相關屬性:value(請求存取路徑)
@ResponseBody
名稱:@ResponseBody
型別:方法註釋
位置:SpringMVC控制器方法定義上方
作用:設定當前控制器方法響應內容為當前返回值,無需解析
AbstractDispatcherServletInitializer類
最後我們總結一下上述操作的出現頻率:
在分析SpringMVC工作流程前,我們需要知道服務層是由下面的框架組成的:
啟動伺服器初始化過程:
單次請求過程:
在學習SpringMVC之後,我們的Bean的範圍逐漸變大:
但是我們在使用時,需要區分相關bean的匯入路徑:
因而我們給出兩種方法來解決Spring的掃描問題:
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
/*
@ComponentScan註解設定掃描範圍
@ComponentScan中包含有value,excludeFilters屬性
value:用於控制掃描範圍
excludeFilters:用於控制排除範圍,需要採用@ComponentScan.Filter過濾器
type:設定排除規則,當前使用按照bean定義時的註解型別進行排除
classes屬性:設定排除的具體註解類,當前設定排除@Controller定義的bean
*/
@ComponentScan(value="com.itheima",
excludeFilters = @ComponentScan.Filter(
type = FilterType.ANNOTATION,
classes = Controller.class
)
)
public class SpringConfig {
}
/*
這裡做一個小補充內容:
@ComponentScan中除了excludeFilters,還包括有includeFilters
includeFilters:載入指定的bean,需要指定型別(type)和具體項(classes)
*/
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
@Configuration
@ComponentScan({"com.itheima.service","com.itheima.dao"})
public class SpringConfig {
}
我們的Servlet容器中可以定義Spring和SpringMVC的組態檔
package com.itheima.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
// 設定SpringMVC組態檔
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
// 設定Spring組態檔
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
// 設定攔截路徑
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
我們可以注意到:
Spring和SpringMVC匯入方法中均採用AnnotationConfigWebApplicationContext來建立物件
兩者之間的區別僅僅是class包的不同
Spring給了我們一種新的繼承類用於簡化開發:
package com.itheima.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
//web設定類簡化開發,僅設定設定類類名即可
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
注意:
AbstractAnnotationConfigDispatcherServletInitializer是createServletApplicationContext的繼承類
我們同樣繼承它的三個方法,但這次我們只需要在裡面標明相關類和路徑即可
在我們的SpringMVC中岔開一個話題:
我們在一個網頁開發中,會不斷的偵錯網頁,通過各種路徑反覆查詢或者採用不同的存取方式(GET/POST)
如果我們採用正常的網頁進行測試,無疑會出現非常麻煩的步驟
所以我們推薦採用Postman軟體,下面我們將會簡單做一下介紹
首先為大家附上連結:
在瞭解操作前,我們需要明白Postman的作用:
關於安裝註冊的過程我們不再贅述
我們先來檢視Postman的主頁:
首先我們可以看到左上角的Workspaces,這個是最大的分類空間
我們可以看到左上角SpringMVC,這是我所建立的WorkSpaces,關於我在SpringMVC所做的網頁測試部分將都在這裡進行
除此之外,我們可以看到右側的DEMO1,以及內部的測試用例資料夾,以及專案save
以上就是我們的Postman的基本頁面
我們的Postman的具體使用流程如下:
到這裡,我們Postman的基本使用基本就結束了,到後面我們會對具體內容做具體補充~
SpringMVC和Servlet同屬於服務層的工具,那麼必不可少的就是請求與響應的反饋問題
接下來我們將一一介紹請求與響應的相關知識
首先我們先來想一想我們之前的路徑設定是否有那麼一點點缺陷?
// Book的服務層
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BookController {
//請求路徑對映
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("book save ...");
return "{'module':'book save'}";
}
}
// User的服務層
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UserController {
//請求路徑對映
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}
//請求路徑對映
@RequestMapping("/delete")
@ResponseBody
public String delete(){
System.out.println("user delete ...");
return "{'module':'user delete'}";
}
}
我們可以注意到我們的單個專案中不可能只包括有一個服務層
但我們的請求對映路徑卻只是簡單設計為相同的名稱,就會導致我們存取該頁面時,系統無法匹配
所以我們需要給他們採用不同的對映路徑,我們常有的操作是直接在前面加上一層該類的路徑名:
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class BookController {
//請求路徑對映
@RequestMapping("/book/save")
@ResponseBody
public String save(){
System.out.println("book save ...");
return "{'module':'book save'}";
}
}
但當專案逐漸增多,我們多次書寫路徑名就有可能導致錯誤,所以我們採用類註解@RequestMapping來解決:
package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
//類上方設定的請求對映與方法上面設定的請求對映連線在一起,形成完整的請求對映路徑
@RequestMapping("/user")
public class UserController {
//請求路徑對映
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save ...");
return "{'module':'user save'}";
}
//請求路徑對映
@RequestMapping("/delete")
@ResponseBody
public String delete(){
System.out.println("user delete ...");
return "{'module':'user delete'}";
}
}
注意:@RequestMapping不僅僅可以用於方法表示對映,也可以用於整個Bean類中表示對映字首
關於引數傳遞我們從三個方面來講解:
我們的傳遞方式通常採用GET或者POST方式
但在前面的學習中我們可以知道我們的傳遞方式是有不同的,我們在Postman的書寫形式也是不同的
例如我們先給出一個簡單的引數傳遞函數
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//普通引數:請求引數與形參名稱對應即可完成引數傳遞
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
System.out.println("普通引數傳遞 name ==> "+name);
System.out.println("普通引數傳遞 age ==> "+age);
return "{'module':'common param'}";
}
}
我們的GET方式直接在網頁後用?和&來書寫傳遞引數:
我們的POST方式只能在下方的body中書寫引數:
然後我們需要注意到的是這裡的中文同樣會出現亂碼行為
這次我們選擇在ServletContainersInitConfig中處理資料:
// 下述程式碼基本屬於我們建立專案的固定程式碼
package com.itheima.config;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import javax.servlet.Filter;
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[0]{SpringConfig.class};
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
//亂碼處理
@Override
protected Filter[] getServletFilters() {
// CharacterEncodingFilter 屬於處理中文編碼的過濾器,我們直接建立即可(一次性操作)
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
}
我們按引數來分類主要分為五種:
我們下面來一一介紹
普通引數:請求引數和形參變數名相同時,自動匹配
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//普通引數:請求引數與形參名稱對應即可完成引數傳遞
@RequestMapping("/commonParam")
@ResponseBody
public String commonParam(String name ,int age){
System.out.println("普通引數傳遞 name ==> "+name);
System.out.println("普通引數傳遞 age ==> "+age);
return "{'module':'common param'}";
}
}
Postman操作:
這裡需要注意:當請求引數名與形參名不同時,使用@RequestParam註解關聯請求引數名稱與形參名稱之間的關係
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//普通引數:請求引數名與形參名不同時,使用@RequestParam註解關聯請求引數名稱與形參名稱之間的關係
@RequestMapping("/commonParamDifferentName")
@ResponseBody
public String commonParamDifferentName(@RequestParam("name") String userName , int age){
System.out.println("普通引數傳遞 userName ==> "+userName);
System.out.println("普通引數傳遞 age ==> "+age);
return "{'module':'common param different name'}";
}
}
Postman操作:
@RequestParam:繫結請求引數與處理器方法形參間的關係
包含有兩個引數
required:是否為必傳引數
defaultValue:引數預設值
POJO引數:請求引數名與形參物件屬性名相同,定義POJO型別形參即可接收引數
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//POJO引數:請求引數與形參物件中的屬性對應即可完成引數傳遞
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("pojo引數傳遞 user ==> "+user);
return "{'module':'pojo param'}";
}
}
Postman操作:
巢狀POJO引數:請求引數名與形參物件屬性名相同,按照物件層次結構關係即可接收巢狀POJO屬性引數
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//巢狀POJO引數:巢狀屬性按照層次結構設定名稱即可完成引數傳遞
@RequestMapping("/pojoContainPojoParam")
@ResponseBody
public String pojoContainPojoParam(User user){
System.out.println("pojo巢狀pojo引數傳遞 user ==> "+user);
return "{'module':'pojo contain pojo param'}";
}
}
Postman操作:
陣列引數:請求引數名與形參物件屬性名相同且請求引數為多個,定義陣列型別形參即可接收引數
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//陣列引數:同名請求引數可以直接對映到對應名稱的形引陣列物件中
@RequestMapping("/arrayParam")
@ResponseBody
public String arrayParam(String[] likes){
System.out.println("陣列引數傳遞 likes ==> "+ Arrays.toString(likes));
return "{'module':'array param'}";
}
}
Postman操作:
集合儲存普通引數:請求引數與形參集合物件名相同且請求引數為多個,@RequestParam繫結引數關係
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//集合引數:同名請求引數可以使用@RequestParam註解對映到對應名稱的集合物件中作為資料
@RequestMapping("/listParam")
@ResponseBody
public String listParam(@RequestParam List<String> likes){
System.out.println("集合引數傳遞 likes ==> "+ likes);
return "{'module':'list param'}";
}
}
Postman引數:
我們的特殊引數主要介紹兩種:
我們下面一一介紹
JSON型別是我們Web開發中最常用的型別,所以這一部分算是一個小重點
我們將一一講解JSON型別傳遞的步驟:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.itheima</groupId>
<artifactId>springmvc_04_request_param</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
<!--JSON座標--->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.1</version>
<configuration>
<port>80</port>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import javax.servlet.Filter;
import javax.servlet.annotation.WebFilter;
@Configuration
@ComponentScan("com.itheima.controller")
//開啟json資料型別自動轉換
@EnableWebMvc
public class SpringMvcConfig {
}
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//集合引數:json格式
//1.開啟json資料格式的自動轉換,在設定類中開啟@EnableWebMvc
//2.使用@RequestBody註解將外部傳遞的json陣列資料對映到形參的集合物件中作為資料
@RequestMapping("/listParamForJson")
@ResponseBody
public String listParamForJson(@RequestBody List<String> likes){
System.out.println("list common(json)引數傳遞 list ==> "+likes);
return "{'module':'list common for json param'}";
}
//POJO引數:json格式
//1.開啟json資料格式的自動轉換,在設定類中開啟@EnableWebMvc
//2.使用@RequestBody註解將外部傳遞的json資料對映到形參的實體類物件中,要求屬性名稱一一對應
@RequestMapping("/pojoParamForJson")
@ResponseBody
public String pojoParamForJson(@RequestBody User user){
System.out.println("pojo(json)引數傳遞 user ==> "+user);
return "{'module':'pojo for json param'}";
}
//集合引數:json格式
//1.開啟json資料格式的自動轉換,在設定類中開啟@EnableWebMvc
//2.使用@RequestBody註解將外部傳遞的json陣列資料對映到形參的儲存實體類物件的集合物件中,要求屬性名稱一一對應
@RequestMapping("/listPojoParamForJson")
@ResponseBody
public String listPojoParamForJson(@RequestBody List<User> list){
System.out.println("list pojo(json)引數傳遞 list ==> "+list);
return "{'module':'list pojo for json param'}";
}
}
Postman操作:
在上面我們有兩個註解需要特別注意一下:
@RequestBody和@RequestParam區別
- 區別
- @RequestParam用於接收url地址傳參,表單傳參[application/x-www-form-urlencoded]
- @RequestBody用於接收JSON資料[application/json]
- 應用
- 後期開發中,傳送json資料為主,@RequestBody應用較廣
- 如果傳送非json格式資料,選用@RequestParam接收請求引數
我們的日期型別資料基於系統不同格式也不相同,大致有以下幾種:
接收形參時,我們根據不同的日期格式設定不同的接收方式
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
//請求引數
@Controller
public class UserController {
//日期引數
//使用@DateTimeFormat註解設定日期型別資料格式,預設格式yyyy/MM/dd
@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,
@DateTimeFormat(pattern="yyyy-MM-dd") Date date1,
@DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2){
System.out.println("引數傳遞 date ==> "+date);
System.out.println("引數傳遞 date1(yyyy-MM-dd) ==> "+date1);
System.out.println("引數傳遞 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);
return "{'module':'data param'}";
}
}
/*
名稱:@DateTimeFormat
型別:形參註解
位置:SpringMVC控制器方法前
作用:設定日期時間型資料格式
屬性:pattern:日期時間格式字串
*/
Postman操作:
這裡我們簡單介紹一下@DateTimeFormat的轉換原理Converter介面:
public interface Converter<S,T>{
@Nullable
T convert(S var1)
}
Converter介面屬於頂層介面,由它為起源建立了許多相關的介面與類用於各種轉化:
@EnableWebMvc功能之一:根據型別匹配對應的型別轉換器
在瞭解請求的相關知識之後,我們回到Controller程式碼中學習一下響應
在正常情況下,我們的響應給出的是當前專案的檔案,相當於頁面的跳轉效應:
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class UserController {
//響應頁面/跳轉頁面
//返回值為String型別,設定返回值為頁面名稱,即可實現頁面跳轉
@RequestMapping("/toJumpPage")
public String toJumpPage(){
System.out.println("跳轉頁面");
return "page.jsp";
}
}
如果我們希望得到一些資訊響應,就需要採用註解解釋:
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@Controller
public class UserController {
//響應文字資料
//返回值為String型別,設定返回值為任意字串資訊,即可實現返回指定字串資訊,需要依賴@ResponseBody註解
@RequestMapping("/toText")
@ResponseBody
public String toText(){
System.out.println("返回純文字資料");
return "response text";
}
//響應POJO物件
//返回值為實體類物件,設定返回值為實體類型別,即可實現返回對應物件的json資料,需要依賴@ResponseBody註解和@EnableWebMvc註解
@RequestMapping("/toJsonPOJO")
@ResponseBody
public User toJsonPOJO(){
System.out.println("返回json物件資料");
User user = new User();
user.setName("itcast");
user.setAge(15);
return user;
}
//響應POJO集合物件
//返回值為集合物件,設定返回值為集合型別,即可實現返回對應集合的json陣列資料,需要依賴@ResponseBody註解和@EnableWebMvc註解
@RequestMapping("/toJsonList")
@ResponseBody
public List<User> toJsonList(){
System.out.println("返回json集合資料");
User user1 = new User();
user1.setName("傳智播客");
user1.setAge(15);
User user2 = new User();
user2.setName("黑馬程式設計師");
user2.setAge(12);
List<User> userList = new ArrayList<User>();
userList.add(user1);
userList.add(user2);
return userList;
}
}
/*
名稱:@ResponseBody
型別:方法註解
位置:SpringMVC控制器方法定義上方
作用:設定當前控制器返回值作為響應體
*/
當我們使用Postman存取該連結時就會給出對應反饋,這裡就不做演示了
首先我們來簡單介紹一下REST:
我們給出正常風格和REST風格兩種書寫形式,我們可以明顯看到REST的內容做出大規模的省略:
REST風格優點:
我們來對REST風格做出簡單解釋:
我們給出五種常見行為動作:
我們通常將根據REST風格進行的存取稱為RESTful
上述行為是約定方式,約定不是規範,是可以打破的,所以稱為REST風格,而不是REST規範
描述模組的名稱通常使用負數,也就是加s的格式描述,表示此類,而非單個資源
從本質上而言,REST只是一種規範形式,我們對於REST的風格修改僅針對於Controller
我們下面將逐步進行RESTful的修改:
package com.itheima.controller;
import com.itheima.domain.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class BookController {
// RequestMapping中包含value和method兩種屬性
// value:存取路徑
// method:存取方法
@RequestMapping(value = "/users",method = Request.POST)
@RequestBody
public String save(@RequestBody User user){
System.out.println("user save" + user);
return "{'module':'user save'}"
}
}
/*
名稱:@RequestMapping
型別:方法註解
位置:SpringMVC控制器方法定義上方
作用:設定當前控制器方法請求存取路徑
屬性:value存取路徑,method請求動作
*/
package com.itheima.controller;
import com.itheima.domain.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class BookController {
// 首先針對我們所需引數給出@PathVariable註解,並在存取路徑中採用{}佔位表示所傳資料
// 簡單來說就是,系統根據請求路徑,得到所需資料,再帶入到方法中
@RequestMapping(value = "/users/{id}" ,method = RequestMethod.DELETE)
@RequestBody
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
}
/*
名稱:@PathVariable
型別:形參註解
位置:SpringMVC控制器方法形參定義前面
作用:繫結路徑引數與處理器方法形參間的關係,要求路徑引數名與形參名一一對應
*/
下面我們給出所有情況案例:
package com.itheima.controller;
import com.itheima.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@Controller
public class UserController {
//設定當前請求方法為POST,表示REST風格中的新增操作
@RequestMapping(value = "/users",method = RequestMethod.POST)
@ResponseBody
public String save(){
System.out.println("user save...");
return "{'module':'user save'}";
}
//設定當前請求方法為DELETE,表示REST風格中的刪除操作
//@PathVariable註解用於設定路徑變數(路徑引數),要求路徑上設定對應的預留位置,並且預留位置名稱與方法形參名稱相同
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){
System.out.println("user delete..." + id);
return "{'module':'user delete'}";
}
//設定當前請求方法為PUT,表示REST風格中的修改操作
@RequestMapping(value = "/users",method = RequestMethod.PUT)
@ResponseBody
public String update(@RequestBody User user){
System.out.println("user update..."+user);
return "{'module':'user update'}";
}
//設定當前請求方法為GET,表示REST風格中的查詢操作
//@PathVariable註解用於設定路徑變數(路徑引數),要求路徑上設定對應的預留位置,並且預留位置名稱與方法形參名稱相同
@RequestMapping(value = "/users/{id}" ,method = RequestMethod.GET)
@ResponseBody
public String getById(@PathVariable Integer id){
System.out.println("user getById..."+id);
return "{'module':'user getById'}";
}
//設定當前請求方法為GET,表示REST風格中的查詢操作
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
public String getAll(){
System.out.println("user getAll...");
return "{'module':'user getAll'}";
}
}
/*
下述為原有程式碼:
@RequestMapping
@ResponseBody
public String delete(){
System.out.println("user delete...");
return "{'module':'user delete'}";
}
@RequestMapping
@ResponseBody
public String update(){
System.out.println("user update...");
return "{'module':'user update'}";
}
@RequestMapping
@ResponseBody
public String getById(){
System.out.println("user getById...");
return "{'module':'user getById'}";
}
@RequestMapping
@ResponseBody
public String getAll(){
System.out.println("user getAll...");
return "{'module':'user getAll'}";
}
*/
我們在這裡給出@RequestBody,@RequestParam,@PathVariable區別
區別:
- @RequestParam用於接收url地址傳參或表單傳參
- @RequestBody用於接收json資料
- @PathVariable用於接收路徑引數,使用{引數名稱}描述路徑引數
應用:
- 後期開發中,傳送請求引數超過1個時,以json格式為主,@RequestBody應用較廣
- 如果傳送非json格式資料,選用@RequestParam接受請求引數
- 採用RESTful進行開發,當引數數量較少時,如1個,可以採用@PathVariable接收請求路徑變數,常用來傳遞id值
我們在上一小節中會發現有許多重複性的程式碼:
// 每次都填寫value,method導致程式碼繁冗
// 包括每次填寫ResponseBody使程式碼繁冗
@RequestMapping(value = "/users",method = RequestMethod.GET)
@ResponseBody
所以我們可以採用一些小技巧來簡化程式碼:
package com.itheima.controller;
import com.itheima.domain.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
//@Controller
//@ResponseBody
@RestController
@RequestMapping("/books")
public class BookController {
}
/*
正常情況下,我們的類本身具有@Controller,並且為了省略類中的@ResponseBody而直接標註在類頭
但Spring提供了一種新的註解@RestController,相當於@Controller和@ResponseBody的結合,我們只需要書寫這一個註解即可
名稱:@RestController
型別:類註解
位置:基於SpringMVC的RESTful開發控制器類定義上方
作用:設定當前控制器為RESTful風格,等同於@Controller與@ResponseBody兩個註解組合功能
*/
package com.itheima.controller;
import com.itheima.domain.Book;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/books")
public class BookController {
//@RequestMapping( method = RequestMethod.POST)
//使用@PostMapping簡化Post請求方法對應的對映設定
@PostMapping
public String save(@RequestBody Book book){
System.out.println("book save..." + book);
return "{'module':'book save'}";
}
//@RequestMapping(value = "/{id}" ,method = RequestMethod.DELETE)
//使用@DeleteMapping簡化DELETE請求方法對應的對映設定
@DeleteMapping("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
//@RequestMapping(method = RequestMethod.PUT)
//使用@PutMapping簡化Put請求方法對應的對映設定
@PutMapping
public String update(@RequestBody Book book){
System.out.println("book update..."+book);
return "{'module':'book update'}";
}
//@RequestMapping(value = "/{id}" ,method = RequestMethod.GET)
//使用@GetMapping簡化GET請求方法對應的對映設定
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("book getById..."+id);
return "{'module':'book getById'}";
}
//@RequestMapping(method = RequestMethod.GET)
//使用@GetMapping簡化GET請求方法對應的對映設定
@GetMapping
public String getAll(){
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}
/*
名稱:@GetMapping @PostMapping @PutMapping @DeleteMapping
型別:方法註解
位置:基於SpringMVC的RESTful開發控制器方法定義上方
作用:設定當前控制器方法請求存取路徑與請求動作,每種對應一個請求動作,例如@GetMapping對應GET請求
引數:value請求存取路徑
*/
好的,關於SpringMVC的內容就介紹到這裡,希望能為你帶來幫助!
該文章屬於學習內容,具體參考B站黑馬程式設計師李老師的SSM框架課程
這裡附上連結:SpringMVC-01-SpringMVC簡介_嗶哩嗶哩_bilibili