学习springboot的旅程,就像蜗牛爬山,一点点的往上爬,一点点的欣赏旅途的风景
继续上一章的问题,在前后分离或不分离的情况下,要怎么管理和处理全局异常?
首先什么异常,简单说就是系统运行过程中的报错!
系统运行过程中的报错可分为哪些?(个人理解)
- 由请求触发
- 非请求触发的(例如定时任务等)–此类异常通常手动捕获或日志处理
由请求触发的异常可分为哪些?(个人理解)
- 第一种:业务逻辑处理的异常,io流异常/空指针/数组下标越界/类型转换异常等,是在业务层面的异常,是进入Controller层之后的异常
- 第二种:非业务逻辑处理的异常,404,是进入Controller层之前的异常
请求的类型(个人理解)
- 非跨域视图请求
- 非跨域数据请求(ajax)
- 跨域视图请求
- 跨域数据请求(ajax)
springboot对于进入Controller层之前的异常:是有springboot自己的视图实现(也就是对于404的异常,springboot有自己的展示视图)–此处要另外处理!
引入Controller功能增强标签(作为知识点补充积累)
- 先引入4个标签:@ControllerAdvice、@ExceptionHandler、@InitBinder、@ModelAttribute
- @ControllerAdvice:是SpringMvc引入的新注解,是用来增强Controller的
- 后三个是配套子标签,分别对应:全局异常处理、全局数据预处理、全局数据绑定
@RestController
@ControllerAdvice
public class ControllerAdviceTest {
/**
* 全局数据绑定:就是进入所有controller层,且@RequestMapping修饰方法前,
* 可以通过Model 先绑定全局数据,供@RequestMapping修饰方法调用和使用。
* 1-把这个map放入Model model
* 2-同时把Model model作为参数传入所有@RequestMapping注解方法
*/
@ModelAttribute(name = "md") //md是放入model的key
public Map<String, Object> ModelAttribute() {
HashMap<String, Object> map = new HashMap<>();
map.put("test", "test");
return map;
}
/**
* Model 使用的例子
*/
@RequestMapping("/test")
public String test(Model model) {
System.out.println(model.get("md"));
}
//----------------------------------------------------------------------------------
/**
* 预处理前端传回的参数,比如:两个实体Book,User,都有相同的属性名name
* 前端传参数:a.name=a&b.name=b
*/
@InitBinder("b")
public void b(WebDataBinder binder) {
binder.setFieldDefaultPrefix("b.");
}
@InitBinder("a")
public void a(WebDataBinder binder) {
binder.setFieldDefaultPrefix("a.");
}
@RequestMapping("/test")
public void test(@ModelAttribute("b") Book book, @ModelAttribute("a") User user) {
}
//----------------------------------------------------------------------------------
/**
* 所有controller层@RequestMapping修饰方法 抛出的异常都会进下面的方法。
* 但是404不进下面方法,404是进入controller前的异常
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public String processUnauthenticatedException(HttpServletRequest request, Exception e) {
return "viewName"; //返回一个逻辑视图名
}
}
spring boot全局异常处理(开始正文)
- 进入Controller层之后的异常处理–404除外
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* 全局异常处理类(除404外)
*/
@ControllerAdvice
public class GlobalExceptionHandler{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 无论什么错误都跳转页,除非ajax
* @param e
* @return
*/
@ResponseBody
@ExceptionHandler(value = Exception.class)
public ModelAndView exceptionHandler(HttpServletRequest request, HttpServletResponse response,Exception e){
Map<String,Object> model = new HashMap<String,Object>();
model.put("code",500);
model.put("msg","后台打盹了,程序猿该起床干活啦!!!");
//发生异常进行日志记录,写入数据库或者其他处理,此处省略
logger.error("后台发生错误",e);
/*System.out.println("开始抓异常咯====》》》");
for(StackTraceElement se:e.getStackTrace()) {
System.out.println("捕获了异常==》"+se.toString());
}
System.out.println("异常都抓完咯====》》》");*/
//当ajax请求时
if(isAjax(request,response)){
response.setHeader("Cache-Control", "no-store");
response.setCharacterEncoding("UTF-8");
model.put("success","true");
PrintWriter pw = null;
try {
pw=response.getWriter();
pw.write(JSONObject.toJSON(model).toString());
pw.flush();
} catch (IOException ee) {
ee.printStackTrace();
}finally{
pw.close();
}
ModelAndView mv=new ModelAndView();
mv.clear();
return mv;
}
return new ModelAndView("com/error/404", model);
}
/**
* 判断是否ajax(是否跨域请求)
* @param request
* @param response
* @return
*/
public boolean isAjax(HttpServletRequest request, HttpServletResponse response) {
if (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals(request.getHeader("X-Requested-With"))) {//非跨域的ajax
return (true);
}
if (request.getHeader("referer") != null && !"".equals(request.getHeader("referer"))){//跨域的ajax
return (true);
}
return (false);
}
}
- (404/找不到请求/找不到文件js/css)等异常处理
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.error.ErrorController;
@Controller
public class NotFoundException implements ErrorController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public String getErrorPath() {
return "/error";
}
@RequestMapping(value = {"/error"})
@ResponseBody
public ModelAndView error(HttpServletRequest request) {
Map<String,Object> model = new HashMap<String,Object>();
model.put("code",404);
model.put("mag","请查看你请求的路径或文件是否存在,或者请求的路径是否正确");
//System.out.println(request.getRequestURL()+"真的404==》请查看你请求的路径或文件是否存在,或者请求的路径是否正确!!!");
//发生异常进行日志记录,写入数据库或者其他处理,此处省略
logger.error("请求异常","请求的文件或者路径真的404!!!");
return new ModelAndView("com/error/404", model);
}
}
至此springboot整合全局异常就OK了。亲测可用,同嫂无欺!!! 下面开始要干嘛呢??是不是要考虑日志管理呢,昨晚日日夜夜都在挖坑的我,日志的管理是必须的!!