首页 > 其他分享 >在SpringBoot当中使用Spring AOP来实现权限验证和消息管理

在SpringBoot当中使用Spring AOP来实现权限验证和消息管理

时间:2024-12-11 16:10:40浏览次数:5  
标签:userMessage String Spring getType videoId private AOP annotation SpringBoot

引言

1. 权限验证

在之前的Blog项目当中,其实已经体验过权限验证了,不过那时候用的是SpringSecurity API来实现的方法,当没使用API时,可以使用Spring的AOP来进行权限验证了.其实也可以通过使用拦截器来实现登录权限验证,但是AOP相对而言更加灵活
消息管理

2. 消息管理

通过Srping的AOP可以在用户对业务进行操作的时候执行时能发送消息,从而使用户能接收到来自业务的消息提醒.


什么是Spring AOP?

实现步骤

1. 创建一个注解

  1. 登录验证
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface GlobalInterceptor {
    boolean checkLogin() default false;
}

这里涉及到的注解相关知识就不再赘述(主要是在写这个知识点的时候已经能看懂代码了所以不想再赘述了)
2. 发送提醒消息

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RecordUserMessage {
    MessageTypeEnum messageType();
}

2. 创建Aspect切面类

  1. 登录验证
    这里代码逻辑简单就不需要特别解释了
@Aspect
@Component
@Slf4j
public class GlobalOperationAspect {

    @Resource
    private RedisComponent redisComponent;

//	在ControllerMethod方法从@GlobalInterceptor自定义注解来标记切面,在ControllerMethod方法前执行该方法
    @Before("@annotation(com.easylive.annotation.GlobalInterceptor)")
    public void interceptoDto(JoinPoint joinPoint) {
        log.error("开始执行登录校验切点拦截");
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        GlobalInterceptor annotation = method.getAnnotation(GlobalInterceptor.class);
        if (Objects.isNull(annotation)) {
            return;
        }
        if (annotation.checkLogin()) {
            checkLogin();
        }
    }

    private void checkLogin() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(Constants.TOKEN_WEB);
        if (Objects.isNull(token)) {
            throw new BusinessException(ResponseCodeEnum.CODE_901);
        }
        TokenUserInfoDto tokenInfo = redisComponent.getTokenInfo(token);
        if (Objects.isNull(tokenInfo)) {
            throw new BusinessException(ResponseCodeEnum.CODE_901);
        }
    }
}
  1. 发送提醒消息
@Aspect
@Component
@Slf4j
public class UserMessageOperationAspect {

    @Resource
    private RedisComponent redisComponent;
    @Resource
    private UserMessageService userMessageService;

    private static final String PARAMETERS_VIDEO_ID = "videoId";
    private static final String PARAMETERS_ACTION_TYPE = "actionType";
    private static final String PARAMETERS_REPLY_COMMENTID = "replyCommentId";
    private static final String PARAMETERS_CONTENT = "content";
    private static final String PARAMETERS_AUDIT_REJECT_REASON = "reason";


    @Around("@annotation(com.easylive.annotation.RecordUserMessage)")
    public ResponseVO interceptorDto(ProceedingJoinPoint joinPoint) throws Throwable {
        ResponseVO proceed = (ResponseVO) joinPoint.proceed();
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RecordUserMessage annotation = method.getAnnotation(RecordUserMessage.class);
		//在这里joinPoint.getArgs()获取的是ControllerMethod的实际参数值,method.getParameters()获取的是控制器方法的参数元数据(参数定义名称和类型)
        if (annotation != null) {
            saveMessage(annotation, joinPoint.getArgs(), method.getParameters());
        }
        return proceed;
    }

    private void saveMessage(RecordUserMessage recordUserMessage, Object[] args, Parameter[] parameters) {
        String videoId = null;
        Integer actionType = null;
        Integer replyCommentId = null;
        String content = null;

        for (int i = 0; i < parameters.length; i++) {
            if (PARAMETERS_VIDEO_ID.equals(parameters[i].getName())) {
                videoId = (String) args[i];
            } else if (PARAMETERS_ACTION_TYPE.equals(parameters[i].getName())) {
                actionType = (Integer) args[i];
            } else if (PARAMETERS_REPLY_COMMENTID.equals(parameters[i].getName())) {
                replyCommentId = (Integer) args[i];
            } else if (PARAMETERS_CONTENT.equals(parameters[i].getName())) {
                content = (String) args[i];
            }
        }
        MessageTypeEnum messageTypeEnum = recordUserMessage.messageType();
	/*
	 *这里还要单独设置一个条件判断是否为收藏是因为原来的doAction方法里注解默认是写LIKE的
	 *靠参数actionType来区分互动类型,互动只提示点赞和收藏不提示投币
	 *所以默认LIKE然后根据actionType参数来变更消息类型
	*/
        if (UserActionTypeEnum.VIDEO_COLLECT.getType().equals(actionType)) {
            messageTypeEnum = MessageTypeEnum.COLLECTION;
        }

        TokenUserInfoDto tokenUserInfoDto = getTokenUserInfoDto();

        userMessageService.saveUserMessage(videoId, tokenUserInfoDto == null ? null : tokenUserInfoDto.getUserId(), messageTypeEnum, content, replyCommentId);
    }

    protected TokenUserInfoDto getTokenUserInfoDto() {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String token = request.getHeader(Constants.TOKEN_WEB);
        return redisComponent.getTokenInfo(token);
    }
}

异步实现发送提醒消息

@Override
    @Async
    public void saveUserMessage(String videoId, String sendUserId, MessageTypeEnum messageTypeEnum, String content, Integer replyCommentId) {
        VideoInfo videoInfo = videoInfoMapper.selectByVideoId(videoId);
        if (Objects.isNull(videoInfo)) {
            return;
        }
        UserMessageExtendDto extendDto = new UserMessageExtendDto();
        extendDto.setMessageContent(content);

        String reciveUserId = videoInfo.getUserId();

//        收藏取消已经记录的不再记录
        if (ArrayUtils.contains(new Integer[]{MessageTypeEnum.LIKE.getType(), MessageTypeEnum.COLLECTION.getType()}, messageTypeEnum.getType())) {
            UserMessageQuery userMessageQuery = new UserMessageQuery();
            userMessageQuery.setUserId(reciveUserId);
            userMessageQuery.setVideoId(videoId);
            userMessageQuery.setMessageType(messageTypeEnum.getType());
            Integer count = userMessageMapper.selectCount(userMessageQuery);
            if (count > 0) {
                return;
            }
        }

        UserMessage userMessage = new UserMessage();
        userMessage.setUserId(reciveUserId);
        userMessage.setVideoId(videoId);
        userMessage.setMessageType(messageTypeEnum.getType());
        userMessage.setReadType(MessageReadTypeEnum.NO_READ.getType());
        userMessage.setCreateTime(new Date());
        userMessage.setSendUserId(sendUserId);

//        评论特殊处理
        if (Objects.nonNull(replyCommentId)) {
            VideoComment videoComment = videoCommentMapper.selectByCommentId(replyCommentId);
            if (Objects.nonNull(videoComment)) {
                reciveUserId = videoComment.getUserId();
                extendDto.setMessageContentReply(videoComment.getContent());
            }
        }
        if (reciveUserId.equals(sendUserId)) {
            return;
        }

//        系统消息特殊处理
        if (MessageTypeEnum.SYS.getType().equals(messageTypeEnum.getType())) {
            VideoInfoPost videoInfoPost = videoInfoPostMapper.selectByVideoId(videoId);
            extendDto.setAuditStatus(videoInfoPost.getStatus());
        }
        userMessage.setUserId(reciveUserId);
        userMessage.setExtendJson(JsonUtils.convertObj2Json(extendDto));
        userMessageMapper.insert(userMessage);
    }

表结构
image
image
这里还有个UserMessageExtendDto类
image
这个类在数据库表里的主要功能是提供灵活性,在表结构当中这个以JSON形式存储在数据库当中,取出返回的时候从JSON序列化为Object,这个可以给数据库表提供灵活性.

结束

其实之前的MHBLOG项目当中也使用过AOP来进行日志记录,但是那次忘记记录了,这次在这个项目当中使用到的AOP相关知识其实也覆盖了上次使用过的知识点.总之就是这么多了.

标签:userMessage,String,Spring,getType,videoId,private,AOP,annotation,SpringBoot
From: https://www.cnblogs.com/MingHaiZ/p/18599650

相关文章

  • 【2024最新】基于Springboot+Vue的休闲娱乐代理售票系统Lw+PPT
    作者:计算机搬砖家开发技术:SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。专栏推荐:SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码精品专栏:Java精选实战项目源码、Python精选实战项目源码、大数据精选实战项目源码......
  • 【2024最新】基于Springboot+Vue的学生就业管理系统Lw+PPT
    作者:计算机搬砖家开发技术:SpringBoot、php、Python、小程序、SSM、Vue、MySQL、JSP、ElementUI等,“文末源码”。专栏推荐:SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码精品专栏:Java精选实战项目源码、Python精选实战项目源码、大数据精选实战项目源码......
  • docker环境部署springboot项目出现 X11FontManager 或者 libfreetype.so 字体文件缺失
    1.背景在本地部署没有问题,但是通过docker-compose部署到docker环境中就出现以下异常:Causedby:java.lang.NoClassDefFoundError:Couldnotinitializeclasssun.awt.X11FontManager 或com.alibaba.excel.exception.ExcelGenerateException:java.lang.UnsatisfiedLinkE......
  • SpringBoot,SpringCloudAlibaba,GateWay,Nacos,OpenFeign,Vue
    springboot,vue,springcloudalibaba课程视频,有需要可以看看<!--springboot,springboot整合redis,整合rocketmq视频:-->https://www.bilibili.com/video/BV1nkmRYSErk/?vd_source=14d27ec13a4737c281b7c79463687112<!--springcloudalibaba,openfeign,nacos,gateway,sso视频:-->......
  • 【计算机毕设选题推荐】基于springboot的健身房管理系统的设计与实现 【附源码+数据库
    ✍✍计算机毕设编程指导师**⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流!⚡⚡Java、Python、小程序、大数据实战项目集⚡⚡文末获取......
  • 基于SpringBoot框架的民宿连锁店业务系统(计算机毕业设计)+万字说明文档
    系统合集跳转源码获取链接一、系统环境运行环境:最好是javajdk1.8,我们在这个平台上运行的。其他版本理论上也可以。IDE环境:Eclipse,Myeclipse,IDEA或者SpringToolSuite都可以tomcat环境:Tomcat7.x,8.x,9.x版本均可操作系统环境:WindowsXP/7/8//8.1/10/11或者L......
  • springboot企业二手交易市场-计算机设计毕业源码17634
    目录摘要1绪论1.1选题背景与意义1.2国内外研究现状1.3论文结构与章节安排2系统分析2.1可行性分析2.1.1技术可行性2.1.2经济可行性2.1.3社会可行性2.2系统流程分析2.2.1数据流程2.2.2业务流程2.3 系统功能分析2.3.1功能性分析2.3.2非......
  • 基于SpringBoot框架的第三阶段学习设计源码-Z5yUlJ9r
    基于SpringBoot框架的第三阶段学习设计源码地址该项目是基于SpringBoot框架的第三阶段学习设计源码,采用HTML,Java,JavaScript和CSS作为主要开发语言。项目文件结构包含560个文件,其中HTML文件149个,Java源文件146个,图片文件(JPG和PNG格式)共90个,XML配置文件41个,属性文件40个,Git忽略......
  • 基于Springboot社团管理系统【附源码】
    基于Springboot社团管理系统效果如下:系统登录页面用户管理页面社团信息管理页面社团活动管理页面经费信息管理页面新闻信息管理页面系统主页面社团信息页面研究背景在当今高校与社区环境中,学生社团蓬勃发展,成为学生课余生活、社交互动以及兴趣培养的重要......
  • springboot和spring对应版本的介绍
    SpringBoot、Spring、JDK版本对应关系:SpringBoot版本对应Spring版本JDK版本SpringBoot特性描述3.2.x6.1.x17,21增强的云本地支持,新的架构优化,支持Java213.1.x6.0.x17,20加入新的架构组件,性能优化增强,支持Java203.0.x6.0.x17+支持Java17,移......