============整合全局异常===========
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注解查看结果:
前台:
后台:(单条线程执行)
|