zoukankan      html  css  js  c++  java
  • @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

  • 相关阅读:
    注册页面
    JDBC操作MySQL数据
    音乐播放页面控制
    mysql知识点
    国内第一篇详细讲解hadoop2的automatic HA+Federation+Yarn配置的教程
    让自己变得更有钱
    看视频也能拿到月薪1万
    超人学院二期学员分享hadoop工作经验
    2013年吴超的个人总结
    国内最全最详细的hadoop2.2.0集群的MapReduce的最简单配置
  • 原文地址:https://www.cnblogs.com/luffystory/p/12010494.html
Copyright © 2011-2022 走看看