SSM-springMVC
springMVC完成表現(xiàn)層的開發(fā)

servlet能做的事情,springMVC都能做。servlet用來接收請(qǐng)求參數(shù),參數(shù)響應(yīng)結(jié)果,springMVC也可以做到這些


springMVC簡介


- MVC模型
![]()


springMVC入門案例




按照上面說的步驟來構(gòu)建項(xiàng)目
-
1.導(dǎo)入依賴
![]()
-
2.制作控制器
-
4.創(chuàng)建sevlet容器的配置類,由tomcat負(fù)責(zé)加載并創(chuàng)建servlet容器(替代web.xml)
-
注意
![]()
-
第一步
<?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>
<!--第一步導(dǎo)入依賴-->
<!--springmvc底層使用的是servlet-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope><!--避免和tomcat沖突-->
</dependency>
<!--里面已經(jīng)集成了spring-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
</dependencies>
<!--Tomcat7-maven-plugin這個(gè)插件可以快速配置并部署和啟動(dòng)web工程(這里沒有使用,沒有學(xué)習(xí)過)-->
<!--<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;
//第二步:定義controller
@Controller//2.1 將控制器將給spring管理
public class UserController {
//2.2設(shè)置當(dāng)前方法的訪問路徑
@RequestMapping("/save")
//2.3設(shè)置當(dāng)前操作的返回值(以save方法的返回值作為返回值)
@ResponseBody
public String save() {
System.out.println("user save....");
return "{'module':'springmvc'}";//以joson的形式返回?cái)?shù)據(jù)
}
}
- 第三步
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
//springmvc的配置類(其實(shí)就是spring的配置類)
//第三步:創(chuàng)建springMvc的配置文件,并加載對(duì)應(yīng)的bean
@Configuration//配置類
@ComponentScan("com.itheima.controller")//組件掃描
public class SpringMvcConfig {
}
- 第四步,讓tomcat加載springmvc配置文件,創(chuàng)建出servlet容器(替代web.xml)
package com.itheima.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
//第四步:一個(gè)servlet容器啟動(dòng)的配置類,在里面加載spring配置(替代web.xml文件)
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加載springmvc容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//設(shè)置哪些請(qǐng)求歸屬springmvc處理
@Override
protected String[] getServletMappings() {
return new String[] { "/" };//所有請(qǐng)求都交給springmvc處理
}
//加載spring容器配置
@Override
protected WebApplicationContext createRootApplicationContext() {
return null;
}
}
當(dāng)我們?cè)L問時(shí)將返回下面的結(jié)果

- 總結(jié)
![]()
入門案例工作流程


bean加載控制


對(duì)應(yīng)的方案

- 具體方案
![]()
- 注意
![]()
- 2種方案
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
@Configuration
//@ComponentScan({"com.itheima.dao", "com.itheima.service"})//精確掃描
@ComponentScan(value = "com.itheima",excludeFilters =@ComponentScan.Filter//使用不包含過濾器
(type = FilterType.ANNOTATION,//按照注解進(jìn)行過濾
classes = Configuration.class))//帶有Configuration注解的類將不進(jìn)行掃描
public class SpringConfig {
}
此時(shí)我們?cè)趦H僅加載spring的配置文件時(shí),在獲得controller的bean的時(shí)候?qū)?huì)報(bào)錯(cuò)(因?yàn)樗念惒]有被加載)


此時(shí)我們就可以在tomcat啟動(dòng)的時(shí)候同時(shí)加載springconfig和springmvc了
- 此時(shí)服務(wù)器加載的配置類就是:
package com.itheima.config;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;
//第四步:一個(gè)servlet容器啟動(dòng)的配置類,在里面加載spring配置(替代web.xml文件)
public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {
//加載springmvc容器配置
@Override
protected WebApplicationContext createServletApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringMvcConfig.class);
return ctx;
}
//設(shè)置哪些請(qǐng)求歸屬springmvc處理
@Override
protected String[] getServletMappings() {
return new String[] { "/" };//所有請(qǐng)求都交給springmvc處理
}
//加載spring容器配置
@Override
protected WebApplicationContext createRootApplicationContext() {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(SpringConfig.class);
return ctx;
}
}


- 我們只需要傳入各自的配置文件就可以了,不需要自己創(chuàng)建容器了
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;
//第四步:一個(gè)servlet容器啟動(dòng)的配置類,在里面加載spring配置(替代web.xml文件)
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[]{"/"};
}
}
postMan工具介紹

- 需要先創(chuàng)建一個(gè)工作空間
![]()
![]()
![]()
總結(jié)來說postman可以模擬瀏覽器向我的服務(wù)器發(fā)送請(qǐng)求,使用這個(gè)工具我們可以在很大程度上忽略前端的必要性,可以加速我們后端的開發(fā)
第二部分:請(qǐng)求與響應(yīng)
設(shè)置請(qǐng)求映射路徑
問題1:不同模塊相同的請(qǐng)求路徑?jīng)_突問題
- 下面有2個(gè)模塊:user和book
//第二步:定義controller
@Controller//2.1 將控制器將給spring管理
public class UserController {
//2.2設(shè)置當(dāng)前方法的訪問路徑
@RequestMapping("/save")
//2.3設(shè)置當(dāng)前操作的返回值(以save方法的返回值作為返回值)
@ResponseBody
public String save() {
System.out.println("user save....");
return "{'UserController':'springmvc'}";//以joson的形式返回?cái)?shù)據(jù)
}
@Controller
public class BookController {
//配置請(qǐng)求路徑
@RequestMapping("/save")
@ResponseBody
public String save(){
System.out.println("user save....");
return "{'BookController':'springmvc'}";
}
他們都有save方法,并且他們的請(qǐng)求路徑都是/save

- 解決沖突的方式
![]()

這樣我們的路徑?jīng)_突就解決了
問題2:同一個(gè)模塊中請(qǐng)求路徑冗長問題


一個(gè)小注意點(diǎn):在postman中使用ctrl+ 加號(hào)和ctrl+減號(hào)可以調(diào)整頁面的大小
get和post請(qǐng)求發(fā)送普通參數(shù)
1.get請(qǐng)求發(fā)送參數(shù)



對(duì)于我們controller中的方法是不區(qū)分get請(qǐng)求還是post請(qǐng)求的,他都能進(jìn)行處理。不需要寫doget和dopost方法了(在之前web中需要使用dopost調(diào)用doget以達(dá)到,方法對(duì)于get和post請(qǐng)求都能處理)。現(xiàn)在簡化了這個(gè)過程
1.post請(qǐng)求發(fā)送參數(shù)
我們的post請(qǐng)求的參數(shù)不是放在url中發(fā)送的,而是放在了請(qǐng)求體中進(jìn)行發(fā)送的(也就是為什么我們?cè)诘刂窓谥锌床坏絧ost請(qǐng)求的參數(shù)了),我們的post請(qǐng)求目前我知道的只能在from表單中進(jìn)行發(fā)送(method=post)



我們的get請(qǐng)求一般不會(huì)發(fā)送中文的參數(shù),下面解決post請(qǐng)求參數(shù)中文亂碼問題
解決post請(qǐng)求中文亂碼問題
- 過去的處理方式
![]()
在springmvc中我們?cè)趕ervlet容器的啟動(dòng)配置類中設(shè)置過濾器可以同樣達(dá)到這個(gè)效果 - 增加一個(gè)過濾器可以解決亂碼
//第四步:一個(gè)servlet容器啟動(dòng)的配置類,在里面加載spring配置(替代web.xml文件)
public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
//設(shè)置請(qǐng)求體的字符集過濾器
@Override
protected Filter[] getServletFilters() {
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("UTF-8");
return new Filter[]{filter};
}
protected String[] getServletMappings() {
return new String[]{"/"};
}
}

注意我們這個(gè)僅僅可以解決post請(qǐng)求體中文亂碼問題,對(duì)于get請(qǐng)求體的中文亂碼問題并不能解決

5種類型參數(shù)傳遞

在前面的我們必須在服務(wù)器端設(shè)置和發(fā)送的參數(shù)相同名稱的方法形參,才能接收到這個(gè)傳遞過來的參數(shù)。我們?cè)鯓涌梢詫?shí)現(xiàn)不這樣做也可以接收到參數(shù)呢?
設(shè)置請(qǐng)求參數(shù)和controller中方法參數(shù)的映射(解決上面的問題)


在一般情況下我們使用默認(rèn)的映射就可以了,不需要寫這個(gè)映射關(guān)系
但是在大多數(shù)情況下我們都是收集一些數(shù)據(jù)封裝成一個(gè)domain,所以下面將演示傳遞一個(gè)domain作為參數(shù)
- POJO數(shù)據(jù)類型
package com.itheima.domain;
public class User {
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 獲取
* @return name
*/
public String getName() {
return name;
}
/**
* 設(shè)置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 獲取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 設(shè)置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
public String toString() {
return "User{name = " + name + ", age = " + age + "}";
}
}
- 控制器
@RequestMapping("/pojoParam")
@ResponseBody
public String pojoParam(User user){
System.out.println("接收到的參數(shù):"+user);
return "{'BookController':'pojo'}";
}


只要我們的請(qǐng)求參數(shù)名和我們的domain的屬性名相同,將會(huì)被自動(dòng)封裝成domain對(duì)象
- 嵌套POJO類型參數(shù)(pojo對(duì)象里面還有引用類型的屬性)
- User類(里面包含引用類型的屬性Address)
package com.itheima.domain;
public class User {
private String name;
private Integer age;
private Address address;
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
/**
* 獲取
* @return name
*/
public String getName() {
return name;
}
/**
* 設(shè)置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 獲取
* @return age
*/
public Integer getAge() {
return age;
}
/**
* 設(shè)置
* @param age
*/
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
- Address
package com.itheima.domain;
public class Address {
private String province;
private String city;
public Address() {
}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
/**
* 獲取
* @return province
*/
public String getProvince() {
return province;
}
/**
* 設(shè)置
* @param province
*/
public void setProvince(String province) {
this.province = province;
}
/**
* 獲取
* @return city
*/
public String getCity() {
return city;
}
/**
* 設(shè)置
* @param city
*/
public void setCity(String city) {
this.city = city;
}
public String toString() {
return "Address{province = " + province + ", city = " + city + "}";
}
}


- 數(shù)組類型參數(shù)


- 集合類型參數(shù)
![]()
![]()
因?yàn)樗麑?duì)于引用類型的處理方案是:創(chuàng)建出這個(gè)類型的對(duì)象,然后將請(qǐng)求參數(shù)setter進(jìn)去。(作為屬性)。但是我們現(xiàn)在是想讓請(qǐng)求參數(shù)作為集合的
值而不是屬性,而且list是接口也沒有構(gòu)造方法
![]()
![]()
對(duì)于傳遞參數(shù)總的來說,名稱可以對(duì)應(yīng)上的直接傳遞就可以了,名稱對(duì)應(yīng)不上 是使用@RequestParam綁定一下就可以了
jason數(shù)據(jù)傳遞參數(shù)(在開發(fā)中大概率使用的是這種方式)

我們的jason參數(shù)是放在請(qǐng)求體里面發(fā)送的
- 集合類型
![]()
- 1.添加jason依賴
<!--jason依賴,實(shí)現(xiàn)將jason數(shù)據(jù)轉(zhuǎn)化成java對(duì)象-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0</version>
</dependency>
-
2.在postman中編寫jason參數(shù)
![]()
但是此時(shí)我們springmvc還不知道傳遞過來的jason數(shù)據(jù),我們必須開啟一個(gè)功能鍵讓spingmvc幫我們轉(zhuǎn)化jason數(shù)據(jù) -
3.開啟轉(zhuǎn)化jason數(shù)據(jù)
![]()
-
4.設(shè)置參數(shù)映射
![]()
此時(shí)我們的jason數(shù)據(jù)就成功封裝到我們的domain中了 -
pojo類型
![]()
![]()
![]()
好像我們的address的值沒有,因?yàn)槲覀儾]有傳遞address屬性的值 -
傳遞address的值
![]()
![]()
-
JSON對(duì)象數(shù)組
![]()
![]()
![]()
-
注意點(diǎn)
![]()
![]()
從目前實(shí)驗(yàn)來看好像發(fā)送jason類型的數(shù)據(jù),在接收端的參數(shù)中都必須加上RequestBody注解才行。對(duì)于非jason參數(shù),
只有l(wèi)ist集合才需要加上RequestParam注解(因?yàn)槭菍⑺鳛橹担环夏J(rèn)的)
使用tomcat7-maven-plugin插件簡化tomcat啟動(dòng)
- 在pom.xml中添加toncat插件
<build>
<plugins>
<plugin>
<!--tomcat插件-->
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>80</port><!--設(shè)置項(xiàng)目使用的端口號(hào)(80為http協(xié)議默認(rèn)端口號(hào))將不需要寫端口號(hào)了-->
<path>/</path><!--默認(rèn)訪問路徑-->
</configuration>
</plugin>
</plugins>
</build>
- 可以使用下面的步驟快速啟動(dòng)tomcat服務(wù)器
![]()
當(dāng)我們將端口號(hào)設(shè)置成http協(xié)議默認(rèn)端口號(hào)80,我們可以省略工程名和端口號(hào)的書寫
![]()
日期型參數(shù)傳遞

1.對(duì)于默認(rèn)格式可以直接轉(zhuǎn)化為Date


2.對(duì)于不是默認(rèn)格式的日期(指定日期格式即可)



響應(yīng)

1.響應(yīng)頁面

但是不知道為什么我的方法可以被訪問到,但是頁面一直無法被顯示
響應(yīng)頁面問題的解決

補(bǔ)充配置maven-tomcat插件的快速啟動(dòng)(不是添加模板,是添加新配置)


2.響應(yīng)文本
我們前面的測(cè)試返回的都不是jason對(duì)象,都是返回的字符串(只是是jason格式的字符串)
@ResponseBody注解表示響應(yīng)的是數(shù)據(jù)


pojo對(duì)象


對(duì)象數(shù)組




第三部分內(nèi)容--REST風(fēng)格
REST風(fēng)格簡介


- 存在問題
![]()
![]()
![]()
對(duì)于請(qǐng)求方式有很多種,但是常用的也就是上面提到的4種
RESTFU入門案例


package com.itheima.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
//rext風(fēng)格
@Controller
public class UserController {
@RequestMapping(value = "/users",method = RequestMethod.POST)//表明是保存行為(請(qǐng)求不是post將報(bào)錯(cuò))
@ResponseBody
public String save(){
return "'module':'user save' ";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)//表明是刪除行為(請(qǐng)求不是delete將報(bào)錯(cuò))
@ResponseBody
public String delete(@PathVariable int id){
System.out.println("參數(shù)是"+id);
return "'module':'user delete' ";
}
@RequestMapping(value = "/users",method = RequestMethod.PUT)//表明是更新行為(請(qǐng)求不是post將報(bào)錯(cuò))
@ResponseBody
public String update(){
return "'module':'user update' ";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.GET)//表明是查詢行為(請(qǐng)求不是delete將報(bào)錯(cuò))
@ResponseBody
public String selectById(@PathVariable int id){
System.out.println("參數(shù)是"+id);
return "'module':'user select' ";
}
@RequestMapping(value = "/users",method = RequestMethod.GET)//表明是查詢行為(請(qǐng)求不是delete將報(bào)錯(cuò))
@ResponseBody
public String select(){
return "'module':'user select' ";
}
}

RESTFUL快速開發(fā)

@RestController //@Controller + ReponseBody
@RequestMapping("/books")
public class BookController {
//@RequestMapping(method = RequestMethod.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("/{id}")
public String delete(@PathVariable Integer id){
System.out.println("book delete..." + id);
return "{'module':'book delete'}";
}
//@RequestMapping(method = RequestMethod.PUT)
/* 名稱 @RestController
類型 類注解
位置 基于SpringMVC的RESTful開發(fā)控制器類定義上方
作用 設(shè)置當(dāng)前控制器類為RESTful風(fēng)格,
等同于@Controller與@ResponseBody兩個(gè)注解組合功能
對(duì)于剛才的問題,我們都有對(duì)應(yīng)的解決方案:
問題1:每個(gè)方法的@RequestMapping注解中都定義了訪問路徑/books,重復(fù)性太高。
問題2:每個(gè)方法的@RequestMapping注解中都要使用method屬性定義請(qǐng)求方式,重復(fù)性太高。
問題3:每個(gè)方法響應(yīng)json都需要加上@ResponseBody注解,重復(fù)性太高。
知識(shí)點(diǎn)1:@RestController
知識(shí)點(diǎn)2:@GetMapping @PostMapping @PutMapping @DeleteMapping*/
@PutMapping
public String update(@RequestBody Book book){
System.out.println("book update..." + book);
return "{'module':'book update'}";
}
//@RequestMapping(value = "/{id}",method = RequestMethod.GET)
@GetMapping("/{id}")
public String getById(@PathVariable Integer id){
System.out.println("book getById..." + id);
return "{'module':'book getById'}";
}
//@RequestMapping(method = RequestMethod.GET)
@GetMapping
public String getAll(){
System.out.println("book getAll...");
return "{'module':'book getAll'}";
}
}
總結(jié)來說是使用了下面新的注解

案例:基于RESTFUL頁面數(shù)據(jù)交互(后臺(tái)接口的開發(fā))
package com.itheima.controller;
import com.itheima.domain.Book;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
//保存圖書
@PostMapping
//RequestBody注解表明參數(shù)從請(qǐng)求體重獲取
public String save(@RequestBody Book book) {
System.out.println("book-->" + book);
return "'book':'book' ";
}
//查詢所有圖書
@GetMapping
public List<Book>getAll(){
List<Book> list = new ArrayList<Book>();
Book book1 = new Book();
book1.setName("紅樓夢(mèng)");
book1.setType("小說");
book1.setDescription("一本好書");
list.add(book1);
Book book2 = new Book();
book2.setName("西游記");
book2.setType("小說");
book2.setDescription("一本好書");
list.add(book2);
return list;
}
}


案例:基于RESTFUL頁面數(shù)據(jù)交互(頁面訪問處理)
1.放行非springmvc的請(qǐng)求
當(dāng)我們直接訪問靜態(tài)頁面的時(shí)候?qū)o法封裝:

因?yàn)槲覀儧]有在controller中給頁面配置請(qǐng)求地址

解決方案
- springMVC需要將靜態(tài)資源進(jìn)行放行。
package com.itheima.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {
//設(shè)置靜態(tài)資源訪問過濾,當(dāng)前類需要設(shè)置為配置類,并被掃描加載
@Override
protected void addResourceHandlers(ResourceHandlerRegistry registry) {
//當(dāng)訪問/pages/????時(shí)候,從/pages目錄下查找內(nèi)容
registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
registry.addResourceHandler("/js/**").addResourceLocations("/js/");
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/")
;
}
}
- 可以正常訪問了
![]()
ajax請(qǐng)求可以實(shí)現(xiàn)異步發(fā)送請(qǐng)求,局部更新頁面
下面以ajax請(qǐng)求舉例,前端發(fā)送ajax請(qǐng)求,后臺(tái)返回jason對(duì)象,然后前臺(tái)使用返回的數(shù)據(jù)進(jìn)行頁面的局部更新
前端不熟悉,故不展開
第四部分-SSM整合
ssm-整合配置



在配置方面好像就是spring將mybatis的配置放在自己配置里面一起加載。springmvc則自己加載。把這2方面放在servletconfig中各自加載
ssm-功能模塊開發(fā)
1.創(chuàng)建表并插入數(shù)據(jù)
CREATE DATABASE ssm
USE ssm
CREATE TABLE tbl_book(
id INT PRIMARY KEY AUTO_INCREMENT,
TYPE VARCHAR(20),
NAME VARCHAR(50),
description VARCHAR(255)
)
INSERT INTO tbl_book(id,type,name,description) VALUES (1,'計(jì)算機(jī)理
論','Spring實(shí)戰(zhàn) 第五版','Spring入門經(jīng)典教程,深入理解Spring原理技術(shù)內(nèi)幕'),(2,'計(jì)算機(jī)理
論','Spring 5核心原理與30個(gè)類手寫實(shí)踐','十年沉淀之作,手寫Spring精華思想'),(3,'計(jì)算機(jī)理
論','Spring 5設(shè)計(jì)模式','深入Spring源碼刨析Spring源碼中蘊(yùn)含的10大設(shè)計(jì)模式'),(4,'計(jì)算機(jī)
理論','Spring MVC+Mybatis開發(fā)從入門到項(xiàng)目實(shí)戰(zhàn)','全方位解析面向Web應(yīng)用的輕量級(jí)框架,帶你
成為Spring MVC開發(fā)高手'),(5,'計(jì)算機(jī)理論','輕量級(jí)Java Web企業(yè)應(yīng)用實(shí)戰(zhàn)','源碼級(jí)刨析
Spring框架,適合已掌握J(rèn)ava基礎(chǔ)的讀者'),(6,'計(jì)算機(jī)理論','Java核心技術(shù) 卷Ⅰ 基礎(chǔ)知識(shí)(原書
第11版)','Core Java第11版,Jolt大獎(jiǎng)獲獎(jiǎng)作品,針對(duì)Java SE9、10、11全面更新'),(7,'計(jì)算
機(jī)理論','深入理解Java虛擬機(jī)','5個(gè)緯度全面刨析JVM,大廠面試知識(shí)點(diǎn)全覆蓋'),(8,'計(jì)算機(jī)理
論','Java編程思想(第4版)','Java學(xué)習(xí)必讀經(jīng)典,殿堂級(jí)著作!贏得了全球程序員的廣泛贊譽(yù)'),
(9,'計(jì)算機(jī)理論','零基礎(chǔ)學(xué)Java(全彩版)','零基礎(chǔ)自學(xué)編程的入門圖書,由淺入深,詳解Java語言
的編程思想和核心技術(shù)'),(10,'市場(chǎng)營銷','直播就這么做:主播高效溝通實(shí)戰(zhàn)指南','李子柒、李佳
奇、薇婭成長為網(wǎng)紅的秘密都在書中'),(11,'市場(chǎng)營銷','直播銷講實(shí)戰(zhàn)一本通','和秋葉一起學(xué)系列網(wǎng)
絡(luò)營銷書籍'),(12,'市場(chǎng)營銷','直播帶貨:淘寶、天貓直播從新手到高手','一本教你如何玩轉(zhuǎn)直播的
書,10堂課輕松實(shí)現(xiàn)帶貨月入3W+');
SELECT * FROM tbl_book

ssm整合--接口測(cè)試
在開發(fā)中有2個(gè)環(huán)節(jié)需要停下來做測(cè)試:1.當(dāng)持業(yè)務(wù)層(即sevice和dao都寫完的時(shí)候)開發(fā)完成時(shí)需要使用junit做業(yè)務(wù)層接口的測(cè)試2.當(dāng)表現(xiàn)層測(cè)試完成需要使用postman做表現(xiàn)層接口的測(cè)試
注意正規(guī)的junit測(cè)試還需要做斷言和匹配
- 1.測(cè)試業(yè)務(wù)層
- 2.測(cè)試表現(xiàn)層
![]()
- 3.配置事務(wù)
傳播行為等書寫,先不要配置看具體需求 - ssm整合全套代碼
建表語句看前面 - config
- jdbcconfig
package com.itheima.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
public class JdbcConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setUrl(url);
return dataSource;
}
//配置事務(wù)管理器
@Bean
public PlatformTransactionManager getTransactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);//配置數(shù)據(jù)源
return transactionManager;
}
}
- mybatisconfig
package com.itheima.config;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import javax.sql.DataSource;
public class MyBatisConfig {
//將sqlSessionFactory交給spring
@Bean
public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource);//設(shè)置數(shù)據(jù)源
factoryBean.setTypeAliasesPackage("com.itheima.domain");//設(shè)置別名
return factoryBean;
}
//映射器
@Bean
public MapperScannerConfigurer getMapperScannerConfigurer(){
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.itheima.dao");//將dao包的路徑作為映射路徑
return mapperScannerConfigurer;
}
}
- servletconfig
package com.itheima.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
//web容器配置類
public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};//將該路徑的請(qǐng)求都交給springmvc
}
}
- springconfig
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.transaction.annotation.EnableTransactionManagement;
@Configuration
@ComponentScan("com.itheima.service")//組件掃描
@PropertySource("classpath:jdbc.properties")//導(dǎo)入配置文件
@EnableTransactionManagement//開啟事務(wù)管理
@Import({JdbcConfig.class,MyBatisConfig.class})//導(dǎo)入其他配置類
public class SpringConfig {
}
- springmvcconfig
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc//開啟web相關(guān)的功能
public class SpringMvcConfig {
}
- bookcontroller
package com.itheima.controller;
import com.itheima.domain.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public boolean save(@RequestBody Book book) {
System.out.println("保存的圖書信息:"+book);
return bookService.save(book);
}
@PutMapping
public boolean update(@RequestBody Book book) {
return bookService.update(book);
}
@DeleteMapping("/{id}")
public boolean delete(@PathVariable Integer id) {
return bookService.delete(id);
}
@GetMapping("/{id}")
public Book getById(@PathVariable Integer id) {
return bookService.getById(id);
}
@GetMapping
public List<Book> getAll() {
return bookService.getAll();
}
}
- bookdao
package com.itheima.dao;
import com.itheima.domain.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List;
public interface BookDao {
@Insert("insert into tbl_book values(null,#{type},#{name},#{description})")
public void save(Book book);
@Update("update tbl_book set type=#{type},name=#{name},description=#{description} where id=#{id}")
public void update(Book book);
@Delete("delete from tbl_book where id=#{id}")
public void delete(Integer id);
@Select("select * from tbl_book where id=#{id}")
public Book getById(Integer id);
@Select("select * from tbl_book")
public List<Book> getAll();
}
- book
package com.itheima.domain;
public class Book {
private Integer id;
private String type;
private String name;
private String description;
public Book() {
}
public Book(Integer id, String type, String name, String description) {
this.id = id;
this.type = type;
this.name = name;
this.description = description;
}
/**
* 獲取
* @return id
*/
public Integer getId() {
return id;
}
/**
* 設(shè)置
* @param id
*/
public void setId(Integer id) {
this.id = id;
}
/**
* 獲取
* @return type
*/
public String getType() {
return type;
}
/**
* 設(shè)置
* @param type
*/
public void setType(String type) {
this.type = type;
}
/**
* 獲取
* @return name
*/
public String getName() {
return name;
}
/**
* 設(shè)置
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 獲取
* @return description
*/
public String getDescription() {
return description;
}
/**
* 設(shè)置
* @param description
*/
public void setDescription(String description) {
this.description = description;
}
public String toString() {
return "Book{id = " + id + ", type = " + type + ", name = " + name + ", description = " + description + "}";
}
}
- bookservice
package com.itheima.service;
import com.itheima.domain.Book;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
/*
1.一般業(yè)務(wù)層方法名和持久層不同(需要一眼就知道是什么業(yè)務(wù)
2.業(yè)務(wù)層刪除修改保存方法一般返回boolean)
* */
@Transactional//給所有的業(yè)務(wù)方法加上事務(wù)
public interface BookService {
public boolean save(Book book);
public boolean update(Book book);
public boolean delete(Integer id);
public Book getById(Integer id);
public List<Book> getAll();
}
- bookserviceimpl
package com.itheima.service.impl;
import com.itheima.dao.BookDao;
import com.itheima.domain.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BookServiceImpl implements BookService {
@Autowired
private BookDao bookDao;
public boolean save(Book book) {
bookDao.save(book);
return true;
}
public boolean update(Book book) {
bookDao.update(book);
return true;
}
public boolean delete(Integer id) {
bookDao.delete(id);
return true;
}
public Book getById(Integer id) {
return bookDao.getById(id);
}
public List<Book> getAll() {
return bookDao.getAll();
}
}
表現(xiàn)層與前端數(shù)據(jù)傳輸協(xié)議的定義

前端將無法區(qū)分哪個(gè)是直接可以使用的數(shù)據(jù)


- 但是可能還是存在下面問題
![]()
![]()
- 最終的骨架
![]()
- 封裝模型如下
![]()
表現(xiàn)層與前端數(shù)據(jù)傳輸協(xié)議的實(shí)現(xiàn)
我們需要定義的數(shù)據(jù)結(jié)果模型應(yīng)該是給表現(xiàn)層使用的,所以我們一般把result類放在controller包中
在這個(gè)實(shí)現(xiàn)中,我們?cè)诓樵冎形覀儗⒎祷豱ull設(shè)置為查詢失敗,將返回非null設(shè)置為查詢成功(并不是表示代碼異常錯(cuò)誤的失敗)
其實(shí)就是和前端通信的協(xié)議
- 數(shù)據(jù)結(jié)果封裝類
package com.itheima.controller;
//數(shù)據(jù)結(jié)構(gòu)封裝模型
public class Result {
private Object data;//數(shù)據(jù)
private Integer code;//狀態(tài)碼
private String msg;//特殊信息
//提供多種形式的構(gòu)造方法以方便我們使用
public Result() {
}
public Result( Integer code,Object data) {
this.data = data;
this.code = code;
}
public Result(Integer code,Object data, String msg) {
this.data = data;
this.code = code;
this.msg = msg;
}
/**
* 獲取
* @return data
*/
public Object getData() {
return data;
}
/**
* 設(shè)置
* @param data
*/
public void setData(Object data) {
this.data = data;
}
/**
* 獲取
* @return code
*/
public Integer getCode() {
return code;
}
/**
* 設(shè)置
* @param code
*/
public void setCode(Integer code) {
this.code = code;
}
/**
* 獲取
* @return msg
*/
public String getMsg() {
return msg;
}
/**
* 設(shè)置
* @param msg
*/
public void setMsg(String msg) {
this.msg = msg;
}
public String toString() {
return "Result{data = " + data + ", code = " + code + ", msg = " + msg + "}";
}
}
package com.itheima.controller;
//狀態(tài)碼類
public class Code {
public static final Integer SAVE_OK=20011;
public static final Integer DELETE_OK=20021;
public static final Integer UPDATE_OK=20031;
public static final Integer GET_OK=20041;
public static final Integer SAVE_ERR=20010;
public static final Integer DELETE_ERR=20020;
public static final Integer UPDATE_ERR=20030;
public static final Integer GET_ERR=20040;
}
- 修改后的控制器類
package com.itheima.controller;
import com.itheima.domain.Book;
import com.itheima.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookService bookService;
@PostMapping
public Result save(@RequestBody Book book) {
final boolean flag = bookService.save(book);
return new Result(flag?Code.SAVE_OK:Code.SAVE_ERR,flag);
}
@PutMapping
public Result update(@RequestBody Book book) {
final boolean flag = bookService.update(book);
return new Result(flag?Code.UPDATE_OK:Code.UPDATE_ERR,flag);
}
@DeleteMapping("/{id}")
public Result delete(@PathVariable Integer id) {
final boolean flag = bookService.delete(id);
return new Result(flag?Code.DELETE_OK:Code.DELETE_ERR,flag); }
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
final Book book = bookService.getById(id);
Integer code = book!=null?Code.GET_OK:Code.GET_ERR;
String msg = book!=null?"":"查詢失敗";//對(duì)于查詢成功的msg可以隨便寫,前端不會(huì)去使用
return new Result(code,book,msg);
}
@GetMapping
public Result getAll() {
final List<Book> bookList = bookService.getAll();
Integer code = bookList!=null?Code.GET_OK:Code.GET_ERR;
String msg = bookList!=null?"":"查詢失敗";//對(duì)于查詢成功的msg可以隨便寫,前端不會(huì)去使用
return new Result(code,bookList,msg);
}
}
ssm整合-異常處理器
- 當(dāng)我們程序出現(xiàn)異常時(shí)-返回的前端的是什么呢?
![]()


- 分析異常
![]()
![]()
![]()
總結(jié)異常處理 - 1.異常需要分類處理
- 2.異常需要放在表現(xiàn)層處理
- 3.異常需要使用AOP的思想處理
我們不需要自己寫AOP,spring給我們提供了建議方法--異常處理器
![]()
- 該節(jié)代碼基于前面的代碼
我們的異常處理器是集中處理controller中的異常的,所以寫在contaroller包中比較好 - 異常處理器類
package com.itheima.controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//異常處理器
@RestControllerAdvice//用于處理rest風(fēng)格開發(fā)的controller
public class ProjectExceptionAdvice {
@ExceptionHandler(Exception.class)//定義該方法用來處理哪一種異常
public Result doException(Exception e){
//此時(shí)還沒有設(shè)置異常的相關(guān)狀態(tài)碼(僅僅示意)
return new Result(666,null);//將異常包裝成結(jié)果返回給前端
}
}

- 總結(jié)


這時(shí)候我們正常情況和異常情況下都可以返回給前端統(tǒng)一的數(shù)據(jù),有利協(xié)調(diào)了前后的開發(fā)
ssm整合--項(xiàng)目異常處理
- 我們?cè)陧?xiàng)目中的異常處理
![]()
![]()
![]()
![]()
- 完成處理方案的代碼編寫
- 1.定義異常編碼
![]()
2.我們需要自定義系統(tǒng)異常和業(yè)務(wù)異常
package com.itheima.exception;
public class BusinessException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public BusinessException(Integer code, String message ) {
super(message);
this.code = code;
}
public BusinessException(Integer code, String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
package com.itheima.exception;
public class SystemException extends RuntimeException{
private Integer code;
public Integer getCode() {
return code;
}
public SystemException(Integer code, String message ) {
super(message);
this.code = code;
}
public SystemException( Integer code,String message, Throwable cause) {
super(message, cause);
this.code = code;
}
}
- 3.在controller中模擬出業(yè)務(wù)異常和系統(tǒng)異常
@GetMapping("/{id}")
public Result getById(@PathVariable Integer id) {
//模擬業(yè)務(wù)異常
if(id!=1){
throw new BusinessException(Code.BUSINESS_ERR,"請(qǐng)不要使用你的技術(shù)挑戰(zhàn)我們的耐性");
}
final Book book = bookService.getById(id);
//模擬系統(tǒng)異常
try {
int a=2/0;
} catch (Exception e) {
//將出現(xiàn)的異常封裝成系統(tǒng)異常
throw new SystemException(Code.SYSTEM_ERR,"服務(wù)區(qū)超時(shí),請(qǐng)重試",e);
}
Integer code = book!=null?Code.GET_OK:Code.GET_ERR;
String msg = book!=null?"":"查詢失敗";//對(duì)于查詢成功的msg可以隨便寫,前端不會(huì)去使用
return new Result(code,book,msg);
}
- 4.編寫不同種類的異常處理器
package com.itheima.controller;
import com.itheima.exception.BusinessException;
import com.itheima.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
//異常處理器
@RestControllerAdvice//用于處理rest風(fēng)格開發(fā)的controller
public class ProjectExceptionAdvice {
//處理系統(tǒng)異常
@ExceptionHandler(SystemException.class)//定義處理系統(tǒng)異常
public Result doSystemException(SystemException e){
//1.記錄日志
// 2.發(fā)送消息給運(yùn)維
//3.發(fā)送郵件給開發(fā)人員(將e這個(gè)對(duì)象發(fā)送給開發(fā)人員)
//code和massage通過異常對(duì)象傳遞過來了
return new Result(e.getCode(),null,e.getMessage());//將異常包裝成結(jié)果返回給前端
}
//處理業(yè)務(wù)異常
@ExceptionHandler(BusinessException.class)//定義處理系統(tǒng)異常
public Result doBusinessSystemException(BusinessException e){
//code和massage通過異常對(duì)象傳遞過來了
return new Result(e.getCode(),null,e.getMessage());//將異常包裝成結(jié)果返回給前端
}
//處理其他異常
@ExceptionHandler(Exception.class)
public Result doException(Exception e){
//1.記錄日志
// 2.發(fā)送消息給運(yùn)維
//3.發(fā)送郵件給開發(fā)人員(將e這個(gè)對(duì)象發(fā)送給開發(fā)人員)
//code和massage通過異常對(duì)象傳遞過來了
return new Result(Code.SYSTEM_UNKNOW_ERR,null,"系統(tǒng)繁忙,請(qǐng)稍后再試");//將異常包裝成結(jié)果返回給前端
}
}
- 注意
![]()
對(duì)于異常的封裝我們可以使用AOP來完成
前后端協(xié)議聯(lián)調(diào)--列表查詢功能
1.給直接訪問頁面的請(qǐng)求放行

- 前端頁面發(fā)送
![]()
前后端協(xié)議聯(lián)調(diào)(添加功能)
- 1.彈出添加窗口
![]()
![]()
![]()
前后端協(xié)議聯(lián)調(diào)(添加功能狀態(tài)處理)

在已有的代碼中,我們的程序只可能是添加成功的

修改:我們可以根據(jù)dao層中函數(shù)的返回值(收到影響的行數(shù))來判斷是否執(zhí)行成功,進(jìn)而通過這個(gè)決定servcie層的返回值


- 我們現(xiàn)在實(shí)驗(yàn)添加失敗的情況
![]()
但是我們點(diǎn)擊后,并沒有出現(xiàn)添加失敗的提示框 - 我們?cè)诳刂婆_(tái)中刪除后臺(tái)返回的數(shù)據(jù):
![]()
![]()
- 這里我們就把這個(gè)異常當(dāng)成是其他異常處理把
![]()
- 一個(gè)小問題
![]()
![]()
前后端協(xié)議聯(lián)調(diào)(修改功能)
1.在修改編輯框中顯示修改前的元數(shù)據(jù)

2.執(zhí)行更新操作

前后端協(xié)議聯(lián)調(diào)(刪除功能)

ssm整合標(biāo)準(zhǔn)總結(jié)


第五部分:攔截器

攔截器簡介




攔截器入門案例

建議將攔截器類下載controller中,因?yàn)閿r截器都是給表現(xiàn)層用的





我們修改一下攔截器的配置,讓他可以攔截更多的東西

- 注意
![]()
攔截器配置的簡化

我們可以將support類中的攔截器配置和靜態(tài)資源訪問放行的配置都放在springmvcconfig中配置,以后就不用寫support類了。
但是感覺會(huì)造成springmvc類冗余,個(gè)人不建議這么做
- 2種方式(有無使用攔截器)執(zhí)行流程在分析
![]()

攔截器參數(shù)
應(yīng)用的比較多是preHandle中的參數(shù)
public class ProjectInterceptor implements HandlerInterceptor {
//原始方法調(diào)用前執(zhí)行的內(nèi)容
public boolean preHandle(HttpServletRequest request, HttpServletResponse
response, Object handler) throws Exception {
final String header = request.getHeader("User-Agent");
System.out.println("header:"+header);
System.out.println("preHandle...");//1.獲取請(qǐng)求相關(guān)的信息
//handler(真實(shí)類型:HandlerMethod)對(duì)象封裝了我們正在執(zhí)行的方法
HandlerMethod hm = (HandlerMethod) handler;//強(qiáng)轉(zhuǎn)成真實(shí)類型
final Method method = hm.getMethod();//2.此時(shí)可以得到我們需求執(zhí)行的方法
System.out.println(method);
//可以在該方法中做校驗(yàn),以確定該方法是返回true還是false
return true;
}
//原始方法調(diào)用后執(zhí)行的內(nèi)容
public void postHandle(HttpServletRequest request, HttpServletResponse
response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle...");
//ModelAndView類封裝了進(jìn)行頁面跳轉(zhuǎn)的一些數(shù)據(jù)
}
//原始方法調(diào)用完成后執(zhí)行的內(nèi)容
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) throws Exception
{
//ex中可以拿到原始程序執(zhí)行過程中拋出的異常
System.out.println("afterCompletion...");
}
handle對(duì)象是對(duì)原始執(zhí)行方法的封裝,如果得到了handle對(duì)象,就可以對(duì)原始方法進(jìn)行操作了
攔截器鏈配置



- 我們將第一個(gè)攔截器的pre返回值改為fasle
![]()
![]()
但是在實(shí)際開發(fā)中,攔截器配置一個(gè)就可以了。配置攔截器鏈的情況還是很少的
![]()


































































浙公網(wǎng)安備 33010602011771號(hào)