Spring Boot项目中不使用@RequestMapping相关注解,如何动态发布自定义URL路径

一、前言

在Spring Boot项目开发过程中,对于接口API发布URL访问路径,一般都是在类上标识@RestController或者@Controller注解,然后在方法上标识@RequestMapping相关注解,比如:@PostMapping@GetMapping注解,通过设置注解属性,发布URL。在某些场景下,我觉得这样发布URL太麻烦了,不适用,有没有什么其他方法自由发布定义的接口呢?答案是肯定的。

二、一般开发流程

按照上面的描述,我们先看一下一般常用的开发代码:

import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class TestController {

    @RequestMapping("/test/url")
    public String test(@RequestParam String name, @RequestBody Map<String, Object> map) { // 这里只是方便测试,实际情况下,请勿使用Map作为参数接收
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("hello, ").append(name).append(", receive param:");
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            stringBuilder.append("\n").append("key: ").append(entry.getKey()).append("--> value: ").append(entry.getValue());
        }
        return stringBuilder.toString();
    }

}

测试效果:

在这里插入图片描述

三、自定义URL发布逻辑

参考步骤二的测试截图效果,我们自定义发布一个URL。

1. 新建一个spring boot项目,导入相关依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

2. 修改Controller实现类代码

去掉@RestController@RequestMapping相关注解,示例代码如下:

import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Map;

// @RestController
@Component
public class TestController {

    //@RequestMapping("/test/url")
    @ResponseBody  // 注意:此注解需要添加,不能少
    public String test(/*@RequestParam*/ String name,/* @RequestBody*/ Map<String, Object> map) { // 这里只是方便测试,实际情况下,请勿使用Map作为参数接收
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("hello, ").append(name).append(", receive param:");
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            stringBuilder.append("\n").append("key: ").append(entry.getKey()).append("--> value: ").append(entry.getValue());
        }
        return stringBuilder.toString();
    }

}

3. 自定义一个事件监听,实现URL发布功能

参考代码如下:

import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 注册一个web容器初始化以后的事件监听,注册自定义URL
 */
@Component
public class CustomRegisterUrl implements ApplicationListener<WebServerInitializedEvent> {
    /**
     * 标识事件监听器是否已经注册,避免重复注册
     */
    private volatile AtomicBoolean flag = new AtomicBoolean(false);

    /**
     * 需要发布的地址
     */
    public static final String CUSTOM_URL = "/test/url";

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;


    @Autowired
    private TestController testController;

    @SneakyThrows
    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        if (flag.compareAndSet(false, true)) {
            // 构建请求映射对象
            RequestMappingInfo requestMappingInfo = RequestMappingInfo
                    .paths(CUSTOM_URL) // 请求URL
                    .methods(RequestMethod.POST, RequestMethod.GET) // 请求方法,可以指定多个
                    .build();
            // 发布url,同时指定执行该请求url的具体类变量的的具体方法
            requestMappingHandlerMapping.registerMapping(requestMappingInfo, testController, testController.getClass().getMethod("test", String.class, Map.class));
        }
    }
}

4. 测试效果

同样请求:http://localhost:8080/test/url?name=jack

在这里插入图片描述

可以看到,此时请求效果并不是正常的,存在参数丢失,怎么办呢?

注意:如果请求出现如下错误:

java.lang.IllegalArgumentException: Expected lookupPath in request attribute "org.springframework.web.util.UrlPathHelper.PATH".

可以在application.yaml文件中添加如下内容:

spring:
  mvc:
    pathmatch:
      matching-strategy: ant_path_matcher

5. 增加统一请求处理器

为了实现参数可以正常解析,同时方便增加自定义处理逻辑,我们可以增加一个统一的请求处理器,参考示例:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Map;

@Component
public class CustomHandlerUrl {

    public static final Method HANDLE_CUSTOM_URL_METHOD;

    private static final ObjectMapper OBJECTMAPPER = new ObjectMapper();

    @Autowired
    private TestController testController;

    static {
        // 提前准备好参数对象
        Method tempMethod = null;
        try {
            tempMethod = CustomHandlerUrl.class.getMethod("handlerCustomUrl", HttpServletRequest.class, HttpServletResponse.class);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        HANDLE_CUSTOM_URL_METHOD = tempMethod;
    }

    @ResponseBody
    /**
     *  拦截自定义请求的url,可以做成统一的处理器,这里我只做简单实现,专门处理test
     */
    public Object handlerCustomUrl(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 获取参数 get方式请求参数
        String name = request.getParameter("name");
        // 获取 post方式请求参数
        Map<String, Object> map = OBJECTMAPPER.readValue(request.getInputStream(), Map.class);

        // 执行业务方法
        String result = testController.test(name, map);
        return result;

    }
}

6. 修改事件监听逻辑

修改事件监听逻辑,此时注册URL时,绑定统一处理器就行了。

示例代码:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 注册一个web容器初始化以后的事件监听,注册自定义URL
 */
@Component
public class CustomRegisterUrl implements ApplicationListener<WebServerInitializedEvent> {
    /**
     * 标识事件监听器是否已经注册,避免重复注册
     */
    private volatile AtomicBoolean flag = new AtomicBoolean(false);

    /**
     * 需要发布的地址
     */
    public static final String CUSTOM_URL = "/test/url";

    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    @Autowired
    private CustomHandlerUrl customHandlerUrl;


    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        if (flag.compareAndSet(false, true)) {
            // 构建请求映射对象
            RequestMappingInfo requestMappingInfo = RequestMappingInfo
                    .paths(CUSTOM_URL) // 请求URL
                    .methods(RequestMethod.POST, RequestMethod.GET) // 请求方法,可以指定多个
                    .build();
            // 发布url,指定一下url的处理器
            requestMappingHandlerMapping.registerMapping(requestMappingInfo, customHandlerUrl, CustomHandlerUrl.HANDLE_CUSTOM_URL_METHOD);
        }
    }
}

7. 重新测试

在这里插入图片描述

此时,请求可以发现,效果和使用@RestController+@RequestMapping注解就一样了。

四、写在最后

自定义发布URL路径一般情况下很少使用,不过针对特殊url的处理,以及自定义rpc框架发布url时,选择这样处理好了,可以达到出其不意的效果。

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

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

相关文章

Java项目:30 基于SpringBoot自习室座位预定系统

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 功能设计 管理员 1、用户管理 管理员可以新增、删除管理员 管理员可以删除学生 2、自习室管理 管理员可以新增自习室、设置自习室的座位…

关于福彩历史数据采集器和体彩历史数据采集器的下载安装说明

前段时间因为研究基于人工神经网络&#xff08;深度学习&#xff0c;所谓的“AI”算法&#xff09;对3D开奖数据进行预测&#xff0c;开发了两款浏览器插件----“福彩历史数据采集器”和“体彩历史数据采集器”。之所以开发这两款插件&#xff0c;是因为不管是基于什么样的方式…

机器学习:集成学习(Python)

一、Adaboost算法 1.1 Adaboost分类算法 adaboost_discrete_c.py import numpy as np import copy from ch4.decision_tree_C import DecisionTreeClassifierclass AdaBoostClassifier:"""adaboost分类算法&#xff1a;既可以做二分类、也可以做多分类&#…

缓存相关问题:雪崩、穿透、预热、更新、降级的深度解析

✨✨祝屏幕前的小伙伴们每天都有好运相伴左右✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 引言 1. 缓存雪崩 1.1 问题描述 1.2 解决方案 1.2.1 加锁防止并发重建缓存 2. 缓存穿透 2.1 问题描述 2.2 解决方案 2.2.1 …

Ubuntu下安装Scala

前言 弄了一下终于成功装上了&#xff0c;这里对此进行一下总结 安装虚拟机 VMware虚拟机安装Ubuntu&#xff08;超详细图文教程&#xff09;_vmware安装ubuntu-CSDN博客https://blog.csdn.net/qq_43374681/article/details/129248167Download Ubuntu Desktop | Download | …

FinalShell连接Linux

远程连接linux 我们使用VMware可以得到Linux虚拟机&#xff0c;但是在/Mware中操作Linux的命令行页面不太方便&#xff0c;主要是: 内容的复制、粘贴跨越VMware不方便 文件的上传、下载跨越VMware不方便 不方便也就是和Linux系统的各类交互&#xff0c;跨越VMwar 到Linux操作系…

win11 更多网络适配器选项

win11更多网络适配器选项查找路径&#xff1a;控制面板→网络和共享中心→更改适配器设置

计算机二级Python刷题笔记------基本操作题23、33、35、37(考察字符串)

文章目录 第二十三题&#xff08;字符串替换&#xff1a;replace(old,new)&#xff09;第三十三题&#xff08;字符串遍历&#xff09;第三十五题&#xff08;字符串与列表&#xff09;第三十七题&#xff08;拼接字符串&#xff09; 第二十三题&#xff08;字符串替换&#xf…

Ubuntu进入python时报错:找不到命令 “python”,“python3” 命令来自 Debian 软件包 python3

一、错误描述 二、解决办法 进入”/usr/bin”目录下&#xff0c;查看/usr/bin目录中所有与python相关的文件和链接&#xff1a; cd /usr/bin ls -l | grep python 可以看到Python3指向的是Python3.10&#xff0c;而并无指向python3的软连接 只需要在python与python3之间手动…

2024.03.02蓝桥云课笔记

1.scanf与printf取消分隔符的限制方法 示例代码&#xff1a; int main() { char s[10];scanf("%d[^\n]",s);printf("%s",s);return 0; } 运行&#xff1a; 输入&#xff1a;Hello World 输出&#xff1a;Hello World 注&#xff1a;其中[]中是一个正则…

YTM32的同步串行通信外设SPI外设详解(Master Part)

YTM32的同步串行通信外设SPI外设详解&#xff08;Master Part&#xff09; 文章目录 YTM32的同步串行通信外设SPI外设详解&#xff08;Master Part&#xff09;IntroductionFeatures引脚信号时钟源其它不常用功能 Pricinple & Mechinism基于FIFO的命令和数据管理机制锁定配…

19. 学习人工智能如何从阅读论文中获取一手信息,并推荐一些技术论文

本文为 「茶桁的 AI 秘籍 - BI 篇 第 19 篇」 文章目录 Hi&#xff0c;你好。我是茶桁。 上节课给大家预告了&#xff0c;今天这节课咱们来看一篇论文。我们之前几节课中讲解的内容其实是在一些论文里面有使用到的。 我们先看一下论文的内容&#xff0c;讲讲 ALS。 就像我上节…

unsubscribe:Angular 项目中常见场景以及是否需要 unsubscribe

本文由庄汇晔同学编写~ 在 Angular 项目中&#xff0c;经常会使用到 observable subscribe&#xff0c;但是 subscribe 读取了数据之后&#xff0c;真的就是万事大吉了吗&#xff1f;这个问题的答案或许是&#xff0c;或许不是。有些 observable 需要 unsubscribe&#xff0c;…

【研发日记】Matlab/Simulink技能解锁(四)——在Simulink Debugger窗口调试

前言 见《【研发日记】Matlab/Simulink技能解锁(一)——在Simulink编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(二)——在Function编辑窗口Debug》 见《【研发日记】Matlab/Simulink技能解锁(三)——在Stateflow编辑窗口Debug》 Block断点 前文在Simulink编辑窗口…

嵌入式Linux中GPIO设置的一些基本指令和步骤

一、GPIO的介绍 嵌入式Linux中的GPIO&#xff08;General Purpose Input/Output&#xff0c;通用输入/输出&#xff09;是一种常用的接口&#xff0c;允许开发者直接控制硬件设备的某些引脚&#xff0c;进行诸如LED控制、传感器读取、设备状态监测等任务。 二、设置步骤和示例…

雷电将军部分技能AOE范围测试

简单说一下&#xff0c;以往的AOE范围数据大部分来自Dim提供的拆包文件或泄露的GM端控制台显示的距离数据&#xff0c;如《AOE范围学》中的数据&#xff0c;然而米哈游自1.6版本及以后未再公开泄露过GM端&#xff0c;因为一些原因Dim也没再更新拆包文件中角色技能参数相关的部分…

C2_W2_Assignment_吴恩达_中英_Pytorch

Neural Networks for Handwritten Digit Recognition, Multiclass In this exercise, you will use a neural network to recognize the hand-written digits 0-9. 在本次练习中&#xff0c;您将使用神经网络来识别0-9的手写数字。 Outline 1 - Packages 2 - ReLU Activatio…

服务器有几种http强制跳转https设置方法

目前为站点安装SSL证书开启https加密访问已经是件很简单的事了&#xff0c;主要是免费SSL证书的普及&#xff0c;为大家提供了很好的基础。 Apache环境下如何http强制跳转https访问。Nginx环境下一般是通过修改“你的域名.conf”文件来实现的。 而Apache环境下通过修改.htacces…

类与对象(一)

目录 1 什么是面向过程和面向对象 1.1举例 2类的引入 3类的定义 3.1类的两种定义方式&#xff1a; 4.类的访问限定符及封装 4.1访问限定符 4.1.1为什么要有访问限定符 4.1.2有哪些访问限定符呢&#xff1f; 4.1.3简单举例理解 4.1.4C中的class与struct的区别(面试问题…

Tomcat基础及与Nginx实现动静分离,搭建高效稳定的个人博客系统

目录 引言 一、TOMCAT基础功能 &#xff08;一&#xff09;自动解压war包 &#xff08;二&#xff09;状态页 1.登录状态页 2.远程登录 &#xff08;三&#xff09;服务管理界面 &#xff08;四&#xff09;Host虚拟主机 1.设置虚拟主机 2.建立站点目录与文件 二、实…
最新文章