本文是作者原创,版权归作者所有.若要转载,请注明出处.

本文都是springboot的常用和实用功能,话不多说开始吧

定时任务

1.启动类开启注解

  1. @EnableScheduling //开启基于注解的定时任务
  2. @MapperScan("com.pdzx.dao")
  3. @SpringBootApplication
  4. public class VideoApplication {
  5.  
  6. public static void main(String[] args) {
  7. SpringApplication.run(VideoApplication.class);
  8. }
  9.  
  10. }

2.开启定时任务

  1. @Component
  2. public class ScheduledService {
  3.  
  4. //每2秒 执行任务
  5. @Scheduled(cron = "0/2 * * * * ?")
  6. public void hello(){
  7. System.out.println("hello.....");
  8. }
  9. }

看结果

注意cron表达式的用法.

6个参数,分别为:秒  分  时   日   月  周

通配符说明:
*:表示匹配该域的任意值。在minutes域使用 * 表示每分钟。在months里表示每个月。在daysOfWeek域表示一周的每一天。
?:只能用在daysofMonth和daysofWeek两个域,表示不指定值,当两个子表达式其中之一被指定了值以后,为了避免冲突,需要将另一个子表达式的值设为 ?。因为daysofMonth和daysofWeek会相互影响。例如想在每月的2号触发调度,不管2号是周几,则只能使用如下写法:0 0 0 2 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管周几都会触发。
-:表示范围。例如在minutes域使用5-20,表示从5分到20分钟每分钟触发一次
/:表示起始时间开始触发,然后每隔固定时间触发一次。例如在minutes域使用5/20,则意味着从当前小时的第5分钟开每20分钟触发一次。
,:表示列出枚举值。例如:在minutes域使用5,20,则意味着在5分和20分时各触发一次。
L:表示最后,是单词“last”的缩写,只能出现在daysofWeek和dayofMonth域。在daysofWeek域使用5L意思是在指定月的最后的一个星期四触发。在dayofMonth域使用5L或者FRIL意思是在指定月的倒数第5天触发。在使用L参数时,不要指定列表或范围。
W:表示有效工作日(周一到周五),只能出现在daysofMonth域,系统将在离指定日期的最近的有效工作日触发事件。例如:在daysofMonth使用5W,如果5号是周六,则将在最近的工作日周五,即4号触发。如果5号是周日,则在6日(周一)触发。如果5日在星期一到星期五中的一天,则就在5日触发。另外,W的最近寻找不会跨过月份 。
LW:这两个字符可以连用,表示指定月的最后一个工作日。
#:用于确定每个月第几个周几,只能出现在daysofMonth域。例如在4#2,表示某月的第二个周三。

常用表达式示例:

例如想在每月的2号触发调度,不管2号是周几,则只能使用如下写法:0 0 0 2 * ?, 其中最后一位只能用?,而不能使用*,如果使用*表示不管周几都会触发

  1. 10/2 * * * * ? 表示每2 执行任务
  2. 10 0/2 * * * ? 表示每2分钟 执行任务
  3. 10 0 2 1 * ? 表示在每月的1日的凌晨2点调整任务
  4. 20 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
  5. 30 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
  6. 40 0 10,14,16 * * ? 每天上午10点,下午2点,4
  7. 50 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
  8. 60 0 12 ? * WED 表示每个星期三中午12
  9. 70 0 12 * * ? 每天中午12点触发
  10. 80 15 10 ? * * 每天上午10:15触发
  11. 90 15 10 * * ? 每天上午10:15触发
  12. 100 15 10 * * ? 每天上午10:15触发
  13. 110 15 10 * * ? 2005 2005年的每天上午10:15触发
  14. 120 * 14 * * ? 在每天下午2点到下午2:59期间的每1分钟触发
  15. 130 0/5 14 * * ? 在每天下午2点到下午2:55期间的每5分钟触发
  16. 140 0/5 14,18 * * ? 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
  17. 150 0-5 14 * * ? 在每天下午2点到下午2:05期间的每1分钟触发
  18. 160 10,44 14 ? 3 WED 每年三月的星期三的下午2:102:44触发
  19. 170 15 10 ? * MON-FRI 周一至周五的上午10:15触发
  20. 180 15 10 15 * ? 每月15日上午10:15触发
  21. 190 15 10 L * ? 每月最后一日的上午10:15触发
  22. 200 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
  23. 210 15 10 ? * 6L 2002-2005 2002年至2005年的每月的最后一个星期五上午10:15触发
  24. 220 15 10 ? * 6#3 每月的第三个星期五上午10:15触发

异步操作

1.启动类开启注解

  1. @EnableAsync //开启异步注解功能
  2. @EnableScheduling //开启基于注解的定时任务
  3. @MapperScan("com.pdzx.dao")
  4. @SpringBootApplication
  5. public class VideoApplication {
  6.  
  7. public static void main(String[] args) {
  8. SpringApplication.run(VideoApplication.class);
  9. }
  10.  
  11. }

2.注解标注异步方法

  1. @Component
  2. public class AsyncService {
  3.  
  4. //告诉Spring这是一个异步方法,SpringBoot就会自己开一个线程池,进行调用!
  5. @Async
  6. public void hello(){
  7. try {
  8. Thread.sleep(10000);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. System.out.println("业务进行中....");
  13. }
  14.  
  15. }

3.控制层测试

  1. @RestController
    public class AsyncController {
  2.  
  3. @Autowired
    AsyncService asyncService;
  4.  
  5. @GetMapping("/async/hello")
    public String hello(){
    long time1 = System.currentTimeMillis();
    asyncService.hello();//调用异步方法
    long time2 = System.currentTimeMillis();
    System.out.println("Controller :"+(time2-time1));
    return "success";
    }
  6.  
  7. }

访问该url,看结果

异步生效了

统一结果返回

封装一个统一的返回类

  1. public class Result<T> {
  2. //是否成功
  3. private Boolean success;
  4. //状态码
  5. private Integer code;
  6. //提示信息
  7. private String msg;
  8. //数据
  9. private T data;
  10. public Result() {
  11.  
  12. }
  13. //自定义返回结果的构造方法
  14. public Result(Boolean success,Integer code, String msg,T data) {
  15. this.success = success;
  16. this.code = code;
  17. this.msg = msg;
  18. this.data = data;
  19. }
  20. //自定义异常返回的结果
  21. public static Result defineError(DefinitionException de){
  22. Result result = new Result();
  23. result.setSuccess(false);
  24. result.setCode(de.getErrorCode());
  25. result.setMsg(de.getErrorMsg());
  26. result.setData(null);
  27. return result;
  28. }
  29. //其他异常处理方法返回的结果
  30. public static Result otherError(ErrorEnum errorEnum){
  31. Result result = new Result();
  32. result.setMsg(errorEnum.getErrorMsg());
  33. result.setCode(errorEnum.getErrorCode());
  34. result.setSuccess(false);
  35. result.setData(null);
  36. return result;
  37. }
  38.  
  39. public Boolean getSuccess() {
  40. return success;
  41. }
  42.  
  43. public void setSuccess(Boolean success) {
  44. this.success = success;
  45. }
  46.  
  47. public Integer getCode() {
  48. return code;
  49. }
  50.  
  51. public void setCode(Integer code) {
  52. this.code = code;
  53. }
  54.  
  55. public String getMsg() {
  56. return msg;
  57. }
  58.  
  59. public void setMsg(String msg) {
  60. this.msg = msg;
  61. }
  62.  
  63. public T getData() {
  64. return data;
  65. }
  66.  
  67. public void setData(T data) {
  68. this.data = data;
  69. }
  70. }

统一异常

  1. public enum ErrorEnum {
  2. // 数据操作错误定义
  3. SUCCESS(200, "nice"),
  4. NO_PERMISSION(403,"你没得权限"),
  5. NO_AUTH(401,"你能不能先登录一下"),
  6. NOT_FOUND(404, "未找到该资源!"),
  7. INTERNAL_SERVER_ERROR(500, "服务器跑路了"),
  8. ;
  9.  
  10. /** 错误码 */
  11. private Integer errorCode;
  12.  
  13. /** 错误信息 */
  14. private String errorMsg;
  15.  
  16. ErrorEnum(Integer errorCode, String errorMsg) {
  17. this.errorCode = errorCode;
  18. this.errorMsg = errorMsg;
  19. }
  20.  
  21. public Integer getErrorCode() {
  22. return errorCode;
  23. }
  24.  
  25. public String getErrorMsg() {
  26. return errorMsg;
  27. }
  28. }

全局异常处理

Springboot对于异常的处理也做了不错的支持,

它提供了一个 @ControllerAdvice注解以及 @ExceptionHandler注解,前者是用来开启全局的异常捕获,后者则是说明捕获哪些异常,对那些异常进行处理。如下

1.自定义异常

  1. public class DefinitionException extends RuntimeException {
  2. protected Integer errorCode;
  3. protected String errorMsg;
  4.  
  5. public DefinitionException(){
  6.  
  7. }
  8. public DefinitionException(Integer errorCode, String errorMsg) {
  9. this.errorCode = errorCode;
  10. this.errorMsg = errorMsg;
  11. }
  12.  
  13. public Integer getErrorCode() {
  14. return errorCode;
  15. }
  16.  
  17. public void setErrorCode(Integer errorCode) {
  18. this.errorCode = errorCode;
  19. }
  20.  
  21. public String getErrorMsg() {
  22. return errorMsg;
  23. }
  24.  
  25. public void setErrorMsg(String errorMsg) {
  26. this.errorMsg = errorMsg;
  27. }
  28. }

2.全局异常处理

  1. @ControllerAdvice
  2. public class GlobalExceptionHandler {
  3.  
  4. /**
  5. * 处理自定义异常
  6. */
  7. @ExceptionHandler(value = DefinitionException.class)
  8. @ResponseBody
  9. public Result bizExceptionHandler(DefinitionException e) {
  10. return Result.defineError(e);
  11. }
  12.  
  13. /**
  14. * 处理其他异常
  15. */
  16. @ExceptionHandler(value = Exception.class)
  17. @ResponseBody
  18. public Result exceptionHandler( Exception e) {
  19. return Result.otherError(ErrorEnum.INTERNAL_SERVER_ERROR);
  20. }
  21. }

测试

  1. @RequestMapping("/getDeException")
  2. public Result DeException(){
  3. throw new DefinitionException(400,"我出错了");
  4. }
  5.  
  6. @RequestMapping("/getException")
  7. public Result Exception(){
  8. Result result = new Result();
  9. int a=1/0;
  10. return result;
  11. }

看结果

首先看自定义异常

看其他异常结果

拦截器

拦截器是在servlet执行之前执行的程序(这里就是controller代码执行之前),它主要是用于拦截用户请求并作相应的处理,比如说可以判断用户是否登录,做相关的日志记录,也可以做权限管理。

SpringBoot中的拦截器实现和spring mvc 中是一样的,

它的大致流程是,先自己定义一个拦截器类,并将这个类实现一个HandlerInterceptor类,或者是继承HandlerInterceptorAdapter,都可以实现拦截器的定义。

然后将自己定义的拦截器注入到适配器中,也有两种方式,一种是实现WebMvcConfigurer接口,一种是继承WebMvcConfigurerAdapter。下面我们来看看如何完成。

1.自定义拦截器

  1. /**
    *
    * 自定义的拦截器可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter类。
    重写三个方法,当然也可以只实现一个最重要的preHandle方法。
    preHandle方法:此方法会在进入controller之前执行,返回Boolean值决定是否执行后续操作。
    postHandle方法:此方法将在controller执行之后执行,但是视图还没有解析,可向ModelAndView中添加数据(前后端不分离的)。
    afterCompletion方法:该方法会在整个请求结束(请求结束,但是并未返回结果给客户端)之后执行, 可获取响应数据及异常信息。
    */
    public class MyInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
    System.out.println("进入拦截器了");
    //中间写逻辑代码,比如判断是否登录成功,失败则返回false
    return true;
    }
  2.  
  3. @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    //
    System.out.println("controller 执行完了");
    }
  4.  
  5. @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    System.out.println("我获取到了一个返回的结果:"+response);
    System.out.println("请求结束了");
    }
    }

2.拦截器注入适配器

  1. @Configuration
  2. public class InterceptorConfig implements WebMvcConfigurer {
  3.  
  4. @Override
  5. public void addInterceptors(InterceptorRegistry registry) {
  6. registry.addInterceptor(new MyInterceptor())
  7. .addPathPatterns("/**")//拦截所有的路径
  8. .excludePathPatterns("/LoginController/*")//配置不需要拦截的路径。
  9. .excludePathPatterns("/hello/login");//配置多个路径。
  10. }
  11. }

3.先创建一个登陆的测试,这个接口是不会拦截的。

  1. @RestController
  2. @RequestMapping("LoginController")
  3. public class Login {
  4.  
  5. @RequestMapping("/login")
  6. public String login(){
  7. System.out.println("controller开始执行");
  8. return "login success";
  9. }
  10.  
  11. }

浏览器测试

  1. http://localhost:5000/pdzx/LoginController/login

看结果

控制台只输出了未拦截接口内的代码,说明这个接口是未拦截的。浏览器的显示就不管了。其实一般是拦截登录接口,这里就将它放开了,以供测试。

4..创建一个拦截的controller

  1. @RestController
  2. @RequestMapping("/hello")
  3. public class HelloController {
  4. @RequestMapping("/hello")
  5. public String hello(){
  6. System.out.println("经过拦截的controller代码执行完毕");
  7. return "hello";
  8. }
  9.  
  10. @RequestMapping("/login")
  11. public String login(){
  12. System.out.println("不拦截的controller代码执行完毕");
  13. return "hello login";
  14. }
  15. }

测试

  1. http://localhost:5000/pdzx/hello/hello

看结果

可以看到,首先是进入了拦截器,

通过拦截器之后,进入了controller中的方法,执行完controller的代码之后就进入了自定义拦截器中的postHandle方法,最后进入afterCompletion方法,并获取到了一个response对象。

事务处理

1.开启事务支持

  1. @EnableTransactionManagement//开启事务支持
  2. @EnableAsync //开启异步注解功能
  3. @EnableScheduling //开启基于注解的定时任务
  4. @MapperScan("com.pdzx.dao")
  5. @SpringBootApplication
  6. public class VideoApplication {
  7.  
  8. public static void main(String[] args) {
  9. SpringApplication.run(VideoApplication.class);
  10. }
  11.  
  12. }

2.@Transactional来修饰一个方法

  1. @Service
  2. public class UserInfoServiceImpl {
  3.  
  4. @Autowired
  5. private UserInfoMapper userInfoMapper;
  6.  
  7. public int insertSelective(UserInfo record) {
  8. return userInfoMapper.insertSelective(record);
  9. }
  10.  
  11. public int updateByPrimaryKeySelective(UserInfo record) {
  12. return userInfoMapper.updateByPrimaryKeySelective(record);
  13. }
  14.  
  15. @Transactional
  16. public void add1(UserInfo record){
  17. userInfoMapper.insertSelective(record);
  18. int i=1/0;
  19. }
  20.  
  21. }

3.controller

  1. @RequestMapping("userInfo")
  2. @RestController
  3. public class UserInfoController {
  4.  
  5. @Autowired
  6. private UserInfoServiceImpl userInfoService;
  7.  
  8. @RequestMapping("/add1")
  9. public void add1(){
  10. UserInfo userInfo=new UserInfo();
  11. userInfo.setName("张三");
  12. userInfoService.add1(userInfo);
  13. }
  14. }

请求该路径之前,看一下数据库

请求该接口

  1. http://localhost:5000/pdzx/userInfo/add1

看结果

看控制台和数据库

数据没进入数据库

我们把那行错误注释掉

  1. @Transactional
  2. public void add1(UserInfo record){
  3. userInfoMapper.insertSelective(record);
  4. //int i=1/0;
  5. }

再试一下,看结果

结果了,可以看出,事务处理生效了.

我们再看一个情况:

不带事务的方法调用该类中带事务的方法,不会回滚。

因为spring的回滚是用过代理模式生成的,如果是一个不带事务的方法调用该类的带事务的方法,直接通过this.xxx()调用,而不生成代理事务,所以事务不起作用

看代码,add2,调用带事务处理的updateByPrimaryKeySelective

  1. @Transactional
  2. public int updateByPrimaryKeySelective(UserInfo userInfo) {
  3. int i=1/0;
  4. userInfo=new UserInfo();
  5. userInfo.setId((long)100);
  6. userInfo.setName("李四");
  7. return userInfoMapper.updateByPrimaryKeySelective(userInfo);
  8. }
  9.  
  10. public void add2(UserInfo record){
  11. userInfoMapper.insertSelective(record);
  12.  
  13. updateByPrimaryKeySelective(record);
  14. }

controller层

  1. @RequestMapping("/add2")
  2. public void add2(){
  3. UserInfo userInfo=new UserInfo();
  4. userInfo.setId((long) 150);
  5. userInfo.setName("张三");
  6. userInfoService.add2(userInfo);
  7. }

测试

  1. http://localhost:5000/pdzx/userInfo/add2

看控制台和数据库

可以看到数据存到数据库了,事物没有生效,这个情况还需注意

springboot实现定时任务,异步操作,统一结果返回,全局异常处理,拦截器及事务处理的更多相关文章

  1. RestFul API 统一格式返回 + 全局异常处理

    一.背景 在分布式.微服务盛行的今天,绝大部分项目都采用的微服务框架,前后端分离方式.前端和后端进行交互,前端按照约定请求URL路径,并传入相关参数,后端服务器接收请求,进行业务处理,返回数据给前端. ...

  2. SpringBoot第五集:整合监听器/过滤器和拦截器(2020最新最易懂)

    SpringBoot第五集:整合监听器/过滤器和拦截器(2020最新最易懂) 在实际开发过程中,经常会碰见一些比如系统启动初始化信息.统计在线人数.在线用户数.过滤敏/高词汇.访问权限控制(URL级别 ...

  3. 小白的springboot之路(十)、全局异常处理

    0.前言 任何系统,我们不会傻傻的在每一个地方进行异常捕获和处理,整个系统一般我们会在一个的地方统一进行异常处理,spring boot全局异常处理很简单: 介绍前先说点题外话,我们现在开发系统,都是 ...

  4. Springboot集成Common模块中的的全局异常处理遇见的问题

    由于项目公共代码需要提取一个common模块,例如对于项目的文件上传,异常处理等,本次集成common代码时候maven引入common的全局异常处理代码之后发现不生效,由于common包路径与自己的 ...

  5. springboot 入门八-自定义配置信息(编码、拦截器、静态资源等)

    若想实际自定义相关配置,只需要继承WebMvcConfigurerAdapter.WebMvcConfigurerAdapter定义些空方法用来重写项目需要用到的WebMvcConfigure实现.具 ...

  6. SpringBoot入坑指南之六:使用过滤器或拦截器

    在Web应用中,常常存在拦截全部或部分请求进行统一处理的应用场景,如权限校验.参数校验.性能监控等. 在SpringMVC框架中,我们可以通过过滤器或拦截器实现相关功能,spring-boot-sta ...

  7. SpringBoot | 第七章:过滤器、监听器、拦截器

    前言 在实际开发过程中,经常会碰见一些比如系统启动初始化信息.统计在线人数.在线用户数.过滤敏高词汇.访问权限控制(URL级别)等业务需求.这些对于业务来说一般上是无关的,业务方是无需关系的,业务只需 ...

  8. Spring Cloud Gateway之全局异常拦截器

    /** * @version 2019/8/14 * @description: 异常拦截器 * @modified: */ @Slf4j public class JsonExceptionHand ...

  9. SpringBoot系列(十一)拦截器与拦截器链的配置与使用详解,你知道多少?

    往期推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件详解 SpringBoot系列(四)web静 ...

随机推荐

  1. RocketMQ 入门

    一.rocketMQ是什么 rocketmq是一款低延迟.高可靠.可伸缩.已使用的消息中间件.具有以下特性: 1.支持发布/订阅.点对点(p2p)消息模型 2.同一个队列中支持先进先出(FIFO)和严 ...

  2. Shell脚本定时监控

    1.建立脚本文件 autostart.sh #!/bin/bashexport JAVA_HOME=/home/java/jdk1.8.0_191export JRE_HOME=$JAVA_HOME/ ...

  3. 减少 zabbix 频繁报警

    一直以来困扰的我问题是,触发器一旦触发,便会猛报警,如果你设置了email ,你的邮箱绝对会爆掉. 今天终于找到了方案,很简单,就是增加action 的steps ,从一个增加到default dur ...

  4. 「雕爷学编程」Arduino动手做(22)——8X8 LED点阵MAX7219屏

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...

  5. clickhouse基本操作一

    常用SQL 创建表 1 2 3 4 5 6 7 CREATE TABLE b6logs( eventDate Date, impid UInt64, uid String, idfa String, ...

  6. JSR303后端校验详细笔记

    目录 JSR303 使用步骤 关于不为空 分组校验 自定义校验 完整代码 JSR303 使用步骤 1.依赖 <!--数据校验--> <dependency> <group ...

  7. context的简单应用

    数据上传 context.setAttribute protected void doGet(HttpServletRequest req, HttpServletResponse resp) thr ...

  8. day08文件的操作(0221)

    #1.文件操作之追加数据01:f = open("yesterday01",'a+U',encoding="utf-8")#a= append,追加之意,w则为 ...

  9. 使用Flutter开发的抖音国际版

    简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额.  两天就基本可以开发个大概出来.   最主要是热更新,太方便实时调整U ...

  10. H3C S5500V2交换机误格式化恢复

    一.格式化后,bin文件及视图全部被删除需要联系H3C客服报交换机后面的序列号,然后根据工单中给你的账号密码去H3C官网下载对应的软件包. 二.下载3CDaemon使用TFTP方式将解压出来的.ipe ...