目录



  • 自定义错误页
  • CORS支持(前端跨域请求)
  • 拦截器HandlerInterceptor
  • 启动系统任务
  • springboot配置AOP
  • 整合servlet、filter、listener

 下图为本节内容

 

springboot insert错误 springboot internal server error_spring

springboot insert错误 springboot internal server error_ide_02

1、自定义错误页

springboot中默认错误是由BasicErrorController类来处理的,该类核心方法有errorHtml(返回Html),error(返回json),DefaultErrorViewResolver是Springboot默认错误解析器。该类源码中可以看出4xx、5xx文件作为错误视图,找不到会回到errorHtml方法中,使用error作为默认的错误页面视图。

1)、自定义Error数据

BasicErrorController的errorHtml、error都是通过getErrorAttributes方法获取error信息。该方法会调用DefaultErrorAttributes类的getErrorAttributes方法,而DefaultErrorAttributes类是在ErrorMvcAutoCongfigutration默认提供的。

@Bean
@ConditionalOnMissingBean(
    value = {ErrorAttributes.class},
    search = SearchStrategy.CURRENT
)
public DefaultErrorAttributes errorAttributes() {
    return new DefaultErrorAttributes(this.serverProperties.getError().isIncludeException());
}

从这段源码可以看出,当系统没有听过ErrorAttributes时才会采用DefaultErrorAttributes,因此自定义错误时,只需要自己提供一个ErrorAttributes。

@Component
public class MyErrorAttribute extends DefaultErrorAttributes {


    @Override
    public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
        Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, includeStackTrace);
        errorAttributes.put("custommsg","出错了");
        errorAttributes.remove("error");
        return errorAttributes;
    }
}

 

2)、自定义error视图

BasicErrorController的errorHtml方法中调用resolveErrorView方法获取一个ModelAndView实例。resolveErrorView是由ErrorViewResolver提供的。

@Bean
@ConditionalOnBean({DispatcherServlet.class})
@ConditionalOnMissingBean
public DefaultErrorViewResolver conventionErrorViewResolver() {
    return new DefaultErrorViewResolver(this.applicationContext, this.resourceProperties);
}

 

 想要自定义自己的视图,只需要提供自己的ErrorViewResolver

@Component
public class MyErrorViewResolver implements ErrorViewResolver {
    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request, HttpStatus status, Map<String, Object> model) {
        ModelAndView modelAndView = new ModelAndView("errorPage");
        modelAndView.addObject("custommsg","出错了");
        modelAndView.addAllObjects(model);
        return modelAndView;
    }
}

 3)、自定义视图和自定义数据

查看Error自动化配置类ErrorMvcAutoConfiguration,BasicErrorController是一个默认的配置。

@Bean
@ConditionalOnMissingBean(
    value = {ErrorController.class},
    search = SearchStrategy.CURRENT
)
public BasicErrorController basicErrorController(ErrorAttributes errorAttributes) {
    return new BasicErrorController(errorAttributes, this.serverProperties.getError(), this.errorViewResolvers);
}

 

从这段源码可以看到,如果没有提供自己的ErrorController,则springboot提供BasicErrorController作为默认的ErrorController。

@Controller
public class MyErrorController extends BasicErrorController {
    public MyErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties,
                             List<ErrorViewResolver> errorViewResolvers) {
        super(errorAttributes,serverProperties.getError(),errorViewResolvers);
    }

    @Override
    public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
        HttpStatus status = getStatus(request);
        Map<String, Object> model =
                getErrorAttributes(request, isIncludeStackTrace(request, MediaType.TEXT_HTML));
        model.put("custommsg","出错了");
        ModelAndView modelAndView = new ModelAndView("myErrorPage",model,status);
        return modelAndView;
    }

    @Override
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        Map<String, Object> errorAttributes = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL));
        errorAttributes.put("custommsg","出错了");
        HttpStatus status = getStatus(request);
        return  new ResponseEntity<>(errorAttributes,status);
    }
}

 2、CORS支持(前端跨域请求)

配置跨域可以在方法上加注解、全局配置。

在方法上加注解

@PostMapping("/book")
@CrossOrigin(value = "http://localhost:8081",maxAge = 1800,allowedHeaders = "*")
public String addBook(String name) {
    return "receive:" + name;
}

全局配置

//跨域全局配置
@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/book/**")
            .allowedHeaders("*")
            .allowedMethods("*")
            .maxAge(1800)
            .allowedOrigins("http://localhost:8081");
}

 

 3、拦截器HandlerInterceptor

配置拦截器,定义配置类进行拦截器的配置

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new MyInterceptor())
            .addPathPatterns("/**")
            .excludePathPatterns("/static/**");
}

 4、启动系统任务

1)、CommandLineRunner

/**
 * CommandLineRunner 系统启动时加载参数
 * @author shuliangzhao
 * @Title: MyCommandLineRunner
 * @ProjectName spring-boot-learn
 * @Description: TODO
 * @date 2019/7/21 12:34
 */
@Component
@Order(1)
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("Runner>>>" + Arrays.toString(args));
    }
}

2)、ApplicationRunner

/**
 * --name = zhangsan getOptionNames getOptionValues
 * 路遥 平凡的世界 getNonOptionArgs取值
 * @author shuliangzhao
 * @Title: MyApplicationRunner
 * @ProjectName spring-boot-learn
 * @Description: TODO
 * @date 2019/7/21 12:36
 */
@Component
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<String> nonOptionArgs = args.getNonOptionArgs();
        System.out.println("nonOptionArgs>>>" + nonOptionArgs);
        Set<String> optionNames = args.getOptionNames();
        for (String optionName:optionNames) {
            System.out.println("key:" + optionName + ";value:" + args.getOptionValues(optionName));
        }
    }
}

 5、springboot配置AOP

Joinpoint:连接点,类里面可以被增强的方法即为连接点,例如想修改哪个方法的功能,那么这个方法即为连接点
Pointcut:切入点,对于Joinpoint进行拦截的定义即为切入点,例如拦截所有的insert
Advice:通知,拦截到Joinpoint之后所要做的事就是通知,
Aspect:切面,Pointcut和Advice的结合
Target:目标对象,要增强类为target
@Component
@Aspect
public class LogAspect {


@Pointcut("execution(* com.sl.service.*.*(..))")
    public void pc() {
    }


@Before(value = "pc()")
    public void before(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法开始执行...");
    }



@After(value = "pc()")
    public void after(JoinPoint jp) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法执行结束...");
    }



@AfterReturning(value = "pc()",returning = "result")
    public void afterReturning(JoinPoint jp,Object result) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法返回值为:" + result);
    }



@AfterThrowing(value = "pc()",throwing = "e")
    public void afterThrowing(JoinPoint jp,Exception e) {
        String name = jp.getSignature().getName();
        System.out.println(name + "方法抛出异常,异常时:" + e);
    }



@Around("pc()")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        return pj.proceed();
    }
}

 6、整合servlet、filter、listener

以servle为例,需要在启动类上加上@ServletComponentScan

@WebServlet
public class MyHttpServlet extends HttpServlet {


@Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("name>>>" + req.getParameter("name"));
    }



@Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doGet(req, resp);
    }
}