我的编程空间,编程开发者的网络收藏夹
学习永远不晚

使用Spring Boot AOP处理方法的入参和返回值

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

使用Spring Boot AOP处理方法的入参和返回值

前言

IOC和AOP是Spring 中最重要的两个模块。这里练习一下如何使用Spring Boot AOP处理方法的入参和返回值。

Spring AOP的简单介绍:

AOP(Aspect-Oriented Programming)面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP能够将那些与业务⽆关,却为业务模块所共同调⽤的逻辑或责任(例如事务处理、⽇志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于提高系统的可拓展性和可维护性。

Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接⼝,那么Spring AOP会使⽤JDK代理,去创建代理对象,⽽对于没有实现接⼝的对象,就⽆法使⽤ JDK代理去进⾏代理了,这时候Spring AOP会使⽤Cglib ,这时候Spring AOP会使⽤ Cglib代理 ⽣成⼀个被代理对象的⼦类来作为代理,如下图所示:

一篇详细介绍AOP的文章:细说Spring——AOP详解(AOP概览)

1. 需求场景

前段时间实习,遇到了一个需求是这样的:项目上线前,项目经理要求有一个用户私密信息的字段需要在数据库中加密存储,从数据库读取出来后需要解密,正常显示到用户界面中。

下面的DEMO中,模拟场景项目经理突然觉得这个用户的身份证号是用户隐私需要进行加密保存,保护用户的隐私,

User类定义如下:


public class User {
    private Integer id;
    private String username;
    private String password;
    private String identityNum;
    //省略getter、setter、toString方法
}

2. 解决方案

因为是临时加的需求,考虑到多个实体类中都会有identityNum属性,为了不侵入原本的业务代码和数据处理代码和业务代码的解耦,一个比较好的方案是使用Spring AOP处理,以DAO层方法做切点,处理字段的加密解密。

3. 代码实现

下面使用Spring Boot+MyBatis实现DEMO,模拟上述场景和解决方案实现。

Controller层UserController类的代码:


@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    UserService userService;
    @GetMapping
    public List<User> getAllUsers(){
        return userService.getAllUsers();
    }
    @PostMapping
    public void save(@RequestBody User user){
        userService.save(user);
    }
}

Service层UserService类代码:


@Service
public class UserService {
    @Autowired
    UserDao userDao;
    public List<User> getAllUsers() {
        return userDao.getAllUsers();
    }
    public void save(User user) {
        userDao.save(user);
    }
}

Dao层UserDao接口实现:


@Mapper
public interface UserDao {
    List<User> getAllUsers();
    void save(@Param("user") User user);
}

UserMapper.xml文件实现:


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.javahai.springbootdemo.dao.UserDao">
    <insert id="save">
        insert into user values (#{user.id},#{user.username},#{user.password},#{user.identityNum})
    </insert>
    <select id="getAllUsers" resultType="top.javahai.springbootdemo.entity.User">
        select id,username,password,identity_num as identityNum  from user
    </select>
</mapper>

切面类UserInfoHandler实现如下,这里只是使用字符串截取的方法模拟加密代码

使用环绕通知@Around注解实现


@Aspect
@Component
public class UserInfoHandler {
    @Pointcut("execution(* top.javahai.springbootdemo.dao.UserDao.*(..))")
    public void pointcut(){
    }
    @Around("pointcut()")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        //处理方法参数,如果是User就进行加密处理
        Object[] args = joinPoint.getArgs();
        for (Object arg : args) {
            if (arg instanceof List){
                if (((List) arg).get(0) instanceof User){
                    ((List<User>) arg).forEach(user->{
                        user.setIdentityNum("encode"+user.getIdentityNum());
                    });
                }
            }
            if (arg instanceof User){
                String identityNum = ((User) arg).getIdentityNum();
                ((User) arg).setIdentityNum("encode"+identityNum);
            }
        }
        //执行方法,获取返回值
        Object obj = joinPoint.proceed();
        //处理方法返回值
        if (obj instanceof List){
            if (!((List) obj).isEmpty()){
                if (((List) obj).get(0) instanceof User){
                    ((List<User>) obj).forEach(data->{
                        data.setIdentityNum(data.getIdentityNum().substring(6));
                    });
                }
            }
        }
        return obj;
    }
}

如果是在其他实体类中也存在identityNum身份证字段,则需要在@PointCut中定义多个切点,另外处理的地方需要添加多个判断。

定义多个切点:


    @Pointcut("execution(* top.javahai.springbootdemo.dao.UserDao.*(..)) ||" +
            "execution(* top.javahai.springbootdemo.dao.ResumeDao.*(..))")
    public void pointcut(){}

4. 测试

通过http://localhost:8080/users接口,将保存一个新的用户数据到数据库中

在这里插入图片描述

查看数据库的存储:

在这里插入图片描述

取出所有的用户数据:

在这里插入图片描述

从测试结果可以看到代码可以正确的处理方法的入参和返回值。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

使用Spring Boot AOP处理方法的入参和返回值

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Spring Boot统一接口返回及全局异常处理的方法

这篇文章主要讲解了“Spring Boot统一接口返回及全局异常处理的方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring Boot统一接口返回及全局异常处理的方法”吧!1、解决方
2023-06-30

C++ 函数调用预处理器宏:参数传递和返回值的高级用法

在 c++++ 中,预处理器宏可用于调用函数,涉及以下步骤:参数传递:宏参数用圆括号括起来,以逗号分隔。返回值:使用宏参数指定要返回的值,并赋值给变量。实战案例:通过使用宏优化查找数组中最大值索引的函数,减少了计算次数,提高了效率。C++
C++ 函数调用预处理器宏:参数传递和返回值的高级用法
2024-05-04

Java带参数与带返回值的方法怎么定义和调用

这篇文章主要介绍“Java带参数与带返回值的方法怎么定义和调用”,在日常操作中,相信很多人在Java带参数与带返回值的方法怎么定义和调用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java带参数与带返回值的
2023-06-29

C++ 函数调用异常处理:参数传递和返回值中的异常情况

摘要:函数调用中的异常处理涉及:参数传递异常:传递的参数引发异常时,异常传递给调用函数。返回值异常:函数通过返回值引发异常,直接传递给调用函数。实战示例:myclass::func() 函数参数为空字符串时抛出 std::invalid_a
C++ 函数调用异常处理:参数传递和返回值中的异常情况
2024-05-02

C++ 函数调用重载机制:参数传递和返回值的多义性处理

c++++ 函数重载允许同一函数名定义多个变体,根据不同形参列表区分。参数传递有值传递和引用传递两种,值传递将值复制到局部变量,引用传递将引用传递给函数,修改引用会影响外部变量。函数可返回不同类型的值,包括基本数据类型、引用和对象。C++
C++ 函数调用重载机制:参数传递和返回值的多义性处理
2024-05-01

PHP中trait的使用和同时引入多个trait时同名方法冲突的处理方法

这篇文章主要介绍了PHP中trait的使用和同时引入多个trait时同名方法冲突的处理,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-05-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录