【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现

【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现

1.分页工具

使用方法:在调用sql语句前,调用 PageHelper.startPage(); 方法就行了(若依包装过了,调用startPage();方法)

1.pagehelper的功能
·实现数据库的分页查询

2.操作步骤
2.1在pom文件中加入maven依赖



com.github.pagehelper

pagehelper

5.1.10


2.2在mybatis主配置文件在加入plugin
·一定要注意这个插件的代码是写在environment配置的上面,而且是写在mybatis的主配置文件中,不是写在pom文件中的。






2.3在查询的代码中调用方法

     PageHelper.startPage(1,3);
      List students = dao.selectAll();

分页工具类(被若依包装过了)

package com.ruoyi.common.utils;

import com.github.pagehelper.PageHelper;
import com.ruoyi.common.core.page.PageDomain;
import com.ruoyi.common.core.page.TableSupport;
import com.ruoyi.common.utils.sql.SqlUtil;

/**
 * 分页工具类
 * 
 * @author ruoyi
 */
public class PageUtils extends PageHelper
{
    /**
     * 设置请求分页数据
     */
    public static void startPage()
    {
        PageDomain pageDomain = TableSupport.buildPageRequest();
        Integer pageNum = pageDomain.getPageNum();
        Integer pageSize = pageDomain.getPageSize();
        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
        Boolean reasonable = pageDomain.getReasonable();
        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
    }

    /**
     * 清理分页的线程变量
     */
    public static void clearPage()
    {
        PageHelper.clearPage();
    }
}


2.线程池

自定义线程池的三种方式

  • 重新实现接口AsyncConfigurer
  • 继承AsyncConfigurerSupport
  • 配置由自定义的TaskExecutor替代内置的任务执行器(若依用的这个)
package com.ruoyi.framework.config;

import com.ruoyi.common.utils.Threads;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 *
 * @author ruoyi
 **/
@Configuration
public class ThreadPoolConfig
{
    // 核心线程池大小
    private int corePoolSize = 50;

    // 最大可创建的线程数
    private int maxPoolSize = 200;

    // 队列最大长度
    private int queueCapacity = 1000;

    // 线程池维护线程所允许的空闲时间
    private int keepAliveSeconds = 300;

    @Bean(name = "threadPoolTaskExecutor")
    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setMaxPoolSize(maxPoolSize);
        executor.setCorePoolSize(corePoolSize);
        executor.setQueueCapacity(queueCapacity);
        executor.setKeepAliveSeconds(keepAliveSeconds);//最大空闲时间 超出则 删除线程
        // 线程池对拒绝任务(无线程可用)的处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

    /**
     * 执行周期性或定时任务
     */
    @Bean(name = "scheduledExecutorService")
    protected ScheduledExecutorService scheduledExecutorService()
    {
        return new ScheduledThreadPoolExecutor(corePoolSize,
                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
                new ThreadPoolExecutor.CallerRunsPolicy())
        {
            @Override
            protected void afterExecute(Runnable r, Throwable t)
            {
                super.afterExecute(r, t);
                Threads.printException(r, t);
            }
        };
    }
}

//使用

package com.ruoyi.framework.manager;

import java.util.TimerTask;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import com.ruoyi.common.utils.Threads;
import com.ruoyi.common.utils.spring.SpringUtils;

/**
 * 异步任务管理器
 * 
 * @author ruoyi
 */
public class AsyncManager
{
    /**
     * 操作延迟10毫秒
     */
    private final int OPERATE_DELAY_TIME = 10;

    /**
     * 异步操作任务调度线程池
     */
    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");

    /**
     * 单例模式
     */
    private AsyncManager(){}

    private static AsyncManager me = new AsyncManager();

    public static AsyncManager me()
    {
        return me;
    }

    /**
     * 执行任务
     * 
     * @param task 任务
     */
    public void execute(TimerTask task)
    {
        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
    }

    /**
     * 停止任务线程池
     */
    public void shutdown()
    {
        Threads.shutdownAndAwaitTermination(executor);
    }
}

3.定时任务

1.2 Quartz的三大核心组件

  1. 调度器:Scheduler
  2. 任务 :JobDetail
  3. 触发器:Trigger,包括SimpleTrigger和CronTrigger

Job(任务):是一个接口,有一个方法 void execute(JobExecutionContext context) ,可以通过实现该接口来定义需要执行的任务(具体的逻辑代码)。

JobDetail:Quartz每次执行Job时,都重新创建一个Job实例,会接收一个Job实现类,以便运行的时候通过newInstance()的反射调用机制去实例化Job。JobDetail是用来描述Job实现类以及相关静态信息,比如任务在scheduler中的组名等信息。

Trigger(触发器):描述触发Job执行的时间触发规则实现类SimpleTrigger和CronTrigger可以通过crom表达式定义出各种复杂的调度方案。

Calendar:是一些日历特定时间的集合。一个Trigger可以和多个 calendar关联,比如每周一早上10:00执行任务,法定假日不执行,则可以通过calendar进行定点排除。

Scheduler(调度器):代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。Scheduler可以将Trigger绑定到某一JobDetail上,这样当Trigger被触发时,对应的Job就会执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。
————————————————
版权声明:本文为CSDN博主「李巴巴」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_52850476/article/details/123140549

应用场景

1.更新缓存

2.读写日志

3.发送邮件

4.定期将redis数据持久化至Mysql中,保证两者之间的数据同步,兼顾效率与数据安全

5.使用Quartz定时器定期将体温数据持久化到本地

看的一些视频

Quartz定时任务 高可用 超简易上手

这个人对Quartz进行了封装,上手 更简单

  1. 引入依赖

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-79Vu6dnG-1666788050355)(D:/GitCode/tuchuang/img/image-20221012185653662.png)]
【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第1张图片

  1. 写调度方法

2.1 实现org.quartz.Job接口

2.2 添加调度注解,使用注解CronExp添加任务的调度策略(任务id,执行频率), 使用注解@Component将任务注入到容器中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hxgQGm4i-1666788050356)(D:/GitCode/tuchuang/img/image-20221012185941557.png)]
【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第2张图片

2.2重写execute方法

SpringBoot整合Quartz时钟调度框架

在日常项目运行中,我们总会有需求在某一时间段周期性的执行某个动作,比如每天在某个时间段导出报表,或者每隔多久统计一次现在在线的用户量等

在springBoot中 有java自带的java.util.timer类,SpringBoot自带的Scheduled来实现,也有强大的调度器Quarzet。Scheduled在Spring3.x引入,默认SpringBoot自带该功能,使用起来也很简单,在启动类级别添加@EnableScheduling 注解即可引入定时环境任务。但遗憾的是Scheduled默认不支持分布式环境,这里主要讲解Quartz始终调度框架与SpringBoot集成。

1.环境整合配置–引入dependency

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ehSfs2xJ-1666788050356)(D:/GitCode/tuchuang/img/image-20221012184549443.png)]

2.源代码添加

  • 定义job,需要实现Job接口 ,job接口来自Quarzet

  • 重写execute方法,把任务写在这里

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bm4TOVqo-1666788050357)(D:/GitCode/tuchuang/img/image-20221012184628562.png)]
    【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第3张图片

  • 构建配置调度类

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1tkIEeNE-1666788050357)(D:/GitCode/tuchuang/img/image-20221012184927234.png)]

【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第4张图片

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Yq3Ap5Lv-1666788050358)(D:/GitCode/tuchuang/img/image-20221012185328599.png)]
    【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第5张图片

4.aop实现日志记录功能

https://www.bilibili.com/video/BV1Ek4y117mm/?spm_id_from=333.337.search-card.all.click&vd_source=e985eba9865594055b36f262b6a2a3de

https://www.bilibili.com/video/BV1KT4y1G7hs/?spm_id_from=333.337.search-card.all.click&vd_source=e985eba9865594055b36f262b6a2a3de

image-20221014205103192

【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第6张图片

image-20221014210516350

【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第7张图片

SpringBoot实战项目教程】AOP记录日志,面试技术亮点,10分钟速成

1.添加注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-baE9itqG-1666788050359)(D:/GitCode/tuchuang/img/image-20221014204425924.png)]
【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第8张图片

2.开发注解

image-20221014204549782 ![在这里插入图片描述](https://img-blog.csdnimg.cn/714b7042e6784d0c949ccc971d8511ee.png#pic_center)
  1. 定义切面 定义了通知和切点的关系 ,上面那个注解就是切点

    @Pointcut是切入点,后面的表达式代表 只要标注了LogAnnotation这个注解的都是切入点 pt(), 对切入点pt()的通知方式为环绕通知 ,表达式有很多种

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9L3vBpGo-1666788050360)(D:/GitCode/tuchuang/img/image-20221014204821739.png)]
    【若依】线程池,分页工具,定时任务,aop日志,全局异常处理功能实现_第9张图片

通知类型

5.全局异常处理

在spring 3.2中,新增了@ControllerAdvice 注解,可以用于定义@ExceptionHandler、@InitBinder、@ModelAttribute,并应用到所有@RequestMapping中。

全局接口异常处理,与@ExceptionHandler(value = Exception.class)一起使用可以全局捕获指定异常。

http://www.icodebang.com/article/252255.html

看@RestControllerAdvice源码可以知道,它就是@ControllerAdvice和@ResponseBody的合并。此注解通过对异常的拦截实现的统一异常返回处理,如果大家在项目中有类似的需求,不妨试一下,好用又方便。

当自定义类加@ControllerAdvice注解时,方法需要返回json数据时,每个方法还需要添加@ResponseBody注解

当自定义类加@RestControllerAdvice注解时,方法自动返回json数据,每个方法无需再添加@ResponseBody注解

若依的全局异常处理类

package com.ruoyi.framework.web.exception;

import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.exception.DemoModeException;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;

/**
 * 全局异常处理器
 * 
 * @author ruoyi
 */
@RestControllerAdvice
public class GlobalExceptionHandler
{
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 权限校验异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
    }

    /**
     * 请求方式不支持
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
            HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
    {
        log.error(e.getMessage(), e);
        Integer code = e.getCode();
        return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生未知异常.", requestURI, e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public AjaxResult handleException(Exception e, HttpServletRequest request)
    {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常.", requestURI, e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(BindException.class)
    public AjaxResult handleBindException(BindException e)
    {
        log.error(e.getMessage(), e);
        String message = e.getAllErrors().get(0).getDefaultMessage();
        return AjaxResult.error(message);
    }

    /**
     * 自定义验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
    {
        log.error(e.getMessage(), e);
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return AjaxResult.error(message);
    }

    /**
     * 演示模式异常
     */
    @ExceptionHandler(DemoModeException.class)
    public AjaxResult handleDemoModeException(DemoModeException e)
    {
        return AjaxResult.error("演示模式,不允许操作");
    }
}

你可能感兴趣的:(mybatis,java,spring)