============整合全局异常===========
1.整合web访问的全局异常
如果不做全局异常处理直接访问如果报错,页面会报错500错误,对于界面的显示非常不友好,因此需要做处理。
全局异常处理的类:
package cn.qlq.ExceptionHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.servlet.ModelAndView; @ControllerAdvice public class WebExceptionHandler { public static final String ERROR_VIEW = "error"; @ExceptionHandler(value = Exception.class) public Object errorHandler(HttpServletRequest reqest, HttpServletResponse response, Exception e) throws Exception { e.printStackTrace(); ModelAndView mav = new ModelAndView(); mav.addObject("exception", e); mav.addObject("url", reqest.getRequestURL()); mav.setViewName(ERROR_VIEW); return mav; } }
拦截到异常之后会跳转到error页面error.html:
目录结构:
内容如下:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8" /> <title>捕获全局异常</title> </head> <body> <h1 style="color: red">发生错误:</h1> <div th:text="${url}"></div> <div th:text="${exception.message}"></div> </body> </html>
测试:
2.整合ajax全局异常处理
ajax异常处理就是捕捉到异常之后返回一个封装的JSON实体,ajax请求根据返回的状态判断是否请求成功。
封装的工具类:
package cn.qlq.utils; import java.io.Serializable; public class JSONResultUtil<T> implements Serializable { private static final long serialVersionUID = 3637122497350396679L; private boolean success; private T data; private String msg; public boolean isSuccess() { return success; } public void setSuccess(boolean success) { this.success = success; } public T getData() { return data; } public void setData(T data) { this.data = data; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public JSONResultUtil(boolean success) { this.success = success; } public JSONResultUtil(boolean success, String msg) { super(); this.success = success; this.msg = msg; } public JSONResultUtil(boolean success, T data, String msg) { super(); this.success = success; this.data = data; this.msg = msg; } /** * 返回正确结果不带数据 * * @return */ public static JSONResultUtil ok() { return new JSONResultUtil(true); } /** * 返回错误的结果带错误信息 * * @param msg * @return */ public static JSONResultUtil error(String msg) { return new JSONResultUtil(false, msg); } }
Ajax请求的错误处理器:
package cn.qlq.ExceptionHandler; import javax.servlet.http.HttpServletRequest; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import cn.qlq.utils.JSONResultUtil; @RestControllerAdvice public class AjaxExceptionHandler { @ExceptionHandler(value = Exception.class) public JSONResultUtil defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception { e.printStackTrace(); return JSONResultUtil.error(e.getMessage()); } }
测试:
前台JS:
$.ajax({ url: "/MySpringboot/err/getAjaxerror", type: "POST", async: false, success: function(data) { if(data.success) { alert("success"); } else { alert("发生异常:" + data.msg); } }, error: function (response, ajaxOptions, thrownError) { alert("error"); } });
后台制造除零异常:
@RequestMapping("/getAjaxerror") @ResponseBody public JSONResultUtil getAjaxerror() { int a = 1 / 0; return JSONResultUtil.ok(); }
结果:
3.一个通用的全局异常处理器
不管是web请求还是ajax请求都可以用它处理。内部根据是否是ajax请求返回对应的数据
package cn.qlq.ExceptionHandler; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.servlet.ModelAndView; import cn.qlq.utils.JSONResultUtil; @RestControllerAdvice public class MyExceptionHandler { public static final String ERROR_VIEW = "error"; @ExceptionHandler(value = Exception.class) public Object errorHandler(HttpServletRequest reqest, HttpServletResponse response, Exception e) throws Exception { e.printStackTrace(); if (isAjax(reqest)) { return JSONResultUtil.error(e.getMessage()); } else { ModelAndView mav = new ModelAndView(); mav.addObject("exception", e); mav.addObject("url", reqest.getRequestURL()); mav.setViewName(ERROR_VIEW); return mav; } } /** * 根据请求头是否携带X-Requested-With参数判断是否是ajax请求 * * @param httpRequest * @return */ public static boolean isAjax(HttpServletRequest httpRequest) { return (httpRequest.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(httpRequest.getHeader("X-Requested-With").toString())); } }
============整合定时任务Task===========
在springmvc使用的时候使用到的定时任务一般是quartz,也研究过使用过SpringTask。SpringBoot整合Task非常简单。
(1)@EnableScheduling开启task
package cn.qlq.config; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration // 通过该注解来表明该类是一个Spring的配置,相当于一个xml文件 @EnableScheduling public class SpringTask { }
(2)通过注解的方式使用task即可。
package cn.qlq.task; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class FirstAnnotationJob { private static int count; @Scheduled(fixedRate = 10000) public void cron() { try { Thread.sleep(2000); } catch (InterruptedException e) { System.err.println("InterruptedException " + e); } System.out.println("spring anno task execute times " + count++); } }
结果:
spring anno task execute times 0
spring anno task execute times 1
spring anno task execute times 2
....
关于springTask的使用参考:https://www.cnblogs.com/qlqwjy/p/9960706.html
============整合异步任务===========
开启异步任务的方式比较简单 。异步任务的使用场景是:发布消息、发送短信等一些异步任务上,当然异步可以用线程池实现,发送消息可以用MQ框架实现。
(1)@EnableAsync声明开启异步任务
package cn.qlq.config; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @Configuration // 通过该注解来表明该类是一个Spring的配置,相当于一个xml文件 //开启Task @EnableScheduling //开启异步调用方法 @EnableAsync public class SpringTask { }
(2)编写异步任务,@Component注入spring,异步的方法加上@Async注解即可
package cn.qlq.task; import java.util.concurrent.Future; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.AsyncResult; import org.springframework.stereotype.Component; @Component public class AsyncTask { @Async public Future<Boolean> doTask11() throws Exception { long start = System.currentTimeMillis(); Thread.sleep(1000); long end = System.currentTimeMillis(); System.out.println("任务1耗时:" + (end - start) + "毫秒,线程名字:" + Thread.currentThread().getName()); return new AsyncResult<>(true); } @Async public Future<Boolean> doTask22() throws Exception { long start = System.currentTimeMillis(); Thread.sleep(700); long end = System.currentTimeMillis(); System.out.println("任务2耗时:" + (end - start) + "毫秒,线程名字:" + Thread.currentThread().getName()); return new AsyncResult<>(true); } @Async public Future<Boolean> doTask33() throws Exception { long start = System.currentTimeMillis(); Thread.sleep(600); long end = System.currentTimeMillis(); System.out.println("任务3耗时:" + (end - start) + "毫秒,线程名字:" + Thread.currentThread().getName()); return new AsyncResult<>(true); } }
(3)Controller层调用异步方法:
package cn.qlq.action; import java.util.concurrent.Future; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import cn.qlq.task.AsyncTask; @RestController @RequestMapping("tasks") public class AsyncTaskController { @Autowired private AsyncTask asyncTask; @RequestMapping("test1") public String test1() throws Exception { long start = System.currentTimeMillis(); Future<Boolean> a = asyncTask.doTask11(); Future<Boolean> b = asyncTask.doTask22(); Future<Boolean> c = asyncTask.doTask33(); while (!a.isDone() || !b.isDone() || !c.isDone()) { if (a.isDone() && b.isDone() && c.isDone()) { break; } } long end = System.currentTimeMillis(); String times = "任务全部完成,总耗时:" + (end - start) + "毫秒"; System.out.println(times); return times; } }
上面执行asyncTask.doTaskXX的时候是异步执行的,相当于三个方法异步执行,下面的while循环直到三个方法都执行完毕。
测试:
前台访问:
后台控制台:(发现是通过多线程执行)
如果去掉上面三个异步方法的@Async注解查看结果:
前台:
后台:(单条线程执行)