============整合全局異常===========
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注解查看結果:
前台:
后台:(單條線程執行)