使用spring boot拦截器实现青少年模式

这篇具有很好参考价值的文章主要介绍了使用spring boot拦截器实现青少年模式。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

思路方法一:

便用Spring Boot拦截器采累计在线时间采实现青少年模式的步骤,可以参考以卜步骤:
1.创建一个拦截器类,实现Handlerlnterceptor 接口。
2.在拦截器类中,定义一个变量来记录用户在线时间。
3.在preHandle方法中,记录用户的登录时间。
4.在afterCompletion方法中,计算用户在线时间,并将其保存到数据库中。
这样就可以实现青少年模式了。当用户在线时间超过一定时长时,就可以提示用户休息一下,保护眼睛和身体健康。

思路方法二:

在用户类中添加一个属性loginTime,用于记录用户的登录时间。每次用户登录时,将该属性设置
为当前时间。每次用户退出或者Session销毁时,获取当前时间,并与loginTime相减,得到用户的
在线时长。

在数据库中添加一个表onlineTime,用于存储用户的在线时长。该表可以包含以下字段:userld
(用户ID)、totalTime(总在线时长)、dailyTime(每日在线时长)、date(日期)。

每次用户退出或者Session 销毁时,将用户的在线时长更新到onlineTime表中。如果该用户当天
已经有记录,则累加totalTime和dailyTime字段。如果该用户当天没有记录,则插入一条新记录,
并设置 totalTime和dailyTime字段为相同的值。

在前端展示用户的在线时长,可以使用Echarts或其他可视化工具,来绘制折线图、柱状图、饼图
等。你可以根据用户的需求,选择展示总在线时长、每日在线时长、每周在线时长、每月在线时长
等。

思路方法三:

我的搜索结果,spring boot拦截器是一种基于AOP的技术,可以用于对接口进行权限验证控制。青少
年模式是一种防止未成年人沉迷网络的系统,会在使用时段、时长、功能和浏览内容等方面对未成年人的
上网行为进行规范。您可以参考以下的步骤来实现这个功能:
1、创建一个拦截器类,实现Handlerlnterceptor接口,重写preHandle和postHandle方法
2、在preHandle方法中,获取请求的用户信息,判断是否是未成年人,如果是,则检查当前时间是否在
允许的使用时段内,如果不是,则返回false,拒绝请求,并提示用户进入青少年模式。
3、在postHandle方法中,获取请求的用户信息,判断是否是未成年人,如果是,则累计用户的在线时
间,并判断是否超过了允许的使用时长,如果超过了,则返回false,拒绝请求,并提示用户进入青少
年模式。
4、创建一个配置类,继承WebMvcConfigurerAdapter类,重写addlnterceptors方法,将拦截器注册到拦
截器链中,并指定拦截的路径
5、在application.properties文件中,配置青少年模式的相关参数,如使用时段、时长、功能和浏览内容
等。
6、在青少年模式下,限制用户的功能和浏览内容,如禁止直播、弹幕、评论、打赏等功能,过滤不良内
容等。

思路方法四:

1、利用AOP或拦截器来收集日志和统计方法执行时长的方法,你可以在切面类中定义一个ThreadLocal
绑定线程变量来存储每个请求的开始时间和结束时间,然后计算出执行时长,并记录到数据库或日志文件中。
2、给出了一种统计用户在线时长的方法,你可以在用户登录和退出时记录时间戳,然后根据用户的状态
(主动游戏或挂机)来累加时长,并定期更新到数据库中。
3、给出了一种利用监听事件来实现异步操作的方法,你可以在用户请求到达时发布一个事件,然后在事
件监听器中处理业务逻辑,并记录在线时长。

思路方法五:

1.创建一个自定义的拦截器类,实现Handlerlnterceptor接口
2.在拦截器类中,重写preHandle方法,在该方法中获取用户的登录信息和在线时间,并判断是否超过
青少年模式的限制,如果超过则返回false并跳转到提示页面,否则返回true并继续执行。
3.在拦截器类中,重写postHandle方法,在该方法中更新用户的在线时间,并保存到数据库或缓存中。
4.在拦截器类中,重写afterCompletion方法,在该方法中做一些清理工作,例如关闭数据库连接等。
5.在Spring Boot的配置类中,注册拦截器,并指定拦截的路径和排除的路径。

代码实现

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.NamedThreadLocal;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Optional;

/**
 * 描述:TeenagerModeInterceptor
 * 青少年模式拦截器
 * 先判断是否开启,如果没有开启 -->>通过
 * 如果开启了 --->> 从Redis判断有没有该key,
 * 如果没有该key则创建,将用户id作为key后缀,将TeenagerMode_作为前缀,将当前时间作为value
 * 如果有该key,(用当前时间-redis存放的时间)>=40分钟,如果大于等于,给出提示并删除该 redis key
 */
@Component
//只有加了这注解,热更新才生效
@RefreshScope
public class TeenagerModeInterceptor implements HandlerInterceptor {
    /**
     * spring 提供的命名ThreadLocal
     * 它是线程绑定的变量,提供线程局部变量
     * 我定义的泛型存储的是 System.currentTimeMillis()
     * 优化点:可以把这两个整合成一个,泛型使用实体对象
     */
    private static final NamedThreadLocal<Long> START_TIME_HOLDER = new NamedThreadLocal<>("StopWatch-StartTime");
    private static final NamedThreadLocal<String> USER_HOLDER = new NamedThreadLocal<>("StopWatch-UserId");

    /**
     * 设置默认值为22
     */
    @Value("${teenager.mode.after.time:22}")
    private Integer teenagerModeAfterTime;

    /**
     * 设置默认值为6
     */
    @Value("${teenager.mode.before.time:6}")
    private Integer teenagerModeBeforeTime;

    /**
     * 接口统计总时间:单位毫秒
     * 设置默认值为12万 即接口统计时长2分钟
     */
    @Value("${teenager.mode.total.time:120000}")
    private Integer teenagerModeTotalTime;


    /**
     * 在请求处理之前调用,返回 true 表示继续处理,返回 false 表示中断请求
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  chosen handler to execute, for type and/or instance evaluation
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String token = ServletRequestUtil.getToken();
        //未登录,放行
        if (StringUtils.isBlank(token)) {
            return true;
        }
        String userId = getUserId();

        //从数据库中查找
        ResultEntity<Boolean> resultEntity = xxxService.teenagerModeIsOpen(userId);
        boolean open = resultEntity.getData();

        if (!open) {
            //如果没有开启,直接放行
            return true;
        } else {
            //晚上10点至早上6点无法使用
            //使用servletUtil 是为了能从参数中动态获取获取,方便测试
            Integer after = ServletRequestUtil.getTeenagerModeAfterTime() == "" ? teenagerModeAfterTime : Integer.valueOf(ServletRequestUtil.getTeenagerModeAfterTime());
            Integer before = ServletRequestUtil.getTeenagerModeBeforeTime() == "" ? teenagerModeBeforeTime : Integer.valueOf(ServletRequestUtil.getTeenagerModeBeforeTime());
            if (LocalDateTime.now().isAfter(LocalDateTime.of(LocalDate.now(), LocalTime.of(after, 0, 0)))
                    || LocalDateTime.now().isBefore(LocalDateTime.of(LocalDate.now(), LocalTime.of(before, 0, 0)))) {
                    //抛出你们项目中自定义的异常,这里直接抛出RuntimeException
                throw new RuntimeException(xxxxx);
            }
            //如果开启了
            //记录开始运行时间,在postHandle方法计算运行时间
            START_TIME_HOLDER.set(System.currentTimeMillis());
            //设置请求userId属性,方便在postHandle方法获取
            //request.setAttribute("userId", userId);
            USER_HOLDER.set(userId);

            String total = redisClient.getTeenagerModeUserIdKey(userId);
            //从Redis判断有没有该key,如果没有该key则创建
            if (StringUtils.isBlank(total)) {
                redisxxx.setTeenagerModeUserIdKey(userId,"0");
                return true;
            }
            //判断总的时间是否已经大于设定值
            if (Long.valueOf(total).longValue() >= teenagerModeTotalTime) {
              //抛出你们项目中自定义的异常,这里直接抛出RuntimeException
                throw new RuntimeException(xxxxx);
            }

        }
        return true;
    }
    //一个是统计每个接口的运行时间、一个是【每天】累计总的时间

    /**
     * 在请求处理之后调用,但在视图渲染之前,即处理之后,返回响应之前
     *  但在实际测试中,基本已经返回响应了,只是可以在响应数据里添加一些东西,但是会出现奇怪的东西
     *
     * @param request      current HTTP request
     * @param response     current HTTP response
     * @param handler      the handler (or {@link HandlerMethod}) that started asynchronous
     *                     execution, for type and/or instance examination
     * @param modelAndView the {@code ModelAndView} that the handler returned
     *                     (can also be {@code null})
     * @throws Exception
     * @date 2023年3月29日09:47:56
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在这里可以对响应进行一些修改或添加额外的信息
        Long startTime = START_TIME_HOLDER.get();
        if (startTime == null) {
            return;
        }
        String userId = Optional.of(USER_HOLDER.get()).orElse("");
        if (userId == "") {
            return;
        }

        //2400000 毫秒值
        //接口运行时间
        long interfaceRunTime = System.currentTimeMillis() - startTime.longValue();
		//从redis 中获取总时间
        String valueForUserTotalTime = redisxxx.getTeenagerModeUserIdKey(userId);
        //如果没有该key对应的value
        if (StringUtils.isBlank(valueForUserTotalTime)) {
            redisxxx.setTeenagerModeUserIdKey(userId, String.valueOf(interfaceRunTime));
        } else {
            //原累计时长+接口运行时间
            //teenagerModeTotalTime 单位毫秒
            Long total = interfaceRunTime + Long.valueOf(valueForUserTotalTime).longValue();
            //更新累计时间
            redisxxx.setTeenagerModeUserIdKey(userId, String.valueOf(total));
        }

    }

    /**
     * 在整个请求结束之后调用,用于清理资源
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @param handler  the handler (or {@link HandlerMethod}) that started asynchronous
     *                 execution, for type and/or instance examination
     * @param ex       any exception thrown on handler execution, if any; this does not
     *                 include exceptions that have been handled through an exception resolver
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 在这里可以释放 ThreadLocal 变量中的信息,避免内存泄漏
        START_TIME_HOLDER.remove();
        USER_HOLDER.remove();
    }
}

为什么不在拦截器中使用request.setAttribute获取数据?

原因是一旦preHandle方法抛出异常,postHandle中的request对象就会为空,这是我踩过坑滴文章来源地址https://www.toymoban.com/news/detail-403045.html

到了这里,关于使用spring boot拦截器实现青少年模式的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • spring boot 拦截器例子

    在Spring Boot中,拦截器是通过实现`HandlerInterceptor`接口来实现的。它允许你在请求到达控制器方法之前和之后执行自定义的逻辑。下面我将为你提供一个简单的Spring Boot拦截器的例子。 假设我们有一个简单的控制器类`UserController`,其中有两个请求处理方法:`getUser`和`saveUser`,

    2024年02月15日
    浏览(26)
  • Spring Boot 配置拦截器

    通过拦截器,我们可以针对特定 URI 做拦截,做相关业务处理,比如检查用户是否登录,打印每个请求的处理耗时等。 新建登录验证类  LoginValidationInterceptor.java : 定义一个拦截器类后,您需要实现  HandlerInterceptor  接口,其有三个方法可以重写: preHandle : 在调用 Controller 方

    2024年02月08日
    浏览(39)
  • Spring Boot 统一功能处理(拦截器实现用户登录权限的统一校验、统一异常返回、统一数据格式返回)

    目录 1. 用户登录权限校验 1.1 最初用户登录权限效验 1.2 Spring AOP 用户统⼀登录验证 1.3 Spring 拦截器 (1)创建自定义拦截器 (2)将自定义拦截器添加到系统配置中,并设置拦截的规则 1.4 练习:登录拦截器 (1)实现 UserController 实体类 (2)返回的登录页面:login.html (3)实

    2024年02月12日
    浏览(32)
  • Spring Boot统一处理功能——拦截器

    ⽤户登录权限的发展从之前每个⽅法中⾃⼰验证⽤户登录权限,到现在统⼀的⽤户登录验证处理,它是⼀个逐渐完善和逐渐优化的过程。 我们先来回顾⼀下最初⽤户登录验证的实现⽅法: 从上述代码可以看出,每个⽅法中都有相同的⽤户登录验证权限,它的缺点是: 1. 每个

    2024年02月13日
    浏览(24)
  • Spring Boot拦截器(Interceptor)详解

    **拦截器(Interceptor)**同 Filter 过滤器一样,它俩都是面向切面编程——AOP 的具体实现(AOP切面编程只是一种编程思想而已)。 你可以使用 Interceptor 来执行某些任务,例如在 Controller 处理请求之前编写日志,添加或更新配置…… 在 Spring 中,当请求发送到 Controller 时,在被 Contr

    2024年02月03日
    浏览(26)
  • Spring Boot学习随笔- 拦截器实现和配置(HandlerInterceptor、addInterceptors)、jar包部署和war包部署

    学习视频:【编程不良人】2021年SpringBoot最新最全教程 拦截器 :Interceptor 拦截 中断 类似于javaweb中的Filter,不过没有Filter那么强大 作用 Spring MVC的拦截器是一种用于在请求处理过程中进行预处理和后处理的机制。拦截器可以在请求到达控制器之前和之后执行一些操作,例如日

    2024年02月02日
    浏览(30)
  • 【Spring Boot】拦截器与统一功能处理

    博主简介:想进大厂的打工人 博主主页: @xyk: 所属专栏: JavaEE进阶   上一篇文章我们讲解了Spring AOP是一个基于面向切面编程的框架,用于将某方面具体问题集中处理,通过代理对象来进行传递,但使用原生Spring AOP实现统一的拦截是非常繁琐的。而在本节,我们将使用一种

    2024年02月14日
    浏览(27)
  • Spring Boot拦截器与动态代理深度剖析

    🎉欢迎来到架构设计专栏~Spring Boot拦截器与动态代理深度剖析 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:架构设计 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限,如果

    2024年01月22日
    浏览(34)
  • Spring Boot拦截器与过滤器的区别

    在使用Spring Boot开发Web应用程序时,您可能需要在处理请求之前或之后执行某些操作。这些操作可以包括身份验证、日志记录、性能监测等。在这种情况下,您可以使用两种不同的机制:拦截器和过滤器。本文将介绍这两种机制及其区别,并提供一些示例代码来演示如何在S

    2024年02月08日
    浏览(46)
  • spring boot 过滤器&拦截器与aop

    在使用 Spring 框架时,可以通过在 web.xml 配置文件中注册过滤器,使其在请求进入 Spring 前就能够进行预处理。这样可以在请求进入 Spring MVC 的 DispatcherServlet 之前,对请求进行拦截、修改或者过滤。 过滤器在 Spring 中的应用场景包括但不限于: 字符编码过滤:通过过滤器,在

    2024年02月01日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包