使用@ControllerAdvice 定义 全局异常处理

package com.app;

import java.io.IOException;
import java.io.PrintWriter; import javax.servlet.http.HttpServletResponse; import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.multipart.MaxUploadSizeExceededException; /**
* ContorllerAdvice 最常见的使用场景是全局异常处理
* 一般搭配 @ExceptionHandler @ModelAttribute 以及 @InitBinder 使用
* 如下是, 当单个文件超出最大size时 对应的自定义处理方法
*
* <p>By default the methods in an {@code @ControllerAdvice} apply globally to
* all Controllers.
*
* spring:
servlet:
multipart:
max-file-size: 50KB
*
*/
@ControllerAdvice
public class CustomExceptionHandler { @ExceptionHandler(MaxUploadSizeExceededException.class)
public void uploadException(MaxUploadSizeExceededException e, HttpServletResponse resp) throws IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("文件大小超出限制!");
out.flush();
out.close();
}
}

当需要将自定义结果写入Response时,有更好的选择:ResponseEntityExceptionHandler( 作为 @ControllerAdvice的基类)

Open Declaration org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler

A convenient base class for @ControllerAdvice classes that wish to provide centralized exception handling across all @RequestMapping methods through @ExceptionHandler methods. 

This base class provides an @ExceptionHandler method for handling internal Spring MVC exceptions. This method returns a ResponseEntity for writing to the response with a message converter, in contrast to DefaultHandlerExceptionResolver which returns a ModelAndView. 

If there is no need to write error content to the response body, or when using view resolution (e.g., via ContentNegotiatingViewResolver), then DefaultHandlerExceptionResolver is good enough. 

如下,在Service中抛出 Exception

package com.app.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import com.app.dao.CityRepository;
import com.app.exceptions.CityNotFoundException;
import com.app.exceptions.NoDataFoundException;
import com.app.model.City; import java.util.List; @Service
public class CityService implements ICityService { @Autowired
private CityRepository cityRepository; @Override
public City findById(Long id) { return cityRepository.findById(id)
.orElseThrow(() -> new CityNotFoundException(id));
} @Override
public City save(City city) { return cityRepository.save(city);
} @Override
public List<City> findAll() { List<City> cities = (List<City>) cityRepository.findAll(); if (cities.isEmpty()) { throw new NoDataFoundException();
} return cities;
} }

并使用ControllerAdvice 标注的类做全局处理:(使用ResponseEntity 返回定制信息以及HttpStatus Code)

package com.app.exceptions;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; @ControllerAdvice
public class ControllerAdvisor extends ResponseEntityExceptionHandler { @ExceptionHandler(CityNotFoundException.class)
public ResponseEntity<Object> handleCityNotFoundException(
CityNotFoundException ex, WebRequest request) { Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", "City not found"); return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
} @ExceptionHandler(NoDataFoundException.class)
public ResponseEntity<Object> handleNodataFoundException(
NoDataFoundException ex, WebRequest request) { Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", "No cities data found"); return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
} @Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
MethodArgumentNotValidException ex, HttpHeaders headers,
HttpStatus status, WebRequest request) { Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDate.now());
body.put("status", status.value()); List<String> errors = ex.getBindingResult()
.getFieldErrors()
.stream()
.map(x -> x.getField() + x.getDefaultMessage())
.collect(Collectors.toList()); body.put("errors", errors); return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
}
}

准备测试数据方法1:

使用MyRunner

package com.app;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component; import com.app.dao.CityRepository;
import com.app.model.City; @Component
public class MyRunner implements CommandLineRunner { private static final Logger logger = LoggerFactory.getLogger(MyRunner.class); @Autowired
private CityRepository cityRepository; @Override
public void run(String... args) throws Exception { logger.info("Saving cities"); cityRepository.save(new City("Bratislava", 432000));
cityRepository.save(new City("Budapest", 1759000));
cityRepository.save(new City("Prague", 1280000));
cityRepository.save(new City("Warsaw", 1748000));
cityRepository.save(new City("Los Angeles", 3971000));
cityRepository.save(new City("New York", 8550000));
cityRepository.save(new City("Edinburgh", 464000));
cityRepository.save(new City("Suzhou", 4327066));
cityRepository.save(new City("Zhengzhou", 4122087));
cityRepository.save(new City("Berlin", 3671000));
}
}

MyRunner 类会在项目启动之后执行:

准备测试数据方法2:

在src/main/resource 下 create 一个 data.sql ,如下:

INSERT INTO cities(name, population) values('Hello',100);
INSERT INTO cities(name, population) values('World',200);

发生异常时的返回值:

Reference:http://zetcode.com/springboot/controlleradvice/

Code: https://github.com/XLuffyStory/SpringBootStudy/tree/master/springboot-controlleradvice

@ControllerAdvice 全局异常处理的更多相关文章

  1. @ControllerAdvice全局异常处理不起作用原因及解决办法

    这段时间使用springboot搭建基础框架,作为springboot新手,各种问题都有. 当把前端框架搭建进来时,针对所有controller层的请求,所发生的异常,需要有一个统一的异常处理,然后返 ...

  2. 014-Spring Boot web【三】拦截器HandlerInterceptor、异常处理页面,全局异常处理ControllerAdvice

    一.拦截器HandlerInterceptor 1.1.HandlerInterceptor接口说明 preHandle,congtroller执行前,如果返回false请求终端 postHandle ...

  3. Spring中通过java的@Valid注解和@ControllerAdvice实现全局异常处理。

    通过java原生的@Valid注解和spring的@ControllerAdvice和@ExceptionHandler实现全局异常处理的方法: controller中加入@Valid注解: @Req ...

  4. springmvc全局异常处理ControllerAdvice区分返回响应类型是页面还是JSON

    思路: 加一个拦截器,在preHandler中取得HandlerMethod,判断其方法的返回类型,以及方法的注解和类的注解. 如果返回是json,收到异常则返回默认的异常包装类型. 如果返回是页面, ...

  5. 《Spring全局异常处理》从零掌握@ControllerAdvice注解

    一.开门见山 在前后端分离框架的大趋势下,前后端基本的职责已经确定. 前端主要负责界面的处理以及基本的判空检验.数据来源则通过vue调用后端发布的接口. 后端的原型还是mvc的模式: controll ...

  6. Spring Boot 全局异常处理

    Spring Boot版本 1.5 @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExcept ...

  7. SpringBoot整合全局异常处理&SpringBoot整合定时任务Task&SpringBoot整合异步任务

    ============整合全局异常=========== 1.整合web访问的全局异常 如果不做全局异常处理直接访问如果报错,页面会报错500错误,对于界面的显示非常不友好,因此需要做处理. 全局异 ...

  8. Spring 全局异常处理

    [参考文章]:Spring全局异常处理的三种方式 [参考文章]:Spring Boot 系列(八)@ControllerAdvice 拦截异常并统一处理 [参考文章]:@ControllerAdvic ...

  9. springBoot注解大全JPA注解springMVC相关注解全局异常处理

    https://www.cnblogs.com/tanwei81/p/6814022.html 一.注解(annotations)列表 @SpringBootApplication:包含了@Compo ...

随机推荐

  1. 可能是把 Java 内存区域讲的最清楚的一篇文章

    出处:  可能是把 Java 内存区域讲的最清楚的一篇文章 Java 内存区域详解 写在前面 (常见面试题) 基本问题 拓展问题 一 概述 二 运行时数据区域 2.1 程序计数器 2.2 Java 虚 ...

  2. springboot拦截中自动注入的组件为null问题解决方法

    一.写SpringUtil类来获取Springh管理的类实例,判断是否注入成功,如果没有注入成功重新获取注入 package com.util; import org.springframework. ...

  3. luogu P4482 [BJWC2018]Border 的四种求法

    luogu 对于每个询问从大到小枚举长度,哈希判断是否合法,AC 假的(指数据) 考虑发掘border的限制条件,如果一个border的前缀部分的末尾位置位置\(x(l\le x < r)\)满 ...

  4. CentOS7部署kettle

    去官网下载kettle, 或者百度网盘下载(nnnk),解压到目录/opt/service/, 解压后的目录是data-integration kettle需要java环境才能运行,因此要安装Java ...

  5. js之运算符(算术运算符)

    Javascript中的运算符大多是由标点符号少数由关键字表示.可以根据其操作数的个数进行分类.大多数运算符是一个二元运算符,将两个表达式合成一个比较复杂的表达式.还有需要注意的一点是运算符的优先级, ...

  6. 第五篇 CSS入门 明白 三种嵌套形式,三种常用控制器

    CSS入门 css是 层叠式样式表   css的作用是什么呢?举个抽象的例子啊,HTML是人,CSS则是衣服...   css给html穿上衣服,有三种形式: 内嵌.内联.外联. 这三种形式,优先级为 ...

  7. SQL-Serverの自動採番(IDENTITY値)の取得・リセット

    システムに必要なテーブルで.自動的に番号を振っていくものが必要なときがあります. たとえば.各種の伝票データの伝票番号の様なものです. プログラム処理上.データを登録した直後に.自動採番された値を取得 ...

  8. css 规范标签

    页头:header 登录条:loginBar 标志:logo 侧栏:sideBar 广告:banner 导航:nav 子导航:subNav 菜单:menu 子菜单:subMenu 搜索:search ...

  9. CentOS 7.x and RHEL 7.x Install qemu-kvm

    ref: https://www.linuxtechi.com/install-kvm-hypervisor-on-centos-7-and-rhel-7/        https://www.th ...

  10. maven中使用jetty插件

    <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>jetty-maven-plugin ...