@ControllerAdvice 全局异常处理
使用@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
Author:LuffyStory
Origin:http://www.cnblogs.com/luffystory/