AOP:分页参数统一校验

news2024/11/26 0:40:24

需求说明

为了保证系统的安全性,需要对所有的 查询列表 接口,添加分页参数,并对分页参数进行校验,
,保证参数的合法性。

比如, pageSize(每页显示条数),如果不做校验,一旦传递过来一个很大的数值,比如,十万亿,数据库可能会直接卡住,或者应用服务器的内存可能也被挤爆。

分页参数与校验逻辑

分页参数校验逻辑
currentPage当前页,应大于等于1
pageSize每页显示条数,取值范围为[1, 100]

currentPagepageSize,都应该是整数,如果传入的是小数、超出范围的数字、或者非数字,也应该直接报错;SpringMVC 已经自动支持这部分校验,不需要我们再去额外处理。

解决方案

使用 AOP(面向切面编程),在所有接口前,检查分页参数;如果不合法,直接返回接口调用失败,并将错误原因返回。

返回接口调用失败,采用的方法是抛出业务异常,然后,由异常统一处理模块,将错误原因封装到返回结果中。

代码

参数校验切面

package com.example.core.advice;

import com.example.core.model.BusinessException;
import com.example.core.model.ErrorEnum;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 分页参数校验
 */
@Aspect
@Order(10)
@Component
public class PageValidator {

    private static final String CURRENT_PAGE = "currentPage";
    private static final String PAGE_SIZE = "pageSize";


    // 拦截 com.example.web 包及其子包下的所有类的@RequestMapping注解修饰的方法
    @Pointcut("execution(* com.example.web..*.*(..)) and @annotation(org.springframework.web.bind.annotation.RequestMapping)")
    private void pointcut() {
    }


    // Before表示 advice() 将在目标方法执行前执行
    @Before("pointcut()")
    public void advice(JoinPoint joinPoint) {
        // 获取请求信息
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes == null) {
            return;
        }
        HttpServletRequest request = attributes.getRequest();


        // 校验: [当前页]
        validateCurrentPage(request);

        // 校验: [每页显示条数]
        validatePageSize(request);
    }


    /**
     * 校验: [当前页]
     */
    private void validateCurrentPage(HttpServletRequest request) {
        String currentPageString = request.getParameter(CURRENT_PAGE);
        if (currentPageString == null) {
            return;
        }

        int currentPage = Integer.parseInt(currentPageString);
        if (currentPage >= 1) {
            return;
        }

        String userMessage = "当前页,应大于等于1";
        String errorMessage = String.format("%s:【分页参数校验异常】:【错误字段:[%s],错误值:[%s],错误信息:[%s]】。",
                ErrorEnum.A0425.getMessage(), CURRENT_PAGE, currentPage, userMessage);

        throw new BusinessException(userMessage, ErrorEnum.A0425.name(), errorMessage);
    }


    /**
     * 校验: [每页显示条数]
     */
    private void validatePageSize(HttpServletRequest request) {
        String pageSizeString = request.getParameter(PAGE_SIZE);
        if (pageSizeString == null) {
            return;
        }

        int pageSize = Integer.parseInt(pageSizeString);
        if (pageSize >= 1 && pageSize <= 100) {
            return;
        }

        String userMessage = "每页显示条数,取值范围为[1, 100]";
        String errorMessage = String.format("%s:【分页参数校验异常】:【错误字段:[%s],错误值:[%s],错误信息:[%s]】。",
                ErrorEnum.A0425.getMessage(), PAGE_SIZE, pageSize, userMessage);

        throw new BusinessException(userMessage, ErrorEnum.A0425.name(), errorMessage);
    }
}

分页参数实体

分页参数,一般使用封装好的 分页参数实体 接收(推荐),但是也可以直接写在接口参数列表中(不推荐)。但是,不论怎样接收,只要是分页参数,就应该被校验。

下面是 分页参数实体 的代码:

package com.example.core.model;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springdoc.api.annotations.ParameterObject;

@Data
@ParameterObject
@Schema(name = "分页参数Query")
public class PageQuery {

    @Schema(description = "当前页", type = "Integer", defaultValue = "1", example = "1", minimum = "1")
    private Integer currentPage = 1;

    @Schema(description = "每页显示条数", type = "Integer", defaultValue = "10", example = "10", minimum = "1", maximum = "100")
    private Integer pageSize = 10;

}

测试接口

package com.example.web.page.controller;

import com.example.core.log.annotation.ApiLog;
import com.example.core.model.PageQuery;
import io.swagger.v3.oas.annotations.Operation;
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.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("page")
@Tag(name = "分页参数校验")
public class PageController {


    @ApiLog
    @GetMapping(path = "users/PageQuery")
    @Operation(summary = "查询用户列表 PageQuery", description = "分页参数校验,使用PageQuery接收分页参数。")
    public String listUsers(PageQuery pageQuery) {
        return "查询用户列表 PageQuery:成功";
    }


    @GetMapping(path = "users/NoPageQuery")
    @Operation(summary = "查询用户列表 NoPageQuery", description = "分页参数校验,分页参数直接写在了方法的参数列表中,未使用PageQuery接收分页参数。")
    public String listUsersWithoutPageQuery(Integer currentPage, Integer pageSize) {
        return "查询用户列表 NoPageQuery:成功";
    }


    @RequestMapping(path = "users/RequestMapping", method = RequestMethod.GET)
    @Operation(summary = "查询用户列表 RequestMapping", description = "分页参数校验,使用 @RequestMapping 注解。")
    public String listUsersByRequestMapping(PageQuery pageQuery) {
        return "查询用户列表 RequestMapping:成功";
    }

}

测试结果

在这里插入图片描述

在这里插入图片描述

@Order(10)

对切面进行排序,设定切面的触发顺序。数值越小的,优先级越高。

能够触发的切面可能有好多个,需要排个序,告诉项目先触发哪一个。

如果没有设定触发顺序,会按照切面在项目中的位置顺序来触发。比如下图中,默认情况,就是PageValidator 先触发,ApiLogAspect 后出发。

如果 PageValidator 抛出了异常,后面的 ApiLogAspect 就不会被触发了。

在这里插入图片描述

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

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

相关文章

基于Java的个人博客文章管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

传统安防音视频平台架构

内部级联,为上下级均为自己平台海康子进程调用海康的设备SDKPTPCS通过封装代理不同的私有协议的差异,封装为大华统一的三代协议PC客户端通过调用平台SDKCMS一般采用双机热备技术PTPCS系统一般采用Windows嵌入式,由于部分设备厂家提供的SDK只有Windows的服务和服务之间的调用通过…

爱创科技携手源石酒庄,助力酒企走出窜货售假“沼泽”

在中国&#xff0c;一场关于美酒生活的消费革命正默默兴起。随着人们生活品质的不断提升&#xff0c;越来越多的消费者开始追求个性化、健康和美好的饮酒体验&#xff0c;消费升级正推动着酒行业整体逐步“迭代进化”。作为国内最早开始葡萄酒产业工业化发展的地区之一&#xf…

BUUCTF reverse wp 56 - 60

[ACTF新生赛2020]SoulLike __int64 __fastcall main(int a1, char **a2, char **a3) {char v5; // [rsp7h] [rbp-B9h]int i; // [rsp8h] [rbp-B8h]int j; // [rspCh] [rbp-B4h]int flag_content[14]; // [rsp10h] [rbp-B0h] BYREFchar flag[110]; // [rsp4Ah] [rbp-76h] BYREFu…

网络协议--概述

1.2 分层 网络协议通常分不同层次进行开发&#xff0c;每一层分别负责不同的通信功能。一个协议族&#xff0c;比如TCP/IP&#xff0c;是一组不同层次上的多个协议的组合。 TCP/IP通常被认为是一个四层协议系统&#xff0c;如图1-1所示。每一层负责不同的功能&#xff1a; 1.链…

从零手搓一个【消息队列】实现消息在文件中的存储

文章目录 一、序列化 / 反序列化二、文件存储设计1, 队列目录2, 消息数据文件3, 消息统计文件 三、硬盘管理 -- 文件1, 创建 MessageFileManager 类2, createQueueFiles() 创建目录/文件3, deleteFiles() 删除目录/文件4, checkFileExists() 检查目录/文件是否存在5, readStat(…

MonkeyRunner自动化测试

一&#xff1a;简介 MonkeyRunner提供了一个API&#xff0c;使用此API写出的程序可以在Android代码之外控制Android设备和模拟器。通过monkeyrunner&#xff0c;您可以写出一个Python程序去安装一个Android应用程序或测试包&#xff0c;运行它&#xff0c;向它发送模拟击键&…

单目标应用:基于狐猴优化算法(Lemurs Optimizer,LO)的微电网优化调度MATLAB

一、狐猴优化算法 狐猴优化算法&#xff08;Lemurs Optimizer&#xff0c;LO&#xff09;由Ammar Kamal Abasi等人于2022年提出&#xff0c;该算法模拟狐猴的跳跃和跳舞行为&#xff0c;具有结构简单&#xff0c;思路新颖&#xff0c;搜索速度快等优势。 狐猴头体长约为30-45…

【通意千问】大模型GitHub开源工程学习笔记(2)--使用Qwen进行推理的示例代码解析,及transformers的库使用

使用Transformers来使用模型 如希望使用Qwen-chat进行推理,所需要写的只是如下所示的数行代码。请确保你使用的是最新代码,并指定正确的模型名称和路径,如Qwen/Qwen-7B-Chat和Qwen/Qwen-14B-Chat 这里给出了一段代码 from transformers import AutoModelForCausalLM, Aut…

Promise击鼓传花

Promise击鼓传花 Promise系列导航前言一、Promise.prototype.then()1.语法2.代码及说明&#xff08;1&#xff09;代码段&#xff1a;&#xff08;2&#xff09;代码段&#xff1a;&#xff08;3&#xff09;代码段&#xff1a;&#xff08;4&#xff09;代码段&#xff1a;&am…

select完成服务器并发

服务器 #include <myhead.h>#define PORT 4399 //端口号 #define IP "192.168.0.191"//IP地址//键盘输入事件 int keybord_events(fd_set readfds); //客户端交互事件 int cliRcvSnd_events(int , struct sockaddr_in*, fd_set *, int *); //客户端连接事件 …

cloudCompare教程:一、可视化、点、线编辑

依据高度等准则(都在Scalar Fields中)渲染点云&#xff08;首先要打开Tools -> Projection -> Export coordinate to SF&#xff09; 在上述准则之外的&#xff0c;设置为不显示&#xff1a; 软件的显示设置&#xff08;首先打开右边的彩色柱状图&#xff0c;点击左边属性…

Qt::工程框架-工具栏停靠|悬浮-QDockWidget

二维矢量动画智能制作软件开发合集 链接&#xff1a;软件开发技术分享及记录合集 个人开发二维矢量动画智能制作软件界面如下&#xff1a; ​目录 一、界面停靠原理 二、界面停靠代码实现 三、界面停靠软件测试视频 结束语 一、工具栏停靠|悬浮原理 本软件的窗口设置如下…

2023年中国肠胃炎用药行业现状分析:随着老龄化进程明显加速,市场规模同比增长7%[图]

急性肠胃炎是一种因为饮食不当而引起的消化系统疾病&#xff0c;通常是因为摄入了含有病原菌的变质食物&#xff0c;或者过量食用刺激性食物&#xff0c;从而导致肠胃道黏膜发生急性炎症反应&#xff1b;慢性肠胃炎是一种长期存在症状并持续引发胃黏膜和肠黏膜发生慢性炎症反应…

超声雷达传感器与三角定位

1.概述 超声波雷达的工作原理是通过超声波发射装置向外发出超声波&#xff0c;到通过接收器接收到发送过来超声波时的时间差来测算距离。 对温度敏感性&#xff0c;使得超声波的速度具有如下特性 或 2.超声波雷达车位探测与障碍物检测 汽车超声波类装配方案多为前后向共8个UP…

28269-2012 座椅用蛇形弹簧 技术条件

声明 本文是学习GB-T 28269-2012 座椅用蛇形弹簧 技术条件. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了用圆截面材料制造的座椅用蛇形弹簧的技术要求、试验方法、检验规则及标志、包装、 运输、贮存。 本标准适用于车辆座椅…

APA技术架构与说明

1.自动泊车的硬件架构 2.APA自动泊车辅助系统 1&#xff09;APA主要包括以下典型功能 &#xff08;1&#xff09;泊车入库&#xff1a;利用超声波雷达或环视摄像头实现车位识别&#xff0c;并计算出合适行驶轨迹&#xff0c;对车辆进行横向/纵向控制使车辆驶入车位&#xff1…

20分钟---Vue2->Vue3

Vue官网地址&#xff1a;gVue.js - The Progressive JavaScript Framework | Vue.js 选项式vs组合式 vue的两种风格&#xff0c;搬运官网源码&#xff1a; 选项式 API (Options API)​ 使用选项式 API&#xff0c;我们可以用包含多个选项的对象来描述组件的逻辑&#xff0c…

28295-2012 高温合金管材通用技术条件

声明 本文是学习GB-T 28295-2012 高温合金管材通用技术条件. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 1.1 本标准规定了经过热、冷加工生产的变形高温合金管材产品交货的技术要求、试验方法、检验规则 和交货条件等技术内容。 1.2 本标…

Linux常用指令(二)

目录 一、 删除空目录&#xff08;rmdir&#xff09; 二、ln 硬链接与软链接 三、新建空文件或更新文件的时间戳&#xff08;touch&#xff09; 四、比较文件内容的差异&#xff08;diff&#xff09; 五、显示当前时间或设置系统时间&#xff08;date&#xff09; 六、显…