SpringBoot HandlerMethodArgumentResolver接口自定义参数解析器

news2024/9/27 19:20:46

参考资料

  1. 【SpringBoot】HandlerMethodArgumentResolver的简单使用
  2. HandlerMethodArgumentResolver(参数解析器)的作用+使用小案例
  3. HandlerMethodArgumentResolver用于统一获取当前登录用户

目录

  • 一. 需求
  • 二. 前期准备
  • 三. 实现HandlerMethodArgumentResolver接口
  • 四. 将自定义的方法参数解析器放入配置类中
  • 五. Controller层接收数据
  • 六. 效果


一. 需求

现在项目有这样的一个需求,前端在请求头中传入userId,后端需要在controller中从请求头中获取该id,然后根据id查询用户的相关信息,并将信息封装到一个Map中

首先我们可以想到的就是将id传入到service层,然后在service层中进行数据库查询。

在service中进行操作的这种方式不够灵活,因此我们考虑:能否在类方法的参数上,自动的通过请求头中的id进行查询,然后将查询到的结果直接绑定到类方法的参数上呢?

Spring中提供了HandlerMethodArgumentResolver接口,我们可以实现该接口完成我们的需求。


二. 前期准备

⏹定义一个注解,用于标识请求头解析

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface HeaderAnalysis {
    
}

⏹定义前台HTML

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <button id="test">发送带自定义请求头的请求</button>
</div>
<script th:src="@{/js/public/jquery-3.6.0.min.js}"></script>
<script th:inline="javascript">

    $("#test").click(function() {
        
        // ⏹提交到后台的数据
        const param = {
            hobby: "睡觉",
            birthday: "2022/12/21",
        };

        $.ajax({
            url: "/test19/test",
            type: 'POST',
            data: JSON.stringify(param),
            contentType : 'application/json;charset=utf-8',
            // ⏹设置请求头
            beforeSend: function(xhr) {
                xhr.setRequestHeader("userId", "110");
            },
            dataType: 'json',
            success: function (data, status, xhr) {
                console.log(data);
            }
        });
    });
    
</script>
</body>
</html>

三. 实现HandlerMethodArgumentResolver接口

import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// ⏹自定义方法参数解析器实现HandlerMethodArgumentResolver接口
@Component
public class MyMethodArgumentResolver implements HandlerMethodArgumentResolver {

    // 模拟从数据库查询到的信息
    private static Map<String, List<String>> userInfoMap = new HashMap<String, List<String>>(){
        {
            put("110", Arrays.asList("jmw", "18"));
            put("120", Arrays.asList("fengyehong", "78"));
        }
    };

    // ⏹判断是否支持参数解析
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 🤔如果参数的类型为Map
        boolean result = parameter.getParameterType().isAssignableFrom(Map.class)
                // 🤔并且该参数还被自定义的HeaderAnalysis注解修饰的话
                && parameter.hasParameterAnnotation(HeaderAnalysis.class);

        // 只有满足了上面两个条件,该参数解析器才会起作用
        return result;
    }

    // ⏹如果支持参数解析的话,就进行参数解析
    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {

        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        // 🤔将一些默认的用户信息放入request的attribute中
        request.setAttribute("userInfoList", Arrays.asList("fengyehong", "29"));

        // 🤔获取请求头userId
        String userId = request.getHeader("userId");

        // 如果本次请求中不包含userId或者userId为非法id的话,则返回null
        if (ObjectUtils.isEmpty(userId) || !userInfoMap.containsKey(userId)) {
            return null;
        }

        // 模拟根据用户的id查询用户的信息,然后返回
        List<String> userList = userInfoMap.get(userId);
        return new HashMap<String, String>() {
            {
                put("userName", userList.get(0));
                put("userAge", userList.get(1));
            }
        };
    }
}

四. 将自定义的方法参数解析器放入配置类中

  • WebMvcConfigurer为Spring提供的配置接口
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;

@Configuration
public class InternationalConfig implements WebMvcConfigurer {
	
	// 注入自定义的方法参数解析器
    @Resource
    private MyMethodArgumentResolver myMethodArgumentResolver;

    // ⏹将自定义的方法参数解析器放入解析器列表中
    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(myMethodArgumentResolver);
    }
}

五. Controller层接收数据

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

@Controller
@RequestMapping("/test19")
public class Test19Controller {

    @GetMapping("/init")
    public ModelAndView init() {

        // 指定跳转的页面
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("test19");

        return modelAndView;
    }

    @PostMapping("/test")
    @ResponseBody
    public void getCacheValue(
            // 解析请求头得到的用户信息
            @HeaderAnalysis Map<String, String> userInfoMap,
            // ajax请求提交json到后台的数据
            @RequestBody Test19Form form,
            // HandlerMethodArgumentResolver接口的实现类中放入requestAttribute中的数据
            @RequestAttribute(value = "userInfoList", required = false) List<String> userInfoList,
            // 获取cookie中的key为JSESSIONID的数据
            @CookieValue(value = "JSESSIONID", required = false) String sessionId
    ) {

        System.out.println("解析请求头得到的用户信息: " + userInfoMap);
        System.out.println("ajax请求提交json到后台的数据: " + form);
        System.out.println("RequestAttribute的数据为: " + userInfoList);
        System.out.println("cookie中JSESSIONID的数据为: " + sessionId);
    }
}

六. 效果

在这里插入图片描述

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

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

相关文章

一套javassf门户网站管理系统源码分享

淘源码&#xff1a;国内专业的免费源码下载平台 JAVA SSF项目框架源码 后台管理系统源码 一套以SpringMVCSpringHibernateFreemarkerShiroLuceneHtml5jQuery为技术核心架构的门户网站管理系统源码。 源码免费分享&#xff0c;需要源码学习可私信我。 主要功能&#xff1a; 内…

笑对过往、活在当下、期盼未来

哈喽大家好&#xff0c;我是阿Q。 去年今日&#xff0c;也是安静的午后&#xff0c;拿起铅笔在纸上寥寥草草的写下几个年终关键词&#xff0c;思索良久&#xff0c;迟迟未能下笔。 时至今日&#xff0c;年末将至&#xff0c;再次执笔已时隔一年&#xff0c;再不拿笔记录这转瞬…

Python制作粒子烟花,程序员的跨年姿势

跨年倒计时还有半天&#xff1f;我已经开始整烟花了&#xff0c;虽然不是很好看吧&#xff0c;但是也能将就看看 &#x1f625; 这个的背景图&#xff0c;音乐&#xff0c;还有文字都是可以自己修改的哦 效果展示 依次导入本次需要使用到的模块 import random import pygame…

免费的JPEG 恢复软件 - 照片删除了怎么恢复?

照片删除了怎么恢复? 照片在我们的生活中起着至关重要的作用&#xff0c;因为它们可以承载我们的快乐回忆&#xff0c;记录我们的日常生活&#xff0c;分享我们的快乐等。我们将在智能手机、相机或计算机上拍摄并存储大量 JPEG 图片。但是&#xff0c;无论我们多么小心地保留它…

Python和MySQL对比(2):用Pandas 实现MySQL的 union 和 join 语法效果

文章目录一、前言二、语法对比数据表unionjoin1、两表 inner join2、两表 left join3、两表 right join4、两表 outer join5、多表 join三、小结一、前言 环境&#xff1a; windows11 64位 Python3.9 MySQL8 pandas1.4.2 本文主要介绍 MySQL 中的union和join如何使用pandas实现…

Spring 核心概念 IOC/DI IOC容器 Bean

目录 一&#xff1a;代码书写现状 二&#xff1a;核心思想 一&#xff1a;代码书写现状 常规操作如上,但存在着问题,将项目上线后&#xff0c;需要将数据层进行更换,更换如下&#xff1a; 数据层更换后&#xff0c;业务层也需要进行更换&#xff0c;更换如下&#xff1a; 数据…

NLP学习笔记(五) 注意力机制

大家好&#xff0c;我是半虹&#xff0c;这篇文章来讲注意力机制 (Attention Mechanism) 在序列到序列模型中的应用 在上一篇文章中&#xff0c;我们介绍了序列到序列模型&#xff0c;其工作流程可以概括为以下两个步骤 首先&#xff0c;用编码器将输入序列编码成上下文向量&a…

费控产品之易快报洞察解析

1.费控行业洞察 1.1 概念及管理范畴界定 费控业务的本质是企业支出的管理&#xff0c;因此分析费控要从企业支出管理的宏观范畴来看&#xff0c;企业支出主要包括两方面&#xff0c;一个是企业成本&#xff0c;一个是期间费用。期间费用就是我们常说的管理费用、销售费用和财务…

Centos7的安装与模板机的制作

Centos7的安装与模板机的制作 1.安装环境准备 1.VMware Workstation 2.centos7镜像 本文用的VMware版本为16.2.1 build-18811642 2.开始安装 话不多说&#xff0c;直接上图 3.模板机制作 1.查看防火墙的运行状态 firewall-cmd --state防火墙目前正在启动中 2.关闭防火墙…

STM32——STM32简介与创建工程

文章目录一、stm32简介stm32MCU&#xff1a;ARM&#xff1a;命名规则&#xff1a;片上资源/外设&#xff1a;系统结构&#xff1a;引脚的定义功能引脚介绍&#xff1a;最小系统引脚介绍&#xff1a;电源引脚介绍&#xff1a;启动配置最小系统电路二、软件安装三、新建工程固件库…

2022年专业408的算法题

文章目录0 结果1 题目2 思路3 实现3.1 思路13.2 思路二0 结果 1 题目 2 思路 1&#xff0c;首先明确二叉搜索树的定义&#xff1a;任何一个节点大于其左子树中的全部结点&#xff0c;小于其右子树中的全部结点。中序遍历二叉搜索树得到一个升序序列。2&#xff0c;明确题目中给…

【微信小程序入门到精通】— 微信小程序实现多页面切换(tabBar)

目录前言一、tabBar 介绍二、实操&#xff08;创建 tabBar &#xff09;2.1 基本配置2.2 详细配置总结前言 对于目前形式&#xff0c;微信小程序是一个热门&#xff0c;那么我们该如何去学习并且掌握之后去做实际项目呢&#xff1f; 为此我特意开设此专栏&#xff0c;在我学习的…

mysql索引机制实现及自适应hash索引

一、介绍   哈希&#xff08;hash&#xff09;是一种非常快的查找方法&#xff0c;一般情况下查找的时间复杂度为O&#xff08;1&#xff09;。常用于连接&#xff08;join&#xff09;操作&#xff0c;如Oracle中的哈希连接&#xff08;hash join&#xff09;。 InnoDB存储…

canopen11-sdo-40读取命令

源码 参考文件 1、SDO介绍 就对象而言,主机要访问节点词典的数据,因此主机是client客户端,节点是server服务器。上传与下载是对服务器来说的(这点和常识有点不太一样)。因此,上传指的是服务器发送数据给客户端,下载是客户端给服务器数据。 我们这里要用主机访问节点服…

Linux多进程编程之exec函数族使用

Linux多进程编程之exec函数族使用1.exec函数族是什么2.execl函数具体使用3.execlp4.exec后面不同字母所代表的含义1.exec函数族是什么 顾名思义&#xff0c;它并不只是一个函数&#xff0c;而是以exec开头的六个函数&#xff0c;并且是没有exec这个函数的&#xff08;就像TCP/…

几行代码演示linux kernel、libc、userSpace app的关系

问一&#xff1a;编译出来的Linux内核镜像(".\build\arch\arm64\boot\Image")&#xff0c;可以单独运行吗&#xff1f;答案是能&#xff0c;但是加载完就提示panic&#xff0c;然后死掉了。 原因是&#xff1a; 内核代码加载完后&#xff0c;一定要切换到低权限模式…

Wireshark TS | Packet Challenge 之 HTTP 案例分析

前言 来自于 Sharkfest Packet Challenge 中的一个数据包案例&#xff0c;Sharkfest 是 Wireshark 官方组织的一年一度的大会&#xff0c;致力于在 Wireshark 开发人员和用户社区之间分享知识、经验和最佳实践。印象中早期是一年一次&#xff0c;近几年发展成一年两次&#xf…

我的2022年终总结

目录 1 序 1 2 工作 1 3 业余 1 3.1 AI 1 3.2 数学小插曲 3 3.3 金融投资 3 4 生活 4 5 最后 4 1 序 老婆大人每年这个时候都要写年终总结&#xff0c;现在也正在写&#xff1b;CSDN也发起了年终征文活动&#xff1b;各大app也各种年度大数据总结。我好像还是第一次写年终总…

两两交换链表中的节点 -- 虚拟头节点

24两两交换链表中的节点 – 虚拟头节点 通过本题可以&#xff1a; 增加对虚拟头节点的理解。 加强对链表这一基本数据结构的基本操作的理解。 1. 交换过程&#xff1a; 如图&#xff0c;假设链表如图所示。 为了减少对头节点的单独讨论&#xff0c;这里采用虚拟头节点进行…

Allegro如何显示走线和铜皮的网络名操作指导

Allegro如何显示走线和铜皮的网络名操作指导 在做PCB设计的时候,如果可以实时看到走线和铜皮的网络名,对于设计有很大帮助,如下图 具体操作如下 选择Set-up-user preferences选择Display