SpringMVC学习(二)——RESTful API、拦截器、异常处理、数据类型转换
一、RESTful
(一)RESTful概述
RESTful是一种软件架构风格,用于设计网络应用程序。REST是“Representational State Transfer”的缩写,中文意思是“表现层状态转移”。它基于客户端-服务器模型和无状态操作,以及使用HTTP请求来处理数据。RESTful架构风格强调利用HTTP协议的四个主要方法(GET、POST、PUT、DELETE)来实现资源的访问和操作。以下是RESTful架构的一些核心原则:
客户端-服务器分离:客户端和服务器之间的交互应该是简单的,服务器端负责存储数据和业务逻辑,客户端负责展示。
无状态:每个请求从客户端到服务器必须包含所有必要的信息,以便服务器能够理解请求并独立地处理它,不依赖于之前的任何请求。
可缓存:数据被标记为可缓存或不可缓存。如果数据被标记为可缓存,那么客户端可以缓存数据以提高效率。
统一接口:系统组件之间的交互通过统一的接口进行,这简化了整体系统架构,使得系统更容易理解、开发和使用。
分层系统:客户端不能直接了解它所消费的服务之外的任何服务器信息,也不应该知道它的数据是来自一个服务器还是多个服务器。
按需代码(可选):服务器可以按需向客户端发送代码,比如JavaScript,以便在客户端执行。
在RESTful架构中,资源(Resources)是核心概念,每个资源都有一个唯一的标识符,通常是一个URI。客户端通过HTTP方法对这些资源进行操作:
GET:请求从服务器检索特定资源。GET请求应该是安全的,不会产生副作用。
POST:向服务器提交新的资源,通常会导致创建新的资源。
PUT:更新服务器上的现有资源。
DELETE:从服务器上删除资源。
RESTful API设计简洁、直观,易于理解和使用,因此在现代网络应用中非常流行

代码示例:
@CrossOrigin // 允许跨域请求
@RestController
@RequestMapping("/emp")
public class EmpController {@Autowiredprivate EmpService empService;/*** 查询员工*/@GetMapping("/{empno}")public R queryEmpById(@PathVariable("empno") Integer empno) {Emp emp = empService.queryById(empno);return R.ok(emp);}/*** 新增员工*/@PostMappingpublic R addEmp(@RequestBody Emp emp) {empService.save(emp);return R.ok();}/*** 修改员工*/@PutMappingpublic R editEmp(@RequestBody Emp emp) {empService.update(emp);return R.ok();}/*** 删除员工*/@DeleteMapping("/{empno}")public R deleteEmpById(@PathVariable("empno") Integer empno) {empService.deleteById(empno);return R.ok();}/*** 查询所有员工*/@GetMapping("/getAll")public R queryEmpList() {List<Emp> empList = empService.getList();return R.ok(empList);}
}
(二)@PathVariable:从URL中提取路径变量
@PathVariable是Spring MVC中用于从URL中提取路径变量的注解。它允许将URL模板中的占位符映射到方法参数,从而实现动态路由和数据传递。
使用场景:
- RESTful API:在设计RESTful API时,通常会使用@PathVariable来获取资源的唯一标识符(如 ID)。
- 动态内容:根据 URL 中的变量来动态生成页面或响应内容。
二、拦截器
(一)HandlerInterceptor
HandlerInterceptor是SpringMVC内置拦截器机制,用于在请求处理的不同阶段插入自定义逻辑。它允许在请求到达控制器之前、控制器处理请求之后以及请求完成之后执行特定的操作。比如:权限验证、日志记录、数据共享等......
使用步骤:
- 实现HandlerInterceptor接口的组件即可成为拦截器
- 创建WebMvcConfigurer组件,并配置拦截器的拦截路径
- 执行顺序:顺序preHandle→目标方法→倒序postHandle→渲染→倒序afterCompletion
- 只有执行成功的preHandle会倒序执行afterCompletion
- postHandle、afterCompletion从哪里跑出异常,倒序链路从哪里结束
- postHandle失败不会影响afterCompletion执行
@Component // 拦截器还需要配置(告诉SpringMVC,这个拦截器主要拦截什么请求)
public class MyHandlerInterceptor implements HandlerInterceptor {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println("MyHandlerInterceptor...preHandle...");return false; // true表示放行,false表示拦截}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println("MyHandlerInterceptor...postHandle...");}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println("MyHandlerInterceptor...afterCompletion...");}
}
@Configuration // 专门对SpringMVC底层进行配置
public class MySpringMVCConfig implements WebMvcConfigurer {@AutowiredMyHandlerInterceptor myHandlerInterceptor;/*** 添加拦截器*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(myHandlerInterceptor).addPathPatterns("/**"); // 拦截所有请求}
}
@CrossOrigin // 允许跨域请求
@RestController
@RequestMapping("/emp")
public class EmpController {@Autowiredprivate EmpService empService;/*** 查询员工*/@GetMapping("/{empno}")public R queryEmpById(@PathVariable("empno") Integer empno) {System.out.println("查询用户。目标方法执行......");Emp emp = empService.queryById(empno);return R.ok(emp);}
}
(二)拦截器与过滤器的区别(面试题)

三、异常处理
1.编程式异常处理
编程式异常处理:如果大量业务都需要加异常处理代码会很麻烦
@GetMapping("/hello")
public R hello(@RequestParam(value = "i", defaultValue = "0") Integer i) {try {int j = 10 / i;return R.ok(j);} catch (Exception e) {return R.error(100, "除数不能为0", e.getMessage());}
}

2.声明式异常处理
- 如果Controller本类出现异常,会自动在本类中找到有没有@ExceptionHandler标注的方法,如果有,执行这个方法,它的返回值,就是客户端收到的结果;如果发生异常,多个都能处理,就精确的优先。
- 异常处理的优先级:本类 > 全局;精确 > 模糊
- 如果出现了异常:本类和全局都不能处理,SpringBoot底层对SpringMVC有兜底处理机制:自适应处理(浏览器响应页面、移动端响应JSON)
- 最佳实践:编写全局异常处理器,处理所有异常
@RestController
public class HelloController {@GetMapping("/hello")public R hello(@RequestParam(value = "i", defaultValue = "0") Integer i) throws FileNotFoundException {int j = 10 / i;
// FileInputStream fileInputStream = new FileInputStream("C:\\Users\\lxm\\Desktop\\test.txt");String str = null;str.length();return R.ok(j);}@ExceptionHandler(ArithmeticException.class)public R handlerArithmeticException(ArithmeticException e) {System.out.println("ArithmeticException异常处理");return R.error(100, "除数不能为0", e.getMessage());}@ExceptionHandler(FileNotFoundException.class)public R FileNotFoundException(FileNotFoundException e) {System.out.println("FileNotFoundException异常处理");return R.error(300, "文件找不到", e.getMessage());}@ExceptionHandler(Throwable.class)public R handlerException(Throwable e) {System.out.println("Throwable异常处理");return R.error(500, "其他异常", e.getMessage());}
}
// @ResponseBody
// @ControllerAdvice // 告诉SpringMVC,这个类是处理全局异常的
@RestControllerAdvice // 全局异常处理器:相当于@ControllerAdvice + @ResponseBody
public class GlobalExceptionHandler {@ExceptionHandler(Exception.class)public R handleException(Throwable e) {System.out.println("全局异常处理");return R.error(500, e.getMessage());}@ExceptionHandler(ArithmeticException.class)public R handlerArithmeticException(ArithmeticException e) {System.out.println("算数异常处理");return R.error(100, e.getMessage());}
}
3.异常处理的最终方式
- 必须有业务异常类:BusinessException
- 必须有异常枚举类:BusinessExceptionEnum列举项目中每个模块将会出现的所有异常情况
- 编写业务代码的时候,只需编写正确逻辑,如果出现预期的问题,需要以抛异常的方式中断逻辑并通知上层
- 全局异常处理器:GlobalExceptionHandler 处理所有异常,返回给前端约定的JSON数据与错误码
异常枚举类:
public enum BusinessExceptionEnum {ORDER_NOT_EXIST(10001, "订单不存在"),ORDER_STATUS_ERROR(10002, "订单状态错误"),ORDER_UPDATE_ERROR(10003, "订单更新失败"),ORDER_DELETE_ERROR(10004, "订单删除失败"),ORDER_CREATE_ERROR(10005, "订单创建失败"),ORDER_QUERY_ERROR(10006, "订单查询失败"),ORDER_PAY_ERROR(10007, "订单支付失败"),ORDER_CANCEL_ERROR(10008, "订单取消失败");@Getterprivate Integer code;@Getterprivate String msg;BusinessExceptionEnum(Integer code, String msg) {this.code = code;this.msg = msg;}
}
全局业务异常类:
@Data
public class BusinessException extends RuntimeException {private Integer code;private String msg;public BusinessException(Integer code, String msg) {super(msg);this.code = code;this.msg = msg;}public BusinessException(BusinessExceptionEnum businessExceptionEnum) {super(businessExceptionEnum.getMsg());this.code = businessExceptionEnum.getCode();this.msg = businessExceptionEnum.getMsg();}
}
业务代码
@Override
public void update(Emp emp) {// 去数据库查询原来的值Integer empno = emp.getEmpno();if (empno == null) {throw new BusinessException(BusinessExceptionEnum.ORDER_NOT_EXIST);}Emp empById = empDao.getEmpById(empno);if (StringUtils.hasText(empById.getEname())) {empById.setEname(emp.getEname());}empDao.updateEmp(emp);
}
四、SpringMVC原理

五、数据类型转换
1.String转Date类型
@Controller
@RequestMapping("/book")
public class BookController {@GetMapping("/jump")public String jump(){// int i = 1/0;return "book/add";}@PostMapping("/doAdd")@ResponseBodypublic BookModel doAdd(BookModel book){return book;/*** {* "id": null,* "name": "红楼梦",* "ctime": 1735228800000* }*/}@PostMapping("/doAdd2")@ResponseBodypublic Date doAdd2(String name,@DateTimeFormat(pattern = "yyyy-MM-dd") Date ctime){return ctime; // 1735142400000}
}
@Data
public class BookModel {private Integer id;private String name;@DateTimeFormat(pattern = "yyyy-MM-dd")private Date ctime;
}
2.String转LocalDateTime类型
自定义参数类型转换器:
public class StringToDate implements Converter<String, Date> {@Overridepublic Date convert(String s) {//传入的参数,等待被转换的2024-12-27 字符串System.out.println(s);SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");Date date = null;try {date = simpleDateFormat.parse(s);} catch (ParseException e) {throw new RuntimeException(e);}return date;}
}public class StringToDateTime implements Converter<String, LocalDateTime> {@Overridepublic LocalDateTime convert(String s) {return LocalDateTime.parse(s, DateTimeFormatter.ISO_LOCAL_DATE_TIME);}
}
@Data
public class BookModel {private Integer id;private String name;
// @DateTimeFormat(pattern = "yyyy-MM-dd")private Date ctime;
// @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime utime;
}

3.接收JSON字符串
<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.11.2</version>
</dependency>
<dependency><groupId>com.fasterxml.jackson.datatype</groupId><artifactId>jackson-datatype-jsr310</artifactId><version>2.11.2</version>
</dependency>
/*** 接收JSON转换日期时间*/
@PostMapping("/doAdd3")
@ResponseBody
public BookModel doAdd3(@RequestBody BookModel book){return book;
}
@Data
public class BookModel {private Integer id;private String name;// @DateTimeFormat(pattern = "yyyy-MM-dd")private Date ctime;@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")private LocalDateTime utime;
}
注意:
JSON时间,可以写2024-01-27 09:09:09
不能写 2024-1-27 9:9:9
相关文章:
SpringMVC学习(二)——RESTful API、拦截器、异常处理、数据类型转换
一、RESTful (一)RESTful概述 RESTful是一种软件架构风格,用于设计网络应用程序。REST是“Representational State Transfer”的缩写,中文意思是“表现层状态转移”。它基于客户端-服务器模型和无状态操作,以及使用HTTP请求来处理数据。RES…...
React 第二十节 useRef 用途使用技巧注意事项详解
简述 useRef 用于操作不需要在视图上渲染的属性数据,用于访问真实的DOM节点,或者React组件的实例对象,允许直接操作DOM元素或者是组件; 写法 const inpRef useRef(params)参数: useRef(params),接收的 …...
VIVO Java开发面试题及参考答案
TCP 能不能两次握手? TCP 不能两次握手。 在 TCP 连接建立过程中,三次握手是必不可少的。第一次握手是客户端向服务器发送一个带有 SYN(同步序列号)标志的 TCP 报文段,这个报文段包含了客户端初始的序列号。这一步的主要目的是告诉服务器,客户端想要建立连接,并且让服务…...
C# Winfrom chart图 实例练习
代码太多了我就不展示了,贴一些比较有代表性的 成品效果展示: Excel转Chart示例 简单说一下我的思路 \ 先把Excel数据展示在dataGridView控件上 XLIST 为 X轴的数据 XLIST 为 Y轴的数据 ZLIST 为 展示的数据进行数据处理点击展示即可 // 将Excel数…...
iOS从Matter的设备认证证书中获取VID和PID
设备认证证书也叫 DAC, 相当于每个已经认证的设备的标识。包含了 VID 和 PID. VID: Vendor ID ,标识厂商 PID: Product ID, 标识设备的 根据 Matter 对于设备证书的规定,DAC证书subject应该包含VID 和 PID. 可通过解析 X509 证书读取subject…...
带着国标充电器出国怎么办? 适配器模式(Adapter Pattern)
适配器模式(Adapter Pattern) 适配器模式适配器模式(Adapter Pattern)概述talk is cheap, show you my code总结 适配器模式 适配器模式(Adapter Pattern)是面向对象软件设计中的一种结构型设计…...
破解海外业务困局:新加坡服务器托管与跨境组网策略
在当今全球化商业蓬勃发展的浪潮之下,众多企业将目光投向海外市场,力求拓展业务版图、抢占发展先机。而新加坡,凭借其卓越的地理位置、强劲的经济发展态势以及高度国际化的营商环境,已然成为企业海外布局的热门之选。此时…...
Mybatis-Plus快速入门
参考:黑马MyBatisPlus教程全套视频教程,快速精通mybatisplus框架 1.Mapper-plus配置 1.MapperScan("Mapper目录的位置") 2.Mapper层文件需要继承BaseMapper extends BaseMapper<实体类> 3.开启日志 4.配置类 Configuration public cl…...
Chrome被360导航篡改了怎么改回来?
一、Chrome被360导航篡改了怎么改回来? 查看是否被360主页锁定,地址栏输入chrome://version,看命令行end后面(蓝色部分),是否有https://hao.360.com/?srclm&lsn31c42a959f 修改步骤 第一步:…...
Coding(Jenkinsfile)+ Docker 自动化部署 Springboot —— 图文细节和一些注意事项说明
前言:本章讲述一下我使用Coding(Jenkinsfile) Docker部署Springboot项目过程,记录图文细节和一些需要注意的问题。 说明:为什么要使用Coding去集成Docker? 节约了服务器内存,不需要单独部署 Jen…...
docker django uwsgi 报错记录
这个配置中是能够正常进行网页访问的,能够查看网页 [uwsgi] chdir /home/luichun/lc/Pyfile/PyCursor/app module app.wsgi:application plugin-dir /usr/lib/uwsgi/plugins plugins python311 env TZAsia/Shanghai socket-timeout 60 websocket-ma…...
数据分析思维(五):分析方法——假设检验分析方法
数据分析并非只是简单的数据分析工具三板斧——Excel、SQL、Python,更重要的是数据分析思维。没有数据分析思维和业务知识,就算拿到一堆数据,也不知道如何下手。 推荐书本《数据分析思维——分析方法和业务知识》,本文内容就是提取…...
【ES6复习笔记】集合Set(13)
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了iterator接口,所以可以使用『扩展运算符』和『for…of…』进行遍历。 集合的属性和方法 size:返回集合的元素个数。add…...
基础爬虫案例实战
我们已经学习了多进程、requests、正则表达式的基本用法,但还没有完整地实现过一个爬取案例。这一节,我们就来实现一个完整的网站爬虫,把前面学习的知识点串联起来,同时加深对这些知识点的理解。 准备工作 我们需要先做好如下准备工作。 安…...
深度学习工作:从追求 SoTA 到揭示新现象
TLDR:主要讨论了从追求模型 SoTA 到揭示新现象的转变。通过几个例子,包括ACNet到RepVGG的发展,RIFE插帧、Film插帧,以及OpenAI的近期工作,阐述了这种转变的重要性。 知乎:黄哲威 hzwer链接:http…...
学习记录—正则表达式-基本语法
正则表达式简介-《菜鸟教程》 正则表达式是一种用于匹配和操作文本的强大工具,它是由一系列字符和特殊字符组成的模式,用于描述要匹配的文本模式。 正则表达式可以在文本中查找、替换、提取和验证特定的模式。 本期内容将介绍普通字符,特殊…...
智慧农业物联网传感器:开启农业新时代
在当今科技飞速发展的时代,农业领域正经历着一场前所未有的变革,而智慧农业物联网传感器无疑是这场变革中的关键利器。它宛如农业的 “智慧大脑”,悄然渗透到农业生产的各个环节,为传统农业注入了全新的活力,让农业生产…...
普通人怎么入门学习并使用AI?
前言 作为普通人看着AI一天一天变革,心急如焚,未来但是就是不知道怎么才算真正进入了AI,使用AI....作为从头至尾追随AI脚步的码农有几点小建议~ 一、💻使用 AI 网站或软件,解决实际问题 不管用哪种AI,先用…...
Java中处理if-else的几种高级方法
前言 在我看来多写几个if-else没啥大不了的,但是就是看起来没啥逼格,领导嫌弃。我根据开发的经历写几个不同的替代方法 一、枚举法替代 我先前写了一篇文章,可以去看看。 通过枚举替换if-else语句的解决方案_枚举代替if else c语言-CSDN博…...
前端知识补充—CSS
CSS介绍 什么是CSS CSS(Cascading Style Sheet),层叠样式表, ⽤于控制⻚⾯的样式 CSS 能够对⽹⻚中元素位置的排版进⾏像素级精确控制, 实现美化⻚⾯的效果. 能够做到⻚⾯的样式和结构分离 基本语法规范 选择器 {⼀条/N条声明} 1)选择器决定针对谁修改…...
AI仿真人剧服务商2025推荐,前沿技术与创新体验结合
AI仿真人剧服务商2025推荐,前沿技术与创新体验结合随着科技的不断进步,AI仿真人剧服务在2025年迎来了爆发式增长。越来越多的企业和个人开始关注这一领域,希望通过AI技术实现更高效、更高质量的内容创作。本文将为大家推荐一家在2025年表现卓…...
【APS合集】20余份APS生产排成系统及与其他系统集成方案合集(PPT+WORD)
本方案面向“十五五”构建以约束优化算法为核心的APS智能排程系统,通过集成ERP、MES、SCADA及WMS,实现计划-执行闭环联动。旨在解决人工排产低效、资源冲突频发等痛点,支持分钟级动态重排与交期精准承诺,显著提升设备利用率与订单…...
基于Matlab的轴承-空心转轴-飞轮不同耦合类型动力学分析
基于Matlab的轴承-空心转轴-飞轮不同耦合类型动力学分析 保持轴承类型不变,变换飞轮和转轴耦合方式,分固有频率的变化趋势 可自行定义轴承、飞轮、转轴参数 程序高度模块化,修改十分方便 程序已调通,可直接运行最近做了一个关于轴…...
2026年脱模油供应商怎么选?这几点很关键
2026年,建筑行业持续发展,脱模油作为建筑施工中不可或缺的材料,其质量和适用性至关重要。关云建材在脱模油领域深耕多年,积累了丰富的行业经验。接下来,我们就来深入探讨脱模油的相关问题,帮助大家选到合适…...
AI 编程盛行的时代,为什么 “『DC- WFW』” 仍然具有必要性?
AI训练存储选型的演进路线 第一阶段:单机直连时代 早期的深度学习数据集较小,模型训练通常在单台服务器或单张GPU卡上完成。此时直接将数据存储在训练机器的本地NVMe SSD/HDD上。 其优势在于IO延迟最低,吞吐量极高,也就是“数据离…...
基于python的本地选择图像接入百度云api的图像识别项目
项目灵感来源于老师布置的任务。怎么感觉老师这个题目也是ai生成的~。~ 题目:基于 AI 视觉的本地图像分析脚本 任务要求: 请使用 Python 编写一个通用的图像分析脚本,具体流程需满足以下三个步骤: * 本地选图:程序运…...
如何让AI读懂古文?GuwenBERT带来的古典汉语处理革命
如何让AI读懂古文?GuwenBERT带来的古典汉语处理革命 【免费下载链接】guwenbert GuwenBERT: 古文预训练语言模型(古文BERT) A Pre-trained Language Model for Classical Chinese (Literary Chinese) 项目地址: https://gitcode.com/gh_mir…...
Anthropic一夜震撼升级:Claude获得「永久在线」,全球打工人变天
文章目录一、凌晨三点,你的电脑自己在加班二、从"睡美人"到"永动机":AI的觉醒之路1. 独立生存空间:专属侧边栏UI2. Webhook唤醒:AI开始自主感知世界3. 浏览器直连:深度集成Chrome三、CoworkConway…...
markdown基础语法及效果演示
[toc] 自动生成目录 文章目录标题二级标题# 标题 一级标题 标题 - 无序列表 无序列表无序列表 # 二级标题 二级标题 代码块: python print(“hello world!”) #代码块 print("hello world!") #代码块>引用 引用 >>二级引用 二级引用 - […...
史上最快破 10 万 Star!Claude Code Python 重写版震撼上线!
文章目录 📖 介绍 📖 🏡 演示环境 🏡 📒 史上最快10万Star项目 📒 📝 事件始末 🔧 项目架构 🗂️ 目录结构 ⭐ Rust工作区模块 🚀 快速开始 📦 Python版 🦀 Rust版 💡 核心特色 🎯 清洁室重写 🔄 AI辅助开发 📊 Rust性能优化 🌟 项目影响力 …...
