异常统一处理:MissingServletRequestParameterException(遗漏Servlet请求参数异常)

一、引言

本篇内容是“异常统一处理”系列文章的重要组成部分,主要聚焦于对 MissingServletRequestParameterException 的原理解析与异常处理机制,并给出测试案例。

  • 关于 全局异常统一处理 的原理和完整实现逻辑,请参考文章:
    《SpringBoot 全局异常统一处理(AOP):@RestControllerAdvice + @ExceptionHandler + @ResponseStatus》
  • 本文仅详细解析 MissingServletRequestParameterException 的异常处理;其他类型异常的原理和处理方法,请参阅本文所在专栏内的其他文章。

二、异常原理

MissingServletRequestParameterException 是Spring MVC框架中处理HTTP请求时抛出的一种异常,它继承自ServletException,表示客户端的HTTP请求缺少了服务器端所期望的一个或多个必需参数

当一个控制器方法通过@RequestParam注解指定了某个参数是必需的(默认情况下就是必需的),而客户端在发起HTTP请求时未提供这个参数或提供的值为空时,服务器端Spring MVC在尝试将请求参数绑定到方法参数的过程中,就会抛出MissingServletRequestParameterException异常。

三、异常处理代码

在Spring Boot应用中,我们可以通过使用@ExceptionHandler注解来捕获并处理MissingServletRequestParameterException异常。这种异常会在请求参数缺失,且该参数被@RequestParam修饰且required = true时抛出。

3.1 异常处理示意图

异常处理核心代码的示例如下:

在这里插入图片描述

3.2 异常处理核心代码

异常处理策略的核心代码如下:

package com.example.core.advice;

import com.example.core.advice.util.UserTipGenerator;
import com.example.core.model.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.HandlerMethod;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 参数被 @RequestParam 修饰,且 required = true,则被修饰的参数为必传参数,不能为空;否则就会抛出异常 MissingServletRequestParameterException。
     * <p>
     * 若存在多个参数被@RequestParam注解修饰,并且设置required = true,则Spring MVC框架会按照参数在方法签名中声明的顺序逐一进行校验。
     * 一次异常只会包含一个参数的错误信息,而不是一次性列出所有缺失的必填参数。
     * <p>
     * 参数不传时,报错示例:
     * DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException:
     * Required request parameter 'name' for method parameter type String is not present]
     */
    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Result<String> handle(MissingServletRequestParameterException e, HandlerMethod handlerMethod) {
        String userMessage = UserTipGenerator.getUserMessage(e, handlerMethod);
        String errorMessage = String.format("MissingServletRequestParameterException(遗漏Servlet请求参数异常):%s", e.getMessage());
        return Result.fail(userMessage, String.valueOf(HttpStatus.BAD_REQUEST.value()), errorMessage);
    }

}

上述代码中,当出现MissingServletRequestParameterException异常时,系统将返回一个状态码为400(Bad Request)的结果,并附带具体的错误信息,包括未传递的必传参数名称以及错误原因,从而提供清晰的错误反馈。

3.3 获取参数的描述或字段名

在生成用户提示信息时,需要明确告知用户哪个参数未传,此时需要获取参数的描述。

  • 如果接口文档注解中有此参数的描述,则使用文档中的描述;
  • 如果接口文档注解中没有此参数的描述,则使用参数的字段名作为描述。
package com.example.core.advice.util;

import io.swagger.v3.oas.annotations.Parameter;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.method.HandlerMethod;

/**
 * 用户提示生成器。
 *
 * @author songguanxun
 * @since 2023-8-24
 */
public class UserTipGenerator {

    public static String getUserMessage(MissingServletRequestParameterException e, HandlerMethod handlerMethod) {
        String parameterDescription = getParameterDescription(e, handlerMethod);
        return String.format("%s,不能为空", parameterDescription);
    }

    /**
     * 获取参数的描述或字段名。
     * <p>
     * 如果接口文档注解中有此参数的描述,则使用文档中的描述;如果接口文档注解中没有描述,则使用参数的字段名作为描述。
     */
    private static String getParameterDescription(MissingServletRequestParameterException e, HandlerMethod handlerMethod) {
        String parameterName = e.getParameterName();

        Parameter[] annotationsByType = handlerMethod.getMethod().getAnnotationsByType(Parameter.class);
        for (Parameter parameter : annotationsByType) {
            String name = parameter.name();
            if (name != null && name.equals(parameterName)) {
                String description = parameter.description();
                if (StringUtils.hasText(description)) {
                    return description;
                }
            }
        }
        return parameterName;
    }

}

四、@RequestParam修饰多个必填参数

在Spring Boot应用中,对于控制器方法中的参数处理机制,若存在多个参数被@RequestParam注解修饰,并且设置required = true(表示这些参数是必需的),则Spring MVC框架会按照参数在方法签名中声明的顺序逐一进行校验。

具体来说,当接收到一个HTTP请求时,Spring MVC会从请求中获取相应的参数并尝试绑定到控制器方法的参数上。如果在这一过程中发现首个必填参数缺失(即未在请求中提供对应的值),框架将立即抛出MissingServletRequestParameterException异常,并停止对后续必填参数的校验。这意味着一次异常只会包含一个参数的错误信息,而不是一次性列出所有缺失的必填参数。

五、测试案例

5.1 测试代码

package com.example.web.exception.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("exception")
@Tag(name = "异常统一处理")
public class ExceptionController {

    /**
     * 参数被 @RequestParam 修饰,且 required = true(默认情况下就是 true),则此参数为必传参数,不能为空。
     * <p>
     * 参数不传时,报错示例:
     * DefaultHandlerExceptionResolver : Resolved [org.springframework.web.bind.MissingServletRequestParameterException:
     * Required request parameter 'name' for method parameter type String is not present]
     */
    @GetMapping("MissingServletRequestParameterException")
    @Operation(summary = "异常:MissingServletRequestParameterException")
    @Parameter(name = "name", description = "姓名", example = "张三")
    @Parameter(name = "mobilePhone", description = "手机号码", example = "18612345678")
    public String getByNameAndMobilePhone(@RequestParam String name, @RequestParam String mobilePhone) {
        log.info("name = {}, mobilePhone = {}", name, mobilePhone);
        return "请求成功";
    }

    /**
     * 参数被 @RequestParam 修饰,且 required = false,则此参数可以为空。
     */
    @GetMapping("MissingServletRequestParameterException/requiredEqualsFalse")
    @Operation(summary = "异常:MissingServletRequestParameterException,可以为空")
    @Parameter(name = "name", description = "姓名", example = "张三")
    public String getRequiredEqualsFalse(@RequestParam(required = false) String name) {
        log.info("name = {}", name);
        return "请求成功";
    }

    /**
     * 参数在接口文档注解中没有描述,则使用参数的字段名作为描述。
     */
    @GetMapping("MissingServletRequestParameterException/withoutParamDescription")
    @Operation(summary = "异常:MissingServletRequestParameterException,参数在接口文档注解中没有描述")
    @Parameter(name = "name", example = "张三")
    public String getWithoutParameterDescription(@RequestParam String name) {
        log.info("name = {}", name);
        return "请求成功";
    }

}


5.2 未处理时异常时的报错

  • 请求响应

在这里插入图片描述

  • 控制台的错误日志

在这里插入图片描述

5.3 测试结果

(1)一个必填参数未传

姓名参数,被@RequestParam注解修饰,且为必填参数(默认为必填);此时请求中未携带此参数,则会抛出异常。

异常处理后的返回结果如下:

在这里插入图片描述

(2)多个必填参数未传,按照参数顺序依次处理

多个参数被被@RequestParam注解修饰,并且设置required = true(表示这些参数是必需的),会按照参数在方法签名中声明的顺序逐一进行校验。

在示例接口中,请求中的姓名参数和手机号码参数都为空姓名参数在手机号码参数前面,所以会先校验姓名参数;当姓名参数未传时,会直接抛出异常,不会对后续必填参数继续进行校验。

在这里插入图片描述

当姓名参数已经传递,此参数就通过了校验,这时会继续向下校验手机号码参数;如果手机号码参数没传(为空),则会抛出异常,异常处理后的返回结果如下:

在这里插入图片描述

(3)@RequestParam(required = false):参数可以为空

在这里插入图片描述

(5)参数在接口文档注解中没有描述,则使用参数的字段名作为描述

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

缺省参数(c++)

void fun(int a0) { cout<<a<<endl; } 当我们调用函数时: fun(10) 输出10; fun&#xff08;&#xff09; 未传参时&#xff1a; 输出0; 未传参时a就会接受0&#xff0c;相当于这个0就是“备胎” 传参了0就没有用 全缺省 void fun2(int a10,int b3,int…

Python 3 中使用 pandas 和 Jupyter Notebook 进行数据分析和可视化

简介 Python 的 pandas 包用于数据操作和分析&#xff0c;旨在让您以直观的方式处理带标签或关联数据。 pandas 包提供了电子表格功能&#xff0c;但由于您正在使用 Python&#xff0c;因此它比传统的图形电子表格程序要快得多且更高效。 在本教程中&#xff0c;我们将介绍如…

第74讲Breadcrumb 面包屑实现

Breadcrumb 面包屑实现 为了实现二级路由&#xff0c;我们搞成搞个子路由&#xff0c;对于二级菜单 const routes [{path: /,name: 首页,component: () > import(../views/layout),redirect:/home,children:[{path: /home,name: 首页,component: () > import(../views…

《CSS 简易速速上手小册》第1章:CSS 基础入门(2024 最新版)

文章目录 1.1 CSS 语法和选择器&#xff1a;挑选你的画笔1.1.1 基础知识1.1.2 重点案例&#xff1a;创建一个响应式导航菜单1.1.3 拓展案例 1&#xff1a;为特定链接添加图标1.1.4 拓展案例 2&#xff1a;创建一个简单的问答折叠面板 1.2 盒模型的基础&#xff1a;构建你的乐高…

【RabbitMQ(二)】:Exchange 详解 | Message Convert 消息转换器

文章目录 03. 使用 Java 代码去操控 RabbitMQ3.1 快速入门3.1.1 创建父子项目3.1.2 编写代码 3.2 Work 模型3.3 RabbitMQ 中的三类交换机3.3.1 Fanout 扇出交换机3.3.2 Direct 交换机3.3.3 Topic 交换机 3.4 声明队列交换机3.4.1 方式一&#xff1a;书写 Config 类3.4.2 方式二…

【软件使用】【edge】如何让edge的某个网页作为应用安装

【背景】 有些常用网页希望用双击快捷方式的形式打开更加效率&#xff0c;我的浏览器主要是edge&#xff0c;研究了两种方法来实现这个需求。 【Edge自带方法】 点击Edge的右上角三点水-》应用-》将此站点作为应用安装。 点击安装&#xff0c;可以选择是否加到开始屏幕等。 …

Linux 从日志中抽取信息,批量生成SQL语句并执行

这里写目录标题 一. 需求分析二. 从日志中抽取出指定字段&#xff0c;并切分为若干个子文件三. 生成查询执行计划四. 生成查询的SQL语句五. 检查并执行 一. 需求分析 有如下日志文件&#xff0c;假设日志文件中有10000条数据&#xff0c;要求将全部的TRANSACTIONID抽取出来&am…

vue3 之 商城项目—二级分类

二级分类功能描述 配置二级路由 准备组件模版 <script setup></script><template><div class"container "><!-- 面包屑 --><div class"bread-container"><el-breadcrumb separator">"><el-bre…

python coding with ChatGPT 打卡第19天| 二叉树:合并二叉树

相关推荐 python coding with ChatGPT 打卡第12天| 二叉树&#xff1a;理论基础 python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历 python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历 python coding with ChatGPT 打卡第15天| 二叉树&#xff1a;翻转…

在虚拟机上完成Centos安装

Linux学习和使用 前言如何安装Centos初始化操作 使用VMware备份操作系统快照克隆 内容总结参考链接 本人介绍:2023年全国大学生数学建模竞赛国家二等奖,2022年蓝桥杯省二等奖,这里是一个和你一起不断努力,不断前进的程序猿一枚 前言 简单介绍一下本片文章将会讲到的内容:本章节…

关于创建vue项目报错command failed: npm install --loglevel error

一、首先 在这个目录下有个文件叫.vuerc 二、其次 进去之后把里面的"useTaobaoRegistry": false,修改下&#xff0c;我之前是true&#xff0c;后来改成了false才成功。

【大厂AI课学习笔记】【1.6 人工智能基础知识】(1)人工智能、机器学习、深度学习之间的关系

6.1 人工智能、机器学习与深度学习的关系 必须要掌握的内容&#xff1a; 如上图&#xff1a;人工智能>机器学习>深度学习。 机器学习是人工智能的一个分支&#xff0c;该领域的主要研究对象是人工智能&#xff0c;特别是如何在经验学习中改进具体算法的性能。 深度学习…

【MySQL进阶之路】生产案例:数据库无法连接,Too many connections

欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术的推送&#xff01; 在我后台回复 「资料」 可领取编程高频电子书&#xff01; 在我后台回复「面试」可领取硬核面试笔记&#xff01; 文章导读地址…

【leetcode】965. 单值二叉树

题目链接 965. 单值二叉树 bool isUnivalTree(struct TreeNode* root) {// if (root->left ! NULL && root->right ! NULL) {// return root->val root->left->val// && root->val root->right->val// && isUnivalTr…

算法学习——LeetCode力扣二叉树篇3

算法学习——LeetCode力扣二叉树篇3 116. 填充每个节点的下一个右侧节点指针 116. 填充每个节点的下一个右侧节点指针 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个 完美二叉树 &#xff0c;其所有叶子节点都在同一层&#xff0c;每个父节点都有两个子节点。二叉树…

【开源】JAVA+Vue.js实现衣物搭配系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 衣物档案模块2.2 衣物搭配模块2.3 衣物收藏模块 三、系统设计3.1 用例设计3.2 E-R图设计3.3 数据库设计3.3.1 衣物档案表3.3.2 衣物搭配表3.3.3 衣物收藏表 四、系统实现4.1 登录页4.2 衣物档案模块4.3 衣物搭配模块4.4…

C语言每日一题(54)对称二叉树

力扣网 101 对称二叉树 题目描述 给你一个二叉树的根节点 root &#xff0c; 检查它是否轴对称。 示例 1&#xff1a; 输入&#xff1a;root [1,2,2,3,4,4,3] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;root [1,2,2,null,3,null,3] 输出&#xff1a;false提…

国际物流数字化运输方式选择指南 | 箱讯科技

国际物流涉及多种运输方式&#xff0c;每种方式都有其独特的优势和适用场景。选择合适的运输方式对于确保货物安全、及时到达目的地并控制成本至关重要。以下是对六种主要国际运输方式的简要介绍和选择建议&#xff1a; 国际快递&#xff1a;适用于小件、高价值或急需的货物。…

游戏服务器租用价格表_TOP3费用对比

游戏服务器租用多少钱一年&#xff1f;1个月游戏服务器费用多少&#xff1f;阿里云游戏服务器26元1个月、腾讯云游戏服务器32元&#xff0c;华为云26元&#xff0c;游戏服务器配置从4核16G、4核32G、8核32G、16核64G等配置可选&#xff0c;游戏专业服务器公网带宽10M、12M、15M…

python+django人力资源管理系统7w5x3

技术栈 后端&#xff1a;python 前端&#xff1a;vue.jselementui 框架&#xff1a;django Python版本&#xff1a;python3.7 数据库&#xff1a;mysql5.7 数据库工具&#xff1a;Navicat 开发软件&#xff1a;PyCharm .设计框架&#xff1a;Vue 1. 表现层&#xff1a;写多…