SpringMVC学习记录

SpringMVC技术与servlet技术功能等同,均属于web层开发技术

SpringMVC简介

SpringMVC概述

SpringMVC是一种基于Java实现MIVC模型的轻量级web框架

优点

  • 使用简单,开发便捷(相比于servlet)
  • 灵活性强

SpringMVC是一种表现层框架技术

SpringMVC用于进行表现层功能开发

SpringMVC入门案例

①:使用SpringMVC技术需要先导入SpringMVC坐标与Servlet坐标

<?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><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--1.导入坐标springmvc和servlet--><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></dependencies><build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><port>8080</port><path>/</path></configuration></plugin></plugins></build></project>

②:创建SpringMVC控制器类(等同于Servlet功能)

package com.example.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;// 2.定义controller
// 2.1使用@Controller定义bean
@Controller
public class UserController {// 2.2设置当前操作的访问路径@RequestMapping("/save")// 2.3设置当前操作的返回值类型@ResponseBodypublic String save() {System.out.println("user save ...");return "{'info':'springmvc}";}
}

③:初始化SpringMVC环境(同Spring环境),设定SpringMVC加载对应的bean

package com.example.config;import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;// 3.创建springmvc的配置文件,加载controller对应的bean
@Configuration
@ComponentScan("com.example.controller")
public class SpringMVCConfig {
}

④:初始化Servlet容器,加载SpringMVC环境,并设置SpringMVC技术处理的请求

package com.example.config;import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;// 4.定义一个servlet容器启动的配置类,在里面加载spring的配置
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

类型:类注解

位置:SpringMVC控制器类定义上方

作用:设定SpringMVC的核心控制器bean

范例:

@Controller
public class UserController {
}

名称:@RequestMapping

类型:方法注解

位置:SpringMVC控制器方法定义上方

作用:设置当前控制器方法请求访问路径

范例:

	@RequestMapping("/save")public String save() {System.out.println("user save ...");return "{'info':'springmvc}";}

相关属性

value(默认):请求访问路径

名称:@ResponseBody

类型:方法注解

位置:SpringMVC控制器方法定义上方

作用:设置当前控制器方法响应内容为当前返回值,无需解析

范例:

// 2.定义controller
// 2.1使用@Controller定义bean
@Controller
public class UserController {// 2.2设置当前操作的访问路径@RequestMapping("/save")// 2.3设置当前操作的返回值类型@ResponseBodypublic String save() {System.out.println("user save ...");return "{'info':'springmvc}";}
}

AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类

AbstractDispatcherServletInitializer提供三个接口方法供用户实现

  • createServletApplicationContext()方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围
  • createRootApplicationContext()方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方式同createServletApplicationContext()
  • getServletMappings()方法,设定SpringMVC对应的请求映射路径,设置为/表示拦截所有请求,任意请求都将转入到SpringMVC进行处理

入门案例工作流程分析

  • 启动服务器初始化过程
  1. 服务器启动,执行ServletContainersInitConfig类,初始化web容器
  2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象
  3. 加载SpringMvcConfig
  4. 执行@ComponentScan加载对应的bean
  5. 加载UserController,每个@RequestMapping的名称对应一个具体的方法
  6. 执行getServletMappings方法,定义所有的请求都通过SpringMVC
  • 单次请求过程
  1. 发送请求localhost/save
  2. web容器发现所有请求都经过SpringMVC,将请求交给SpringMVC处理
  3. 解析请求路径/save
  4. 由/save匹配执行对应的方法save()
  5. 执行save()
  6. 检测到有@ResponseBody直接将save()方法的返回值作为响应求体返回给请求方

bean加载控制

SpringMVC加载其相关bean(表现层bean),也就是controller包下的类

Spring控制的bean

  • 业务bean(Service)
  • 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)

如何让Spring和SpringMVC分开加载各自的内容。

因为功能不同,如何避免Spring错误加载到SpringMVC的bean?

  • 方式一:Spring加载的bean设定扫描范围为com.itheima,排除掉controller包中的bean
@Configuration
@ComponentScan(value="com.itheima",excludeFilters=@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)
)
public class SpringConfig {
}

excludeFilters属性:设置扫描加载bean时,排除的过滤规则

type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除

ANNOTATION:按照注解排除

ASSIGNABLE_TYPE:按照指定的类型过滤

ASPECTJ:按照Aspectj表达式排除,基本上不会用

REGEX:按照正则表达式排除

CUSTOM:按照自定义规则排除

classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean

  • 方式二:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
@Configuration
@ComponentScan({"com.itheima.service","comitheima.dao"})
public class SpringConfig {
}
  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

PostMan

Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件

作用:常用于进行接口测试

特征

  • 简单
  • 实用
  • 美观
  • 大方

请求与响应

请求映射路径

  • 名称:@RequestMapping

  • 类型:方法注解 类注解

  • 位置:SpringMVC控制器方法定义上方

  • 作用:设置当前控制器方法请求访问路径,如果设置在类上统一设置当前控制器方法请求访问路径前缀

  • 范例:

    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")@ResponseBodypublic String save(){System.out.println("user save ...");return "{'module':'user save'}";}//请求路径映射@RequestMapping("/delete")@ResponseBodypublic String delete(){System.out.println("user delete ...");return "{'module':'user delete'}";}}
    
  • 属性

    • value(默认):请求访问路径,或访问路径前缀

请求参数

@Controller
public class UserController {//请求路径映射@RequestMapping("/commonParam")@ResponseBodypublic String commonParam(String name,int age) {System.out.println("name:"+name+",age:"+age);return "{'user':'common param'}";}}

GET请求

选择GET。

postman中直接输入

http://localhost:8080/commonParam?name=faiz&age=555

点击send

运行结果:

name:faiz,age:555

POST请求

选择POST。

在postman中输入

http://localhost:8080/commonParam

下面选择body,再选择x-www-form-urlencoded

再KEY和VALUE下分别添加:

name    faiz
age    555

点击send,运行结果为:

name:faiz,age:555

Post请求中文乱码处理:

  • 为web容器添加过滤器并指定字符集,Spring-web包中提供了专用的字符过滤器
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;import javax.servlet.Filter;public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {protected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}protected String[] getServletMappings() {return new String[]{"/"};}protected Class<?>[] getRootConfigClasses() {return new Class[0];}// 乱码处理@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");return new Filter[]{filter};}
}

普通参数

  • 普通参数:url地址传参,地址参数名与形参变量名相同,定义形参即可接收参数
  • 请求参数名与形参变量名不同,使用@RequestParam绑定参数关系
@Controller
//类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径
//@RequestMapping("/user")
public class UserController {//请求路径映射@RequestMapping("/commonParam")@ResponseBodypublic String commonParam(@RequestParam("name2") String name,int age) {System.out.println("name:"+name+",age:"+age);return "{'user':'common param'}";}}

POJO参数

  • POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数
package com.itheima.domain;public class User {String name;int age;public User(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}
package com.itheima.controller;import com.itheima.domain.User;
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("/commonParam")@ResponseBodypublic String commonParam(User user) {System.out.println("user:"+user);return "{'user':'common param'}";}}
http://localhost:8080/commonParam?name=faiz&age=555

运行结果为:

user:User{name='faiz', age=555}

嵌套POJO参数

  • 嵌套POJO参数:POJO对象中包含POJO对象
package com.itheima.domain;public class Address {String province;String city;public String getProvince() {return province;}public void setProvince(String province) {this.province = province;}public String getCity() {return city;}public void setCity(String city) {this.city = city;}@Overridepublic String toString() {return "Address{" +"province='" + province + '\'' +", city='" + city + '\'' +'}';}
}
package com.itheima.domain;public class User {String name;int age;Address address;public Address getAddress() {return address;}public void setAddress(Address address) {this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +", address=" + address +'}';}
}
  • 嵌套POJO参数:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数
package com.itheima.controller;import com.itheima.domain.User;
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("/commonParam")@ResponseBodypublic String commonParam(User user) {System.out.println("user:"+user);return "{'user':'common param'}";}}
http://localhost:8080/commonParam?name=faiz&age=555&address.city=sy&address.province=hn

运行结果为:

user:User{name='faiz', age=555, address=Address{province='hn', city='sy'}}

数组参数

  • 数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型形参即可接收参数
@Controller
public class UserController {//请求路径映射@RequestMapping("/param")@ResponseBodypublic String param(String[] names) {System.out.println("names:"+ Arrays.toString(names));return "{'user':'common param'}";}}
http://localhost:8080/param?names=faiz&names=wxm&names=tdzs

运行结果为

names:[faiz, wxm, tdzs]

集合保存普通参数

  • 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系
@Controller
public class UserController {//请求路径映射@RequestMapping("/param")@ResponseBodypublic String param(@RequestParam List<String> names) {System.out.println("names:"+ names);return "{'user':'common param'}";}}
http://localhost:8080/param?names=faiz&names=wxm&names=tdzs

运行结果为:

names:[faiz, wxm, tdzs]

接收请求中的json数据

  1. 添加json数据转换相关坐标
        <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.13.4</version></dependency>
  1. 设置发送json数据(请求body中添加json数据)

    再postman中选择Body,再选择raw,再选择JSON

  2. 开启自动转换json数据的支持

@Configuration
@ComponentScan("com.itheima.controller")
@EnableWebMvc  // 这里
public class SpringMvcConfig {
}
  1. 设置接收json数据
@Controller
public class UserController {//请求路径映射@RequestMapping("/param")@ResponseBodypublic String param(@RequestBody List<String> names) {System.out.println("names:"+ names);return "{'user':'common param'}";}}

在postman中输入

["aa","bb","cc","dd"]

点击send,结果为

names:[aa, bb, cc, dd]

@RequestBody与@RequestParam区别

  • 区别

    • @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】

    • @RequestBody用于接收json数据【application/json】

  • 应用

    • 后期开发中,发送json格式数据为主,@RequestBody应用较广

    • 如果发送非json格式数据,选用@RequestParam接收请求参数

日期类型参数传递

  • 日期类型数据基于系统不同格式也不尽相同

    • 2088-08-18

    • 2088/08/18

    • 08/18/2088

  • 接收形参时,根据不同的日期格式设置不同的接收方式

@Controller
public class UserController {//请求路径映射@RequestMapping("/param")@ResponseBodypublic String param(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:"+ date1);System.out.println("date2:"+ date2);return "{'user':'common param'}";}}
http://localhost:8080/param?date=2023/07/22&date1=2023-07-21&date2=2023/07/22 09:33:55

运行结果为:

date:Sat Jul 22 00:00:00 GMT+08:00 2023
date1:Fri Jul 21 00:00:00 GMT+08:00 2023
date2:Sat Jul 22 09:33:55 GMT+08:00 2023

响应

响应页面(了解)

@Controller
@RequestMapping("/book")
public class BookController {//请求路径映射@RequestMapping("index")public String index(){System.out.println("index");return "/book.jsp";}
}

响应文本数据(了解)

@Controller
@RequestMapping("/book")
public class BookController {@RequestMapping("text")@ResponseBodypublic String text(){System.out.println("text");return "Hello World";}
}

响应json数据(对象转json)

@Controller
@RequestMapping("/book")
public class BookController {//请求路径映射@RequestMapping("index")public String index(){System.out.println("index");return "/book.jsp";}@RequestMapping("text")@ResponseBodypublic String text(){System.out.println("text");return "Hello World";}@RequestMapping("pojo")@ResponseBodypublic User pojo(){User user = new User();user.setName("faiz");user.setAge(18);return user;}
}
http://localhost:8080/book/pojo

运行结果:

{"name": "faiz","age": 18,"address": null
}

响应json数据(对象集合转json数组)

@Controller
@RequestMapping("/book")
public class BookController {//请求路径映射@RequestMapping("list")@ResponseBodypublic List<User> list(){User user = new User();user.setName("faiz");user.setAge(18);User user2 = new User();user2.setName("faiz");user2.setAge(18);List<User> list = new ArrayList<>();list.add(user);list.add(user2);return list;}
}
http://localhost:8080/book/list

运行结果为:

[{"name": "faiz","age": 18,"address": null},{"name": "faiz","age": 18,"address": null}
]

名称:@ResponseBody

类型:方法注解

位置:SpringMVC控制器方法定义上方

作用:设置当前控制器返回值作为响应体

REST风格

REST简介

REST(Representational State Transfer),表现形式状态转换

  • 传统风格资源描述形式

    http://localhost/user/getById?id=1

    http://localhost/user/saveUser

  • REST风格描述形式

    http://localhost/user/1

    http://localhost/user

优点:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作

  • http://localhost/users 查询全部用户信息 GET(查询)
  • http://localhost/users/1 查询指定用户信息 GET(查询)
  • http://localhost/users 添加用户信息 POST(新增/保存)
  • http://localhost/users 修改用户信息 PUT(修改/更新)
  • http://localhost/users/1 删除用户信息 DELETE(删除)

根据REST风格对资源进行访问称为RESTful

RESTful入门案例

package com.itheima.controller;import com.itheima.domain.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;@Controller
public class UserController {//请求路径映射@RequestMapping(value = "/users",method = RequestMethod.POST)@ResponseBodypublic String save(){System.out.println("user save ...");return "{'module':'user save'}";}//请求路径映射@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id){System.out.println("user delete ..."+id);return "{'module':'user delete'}";}//请求路径映射@RequestMapping(value = "/users",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody User user){System.out.println("user update ..."+user);return "{'module':'user update'}";}//请求路径映射@RequestMapping(value = "/users/{id}",method = RequestMethod.GET)@ResponseBodypublic String getById(@PathVariable Integer id){System.out.println("user getById ..."+id);return "{'module':'user getById'}";}}

@RequestMapping

名称:@RequestMapping

类型:方法注解

位置:SpringMVC控制器方法定义上方

作用:设置当前控制器方法请求访问路径

属性

  • value(默认):请求访问路径
  • method:http请求动作,标准动作(GET/POST/PUT/DELETE)

@PathVariable

名称:@PathVariable

类型:形参注解

位置:SpringMVC控制器方法形参定义前面

作用:绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应

@RequestBody @RequestParam @PathVariable

  • 区别
    • @RequestParam用于接收url地址传参或表单传参
    • @RequestBody用于接收json数据
    • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数
  • 应用
    • 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数
    • 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值

REST快速开发

//@Controller
//@ResponseBody
@RestController
@RequestMapping("users")
public class UserController {//请求路径映射
//    @RequestMapping(method = RequestMethod.POST)@PostMappingpublic String save(){System.out.println("user save ...");return "{'module':'user save'}";}//请求路径映射
//    @RequestMapping(value = "/{id}",method = RequestMethod.DELETE)@DeleteMapping("/{id}")public String delete(@PathVariable Integer id){System.out.println("user delete ..."+id);return "{'module':'user delete'}";}//请求路径映射
//    @RequestMapping(method = RequestMethod.PUT)@PutMappingpublic String update(@RequestBody User user){System.out.println("user update ..."+user);return "{'module':'user update'}";}//请求路径映射
//    @RequestMapping(value = "/{id}",method = RequestMethod.GET)@GetMapping("/{id}")public String getById(@PathVariable Integer id){System.out.println("user getById ..."+id);return "{'module':'user getById'}";}}

@RestController

名称:@RestController

类型:类注解

位置:基于SpringMVC的RESTful开发控制器类定义上方

作用:设置当前控制器类为RESTful风格,等同于@Controller与@ResponseBody两个注解组合功能

@GetMapping @PostMapping @PutMapping @DeleteMapping

名称:@GetMapping @PostMapping @PutMapping @DeleteMapping

类型:方法注解

位置:基于SpringMVC的RESTful开发控制器方法定义上方

作用:设置当前控制器方法请求访问路径与请求动作,每种对应一个请求动作,例如@GetMapping对应GET请求

属性

  • value(默认):请求访问路径

设置对静态资源的访问放行

@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {//当访问/pages/????时候,走/pages目录下的内容registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
}

SSM整合

SSM整合

SSM整合流程

1.创建工程

2.SSM整合

  • Spring
    • SpringConfig
  • MyBatis
    • Mybatisconfig
    • JdbcConfig
    • jdbc.properties
  • SpringMVC
    • servletConfig
    • SpringMvcConfig

3.功能模块

  • 表与实体类
  • dao(接口+自动代理)
  • service(接口+实现类)
    • 业务层接口测试(整合JUnit )
  • controller
    • 表现层接口测试(PostMan )

表现层数据封装

表现层数据封装

  • 设置统一数据返回结果类
package org.example.controller;public class Result {private Object data;private Integer code;private String msg;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;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}
}

注意事项

Result类中的字段并不是固定的,可以根据需要自行增减提供若干个构造方法,方便操作

  • 设置统一数据返回结果编码
package org.example.controller;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;
}

注意事项
Code类的常量设计也不是固定的,可以根据需要自行增减,例如将查询再进行细分为GET_OK,GET_All_OK,GET_PAGE_OK

  • 根据情况设定合理的Result
package org.example.controller;import org.example.domain.Book;
import org.example.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 {@Autowiredprivate BookService bookService;@PostMappingpublic Result save(@RequestBody Book book) {boolean flag = bookService.save(book);return new Result(flag ? Code.SAVE_OK : Code.SAVE_ERR, flag);}@PutMappingpublic Result update(@RequestBody Book book) {boolean flag = bookService.update(book);return new Result(flag ? Code.UPDATE_OK : Code.UPDATE_ERR, flag);}@DeleteMapping("/{id}")public Result delete(@PathVariable Integer id) {boolean flag = bookService.delete(id);return new Result(flag ? Code.DELETE_OK : Code.DELETE_ERR, flag);}@GetMapping("/{id}")public Result getById(@PathVariable Integer id) {Book book = bookService.getById(id);Integer code = book != null ? Code.GET_OK : Code.GET_ERR;String msg = book != null ? "" : "数据查询失败,请重试";return new Result(code,book,msg);}@GetMappingpublic Result getAll() {List<Book> bookList = bookService.getAll();Integer code = bookList != null ? Code.GET_OK : Code.GET_ERR;String msg = bookList != null ? "" : "数据查询失败,请重试";return new Result(code,bookList,msg);}
}

异常处理器

出现异常现象的常见位置与常见诱因如下:

  • 框架内部抛出的异常:因使用不合规导致
  • 数据层抛出的异常:因外部服务器故障导致(例如:服务器访问超时)
  • 业务层抛出的异常:因业务逻辑书写错误导致(例如:遍历业务书写操作,导致索引异常等)
  • 表现层抛出的异常:因数据收集、校验等规则导致(例如:不匹配的数据类型间导致异常)
  • 工具类抛出的异常:因工具类书写不严谨不够健壮导致(例如:必要释放的连接长期未释放等)

各个层级均出现异常,异常处理代码书写在哪一层?

所有的异常均抛出到表现层进行处理

表现层处理异常,每个方法中单独书写,代码书写量巨大且意义不强,如何解决——AOP思想

异常处理器

集中的、统一的处理项目中出现的异常

在controller下新建一个类:

package org.example.controller;import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class ProjectExceptionAdvice {@ExceptionHandler(Exception.class)public Result doException(Exception e) {System.out.println("异常:"+e);return new Result(555,null,e.toString());}
}

项目异常处理方案

项目异常分类

  • 业务异常(BusinessException)
    • 规范的用户行为产生的异常
    • 不规范的用户行为操作产生的异常
  • 系统异常(SystemException)
    • 项目运行过程中可预计且无法避免的异常
  • 其他异常(Exception)
    • 编程人员未预期到的异常

项目异常处理方案

  • 业务异常(BusinessException)
    • 发送对应消息传递给用户,提醒规范操作
  • 系统异常(SystemException)
    • 发送固定消息传递给用户,安抚用户
    • 发送特定消息给运维人员,提醒维护
    • 记录日志
  • 其他异常(Exception)
    • 发送固定消息传递给用户,安抚用户
    • 发送特定消息给编程人员,提醒维护(纳入预期范围内)
    • 记录日志
  1. 自定义项目系统级异常
package org.example.exception;public class SystemException extends RuntimeException{private Integer code;public SystemException(String message, Integer code) {super(message);this.code = code;}public SystemException(String message, Throwable cause, Integer code) {super(message, cause);this.code = code;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}
}
  1. 自定义项目业务级异常
package org.example.exception;public class BusinessException extends RuntimeException{private Integer code;public BusinessException(String message, Integer code) {super(message);this.code = code;}public BusinessException(String message, Throwable cause, Integer code) {super(message, cause);this.code = code;}public Integer getCode() {return code;}public void setCode(Integer code) {this.code = code;}
}
  1. 自定义异常编码(持续补充)
package org.example.controller;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;public static final Integer BUSINESS_ERR = 60002;public static final Integer BUSINESS_UNKNOWN_ERR = 59999;public static final Integer SYSTEM_ERR = 50002;
}
  1. 触发自定义异常
package org.example.service.impl;import org.example.controller.Code;
import org.example.dao.BookDao;
import org.example.domain.Book;
import org.example.exception.BusinessException;
import org.example.exception.SystemException;
import org.example.service.BookService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class BookServiceImpl implements BookService {@Autowiredprivate BookDao bookDao;@Overridepublic boolean save(Book book) {bookDao.save(book);return true;}@Overridepublic boolean update(Book book) {bookDao.update(book);return true;}@Overridepublic boolean delete(Integer id) {bookDao.delete(id);return true;}// 这里@Overridepublic Book getById(Integer id) {// 将可能出现的异常进行包装,转换成自定义异常if (id == 0) {throw new BusinessException("请输入规范的id", Code.BUSINESS_ERR);}try {int i = 1/0;} catch (Exception e) {throw new SystemException("服务器访问超时,请重试",e,Code.SYSTEM_ERR);}return bookDao.getById(id);}@Overridepublic List<Book> getAll() {return bookDao.getAll();}
}
  1. 拦截并处理异常
package org.example.controller;import org.example.exception.BusinessException;
import org.example.exception.SystemException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class ProjectExceptionAdvice {@ExceptionHandler(SystemException.class)public Result doSystemException(SystemException e) {// 记录日志// 发送消息给运维// 发送邮件给开发人员,e对象发给return new Result(e.getCode(),null,e.getMessage());}@ExceptionHandler(BusinessException.class)public Result doSystemException(BusinessException e) {return new Result(e.getCode(),null,e.getMessage());}@ExceptionHandler(Exception.class)public Result doException(Exception e) {System.out.println("异常:"+e);return new Result(Code.BUSINESS_UNKNOWN_ERR,null,"系统繁忙,请稍后再试");}
}

拦截器

拦截器概念

拦截器(Interceptor )是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行

作用:

  • 在指定的方法调用前后执行预先设定后的的代码
  • 阻止原始方法的执行

拦截器与过滤器区别

  • 归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter对所有访问进行增强,Interceptor仅针对SpringMVC的访问进行增强

入门案例

  1. 声明拦截器的bean,并实现HandlerInterceptor接口(注意:扫描加载bean)
package org.example.controller.interceptor;import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;@Component
public class ProjectInceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("preHandle...");// false终止原始操作的执行return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}
}
  1. 定义配置类,继承WebMvcConfigurationSupport,实现addInterceptor方法(注意:扫描加载配置)
@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Overrideprotected void addInterceptors(InterceptorRegistry registry) {}
}
  1. 添加拦截器并设定拦截的访问路径,路径可以通过可变参数设置多个
package org.example.config;import org.example.controller.interceptor.ProjectInceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configuration
public class SpringMvcSupport extends WebMvcConfigurationSupport {@Autowiredprivate ProjectInceptor projectInceptor;@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}@Overrideprotected void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(projectInceptor).addPathPatterns("/books","/books/*");}
}
  • 使用标准接口webMvcConfigurer简化开发(注意:侵入式较强)
package org.example.config;import org.example.controller.interceptor.ProjectInceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
@ComponentScan({"org.example.controller"})
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {@Autowiredprivate ProjectInceptor projectInceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(projectInceptor).addPathPatterns("/books","/books/*");}}

拦截器执行流程

在这里插入图片描述

拦截器参数

前置处理

    @Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String contentType = request.getHeader("Content-Type");System.out.println("handler:"+handler+" handler.getClass():"+handler.getClass());HandlerMethod hm = (HandlerMethod) handler;System.out.println("preHandle..."+contentType);// false终止原始操作的执行return true;}

参数

  • request:请求对象
  • response:响应对象
  • handler:被调用的处理器对象,本质上是一个方法对象,对反射技术中的Method对象进行了再包装

返回值

  • 若返回值为false,被拦截的处理器将不执行

后置处理

    @Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("postHandle...");}

参数

  • modelAndView:如果处理器执行完成具有返回结果,可以读取到对应数据与页面信息,并进行调整

完成后处理

    @Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("afterCompletion...");}

参数

  • ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

拦截器链配置

多拦截器执行顺序

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序参照拦截器添加顺序为准
  • 当拦截器中出现对原始处理器的拦截,后面的拦截器均终止运行
  • 当拦截器运行中断,仅运行配置在前面的拦截器的afterCompletion操作

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/19365.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

忘记数据库密码如何处理

windows 5.6.51版本及以前 #当前账号设置密码 set password password(123456); #当前账号取消密码 set password ; &#xff08;1&#xff09;用管理员身份打开控制台输入 net stop m5&#xff08;我的电脑MySQL名字为m5&#xff0c;根据自己的更改&#xff09; &#xff08;…

maven下载安装及初次使用相关配置

maven下载按照及初次使用相关配置 一、下载 与安装 下载完解压放在文件夹中即可&#xff01; 依赖Java&#xff0c;需要配置JAVA_HOME设置MAVEN自身的运行环境&#xff0c;需要配置MAVEN_HOME&#xff08;参考安装java&#xff09;测试环境配置结果 MVN测试成功&#xff01…

Redis 高可用之持久化

目录 一、Redis 高可用 1.1 什么是高可用 1.2 Redis的高可用技术 二、Redis持久化 2.1 持久化的功能 2.2 Redis提供两种方式进行持久化&#xff1a; 三、RDB持久化 3.1 触发条件 &#xff08;1&#xff09;手动触发 &#xff08;2&#xff09;自动触发 &#xff08;3…

UG\NX 二次开发 选择相切面、相邻面的选择面控件

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan 简介&#xff1a; 有群友问“UFUN多选功能过滤面不能选择相切面或相邻面之类的吗&#xff1f;” 这个用Block UI的"面收集器"就可以&#xff0c;ufun函数是不行的。 效果&am…

12-4_Qt 5.9 C++开发指南_创建和使用共享库

文章目录 1. 创建共享库2. 使用共享库2.1 共享库的调用方式2.2 隐式链接调用共享库2.3 显式链接调用共享库 1. 创建共享库 除了静态库&#xff0c;Qt 还可以创建共享库&#xff0c;也就是 Windows 平台上的动态链接库。动态链接库项目编译后生成 DLL 文件&#xff0c;DLL 文件…

docker 保存和载入镜像

查看本机docker镜像 docker images保存镜像 docker save -o /home/space/work1/docker_qnx7.1.tar.gz a01ee6d74c36复制镜像到其他服务器 scp /home/space/work1/docker_qnx7.1.tar.gz XXXIP:/home/dell/work1/登录新 服务器操作 docker load -i docker_qnx7.1.tar.gz载入后…

网络安全/信息安全—学习笔记

一、网络安全是什么 网络安全可以基于攻击和防御视角来分类&#xff0c;我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术&#xff0c;而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 无论网络、Web、移动、桌面、云等哪个领域&#xff0c;都有攻与防两面…

MySQL 的解析器以及 MySQL8.0 做出的改进 | StoneDB技术分享 #2

设计&#xff1a;小艾 审核&#xff1a;丁奇 编辑&#xff1a;宇亭 作者&#xff1a;柳湛宇&#xff08;花名&#xff1a;乌淄&#xff09; 浙江大学-软件工程-在读硕士、StoneDB 内核研发实习生 一、MySQL 的解析器 MySQL 所使用的解析器&#xff08;即 Lexer 和 Parser …

【Git】git reset 版本回退 git rm

前言 在日常开发时&#xff0c;我们经常会需要撤销之前的一些修改内容或者回退到之前的某一个版本&#xff0c;这时候reset命令就派上用场了 git reset 用法1——所有文件回退到某个版本 1、使用git reflog查看要回退的commit对象 2、使用git reset [-- hard/soft /mixed] …

算法通关村第二关——反转链表白银笔记

文章目录 1.链表指定区间翻转2.两两交换链表中的节点 1.链表指定区间翻转 LeetCode 92.反转链表 解法一&#xff1a;头插法。利用虚拟节点进行反转&#xff0c;因为头节点有可能发生变化&#xff0c;比如 left1 那么需要 dummyNode.next 记录头结点&#xff0c;使用虚拟头节点…

Arcgis通过模型构建器计算几何坐标

模型 模型中&#xff0c;先添加字段&#xff0c;再计算字段 计算字段 模型的计算字段中&#xff0c;表达式是类似这样写的&#xff0c;其中Xmin表示X坐标&#xff0c;Ymin表示Y坐标 !Shape.extent.Xmin!类似计算面积 !shape.area!

突破游戏行业天花板,“技术外溢”成趋势

文 | 螳螂观察 作者 | 余一 受游戏版号发放的“放缓”、人口结构的调整&#xff0c;过去两年国内游戏行业过得并不算好。前不久据相关机构发布的数据显示&#xff0c;2022年中国游戏市场实际销售收入2658.84亿元&#xff0c;同比减少306.29亿元&#xff0c;下降10.33%。且游戏…

创建个人博客(在文章的列表页,根据文章标题和文章内容实现搜索)

1. 在视图文件增加搜索表单&#xff1a; 在文章列表页的视图文件中&#xff0c;增加一个搜索表单&#xff0c;包含一个文本搜索框和一个提交按钮 <% form_tag articles_path, method: :get do %><% text_field_tag :title, params[:title], placeholder: "搜索…

海康视频插件VideoWebPlugin在vue中的实现

一,将js文件放在public文件下 二,在index中全局引入 三.在视频页面写方法,创建实例,初始化,我写的是1*4屏的 <template><!--视频窗口展示--><div idplayWnd classNameplayWnd refplayWnd styleleft: 0; bottom: 0;height: 902px;width: 60vw></div>&…

Eureka 学习笔记2:EurekaClient

版本 awsVersion ‘1.11.277’ EurekaClient 接口实现了 LookupService 接口&#xff0c;拥有唯一的实现类 DiscoveryClient 类。 LookupService 接口提供以下功能&#xff1a; 获取注册表根据应用名称获取应用根据实例 id 获取实例信息 public interface LookupService<…

HTTP杂谈之Referer和Origin请求头再探

一 关于Referer和Origin的汇总 1) 知识是凌乱的,各位看官看个热闹即可2) 内容不断更新1、理解有盲区,需要及时纠正2、内容交叉有重复,需要适当删减3、扩展视野3) 以下内容都与Referer和Origin请求头有关联 nginx防盗链 HTTP杂谈之Referrer-Policy响应头 iframe标签referre…

物联网|可变参数的使用技巧|不一样的点灯实验|访问外设的寄存器|操作寄存器实现点灯|硬件编程的基本流程-学习笔记(11)

文章目录 可变参数的使用技巧第三阶段-初级实验Lesson5:不一样的点灯实验---学习I/O的输出 ☆点灯的电路图分析1 一起看看点灯的电路图Tip1:另一种点灯的电路Tip1:如何访问外设的寄存器2 STM32F407中操作GPIO的方法 通过直接操作寄存器实现点灯实验Tip1:硬件编程的基本流程 2代…

HTML5+CSS3小实例:带标题的3D多米诺人物卡片

实例:带标题的3D多米诺人物卡片 技术栈:HTML+CSS 效果: 源码: 【html】 <!DOCTYPE html> <html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"><meta name="viewport" content…

【信号去噪】基于马氏距离和EDF统计(IEE-TSP)的基于小波的多元信号去噪方法研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Linux 终端生成二维码

1、安装qrencode [rootnode1 script]# yum -y install qrencode2、输出正常的 [rootnode1 aihuidi]# echo https://blog.csdn.net/weixin_43822878?t1|qrencode -o - -t utf83、输出彩色的 [rootnode1 aihuidi]# qrencode -t utf8 -s 1 https://blog.csdn.net/weixin_4382…