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

news2024/9/23 5:20:48

一、引言

本篇内容是“异常统一处理”系列文章的重要组成部分,主要聚焦于对 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.coloradmin.cn/o/1440699.html

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

相关文章

Linux基础I/O(中)——重定向

重定向 根据上一篇的文章我们知道&#xff0c;文件描述符是什么。 0->stdin; 1->stdout; 2->stderr; 如果我们新打开一个文件的话&#xff0c;该文件描述符为3&#xff0c;如下图&#xff1a; &#xff1a;&#xff1a;“ 如果我先close(1),再打开一个文件,根据之前的…

for循环的多重跳出

for的多重跳出 1.前言2.标签使用3.使用异常的方式 本文在jdk17中测试通过 1.前言 前段时间面试时&#xff0c;面试官问我多重for循环如何跳出&#xff0c;我懵了&#xff0c;今天特别的研究了一下 本文主要说的不是continue与break&#xff0c;而是少用的另类操作 1.continue:…

三维可视化助力船舶制造:大数据处理、实时协作更高效!

随着科技的不断发展&#xff0c;船舶制造行业也在不断寻求创新和提高效率的途径。其中&#xff0c;HOOPS技术作为一种先进的三维可视化和工程协作技术&#xff0c;正逐渐成为船舶制造领域的关键工具。 本文将深入探讨HOOPS技术在船舶制造行业的应用&#xff0c;探讨其带来的优…

(2)llvm ir某些细节

&#xff08;1&#xff09;为什么需要llvm ir 也就是说&#xff0c;一个需求是解耦&#xff0c;一个需求是进行大家都需要的平台无关优化。 &#xff08;2&#xff09;llvm ir形式 &#xff08;3&#xff09;llvm结构 结构一个文件是module&#xff0c;里面可以有函数&#x…

基于YOLOv7算法和KITTI数据集的高精度实时车辆目标检测系统(PyTorch+Pyside6+YOLOv7)

摘要&#xff1a;基于YOLOv7算法和KITTI数据集的高精度实时车辆目标检测系统可用于日常生活中检测与定位行人&#xff08;Pedestrian&#xff09;、面包车&#xff08;Van&#xff09;、坐着的人&#xff08;Person Sitting&#xff09;、汽车&#xff08;Car&#xff09;、卡车…

PHPExcel导出excel

PHPExcel下载地址 https://gitee.com/mirrors/phpexcelhttps://github.com/PHPOffice/PHPExcel 下载后目录结构 需要的文件如下图所示 将上面的PHPExcel文件夹和PHPExcel.php复制到你需要的地方 这是一个简单的示例代码 <?php$dir dirname(__FILE__); //require_once …

低成本高利润:小区开店的最佳选择

作为一位在鲜奶吧行业摸爬滚打5年的创业者&#xff0c;我深知在小区内开店&#xff0c;选择什么项目能够实现低成本高利润。今天&#xff0c;我就为大家揭秘这个稳赚不亏的创业秘籍——鲜奶吧。 一、鲜奶吧&#xff1a;小区内的健康饮品专家 鲜奶吧以其新鲜、健康、营养的特点…

Java图形化界面编程——Container容器 笔记

2.3 Container容器 2.3.1 Container继承体系 Winow是可以独立存在的顶级窗口,默认使用BorderLayout管理其内部组件布局;Panel可以容纳其他组件&#xff0c;但不能独立存在&#xff0c;它必须内嵌其他容器中使用&#xff0c;默认使用FlowLayout管理其内部组件布局&#xff1b;S…

ZooKeeper安装及配置(Windows版)

步骤&#xff1a; 1.官网下载二进制版本ZooKeeper安装包。 2.解压到你要安装的目录下 3.配置 3.1进入目录 D:\Install\apache-zookeeper-3.9.1-bin 新增两个文件夹&#xff1a;data和log 3.2 进入目录D:\Install\apache-zookeeper-3.9.1-bin\conf 复制zoo_sample.cfg文件&a…

第二讲:数据结构 AcWing 826. 单链表

目录 数组模拟链表数组模拟单链表 单链表思路 && 代码 看图更好理解推荐一下y总的刷题网站 数组模拟链表 笔试的题目大部分 大部分涉及到链表都是十万级别的 用数组的方式创建链表速度很快&#xff0c;不会超时&#xff0c;而如果用new 一个结构体的话 大部分就是比较…

基于微信小程序的校园二手交易平台

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

在Linux系统中设置全局HTTP代理的步骤与技巧

在Linux系统中&#xff0c;设置全局HTTP代理可以方便我们统一管理和控制网络请求。这不仅可以帮助我们加速网络访问&#xff0c;还可以在某些情况下绕过网络限制或实现匿名上网。下面&#xff0c;我将为你详细介绍在Linux系统中设置全局HTTP代理的步骤与技巧。 步骤一&#xf…

SSM框架,Spring-ioc的学习(上)

知识点引入 关于框架 框架( Framework )是一个集成了基本结构、规范、设计模式、编程语言和程序库等基础组件的软件系统&#xff0c;它可以用来构建更高级别的应用程序。框架的设计和实现旨在解决特定领域中的常见问题&#xff0c;帮助开发人员更高效、更稳定地实现软件开发目…

wyh的迷宫

涉及知识点&#xff1a;求迷宫能否到达终点的&#xff0c;而不是求路径数的&#xff0c;用bfs时可以不用重置状态数组&#xff08;回溯&#xff09;。 题目描述 给你一个n*m的迷宫&#xff0c;这个迷宫中有以下几个标识&#xff1a; s代表起点 t代表终点 x代表障碍物 .代…

山西电力市场日前价格预测【2024-02-08】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2024-02-08&#xff09;山西电力市场全天平均日前电价为200.58元/MWh。其中&#xff0c;最高日前电价为347.58元/MWh&#xff0c;预计出现在07:00。最低日前电价为0.00元/MWh&#xff0c;预计出…

信息安全省赛杂项题解题思路

task1 直接查看文件属性即可得到 flag task2 载入 HxD 中&#xff0c;搜索 flag 即可得到 task3 也是同样的操作&#xff0c;载入 HxD 中搜索 flag task4 打开题目的压缩包发现被加密了&#xff0c;这个题目的标题提示的很明显&#xff0c;就是四位数加密 四位数加密的 zip…

爪哇部落算法组2024新生赛热身赛题解

第一题&#xff08;签到&#xff09;&#xff1a; 1、题意&#xff1a; 2、题解: 我们观察到happynewyear的长度是12个字符&#xff0c;我们直接从前往后遍历0到n - 12的位置&#xff08;这里索引从0开始&#xff09;&#xff0c;使用C的substr()函数找到以i开头的长度为12的字…

新增C++max函数的使用

在 C 中&#xff0c;max函数是标准库中的一个函数&#xff0c;用于返回两个或多个元素中的最大值。max函数的声明如下&#xff1a; cpp #include <algorithm>template<class T> const T& max(const T& a, const T& b);这个函数接受两个同类型的参数a…

Qt网络编程-写一个简单的网络调试助手

环境 Windows&#xff1a;Qt5.15.2&#xff08;VS2022&#xff09; Linux&#xff1a;Qt5.12.12&#xff08;gcc) 源代码 TCP服务器 头文件&#xff1a; #ifndef TCPSERVERWIDGET_H #define TCPSERVERWIDGET_H #include <QWidget> namespace Ui { class TCPServerW…

Java学习17-- super类

重点&#xff1a;super类 & 方法重写 super类 super指的是本级的上一级&#xff0c;即father class父类 很好理解&#xff0c;比如Person class>Student class 当前在Student class执行&#xff0c;那么就写this.xxx 需要在Student程序里面调用Person&#xff0c;那就…