SpringBoot 扩展对SpringMVC的默认配置(拦截器等)

SpringBoot 默认已经做了很多SpringMVC的默认配置:

1、视图解析器ViewResolver

2、静态资料的目录

3、默认首页index.html

4、图标名字和图标所在目录,favicon.ico

5、类型转换器Converter,格式转换器的Formatter

6、消息转换器HttpMessageConverters,我们直接向页面返回JSON格式的数据就靠它实现

7、消息代码解析器MessageCodesResolver, 作用配置了错误代码显示规则的一些东西,JSR303数据校验要用到它

 

在项目开发中,这些默认配置是绝对不够用的,所以,必须在它们的基础上扩展更多我们需要的配置。

SpringBoot 提供了相应扩展接口WebMvcConfigurer,在SpringBoot的配置类上实现它并加上@Configuretion注解就可以了

  

 

一、addViewControllers 的使用

       在之前使用SpringMVC时,可以在springmvc.xml配置文件中直接配置路径映射。

<mvc:view-controller path="/index" view-name="index"/>

       如果模板页面只是动态渲染,不需要后台的数据,那个我们就可以配置路径映射。这样就不需要在controller类里写映射方法返回页面。比如:欢迎页面,路径映射或者controller或者静态index方式实现,只是动态动态渲染,路径映射方式更好。

       在SpringBoot 中创建配置类,实现接口WebMvcConfigurer

@Configuration
public class AddMvcConfig implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/index") // 访问的路径
                .setViewName("index");     // 视图名
        registry.addViewController("/hello").setViewName("hello");
    }
}

    index.html 简单展示下:

     

注意:

     1)关于扩展,有一个特殊的注解 @EnableWebMvc ,它的作用是全面接管SpringMvc的配置,也就是说SpringBoot的所有关于SpringMvc的自动配置都会失效(包括静态资源页的访问等等),而只有我们自己做的配置才会生效,所以什么都需要我们自己手动配置所有的类。

    2)官方解释:

       如果要保留Spring Boot MVC功能,并且要添加其他MVC配置(拦截器、格式化程序、视图控制器和其他功能),可以添加自己的@configuration类(类型为webmvcconfigurer),但不添加@enableWebMVC。如果要提供RequestMappingHandlerMapping、RequestMappingHandlerAdapter或ExceptionHandlerExceptionResolver的自定义实例,可以声明WebMVCregistrationsAdapter实例以提供此类组件。

      如果要完全控制SpringMVC,可以添加自己的@configuration,并用@enableWebMVC注释。

   3)Springboot提供了大量的自动配置,如果项目不想使用它的自动配置,可以可以在启动类上使用exclude排除。一般没必要排除。

@SpringBootApplication(exclude = {WebMvcAutoConfiguration.class, DataSourceAutoConfiguration.class})

 

二、addInterceptors 的拦截器使用

   1)在配置类中添加 拦截器配置

@Configuration
public class WebConfig implements WebMvcConfigurer {
    /**
     *  配置拦截器
     * @param registry
     */
   @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/", "/index");
    }
}

   2)创建拦截器实现类

public class LoginInterceptors extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle 方法。。。");
        return super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle 方法。。。");
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                Exception ex) throws Exception {
        System.out.println("afterCompletion 方法。。。");
        super.afterCompletion(request, response, handler, ex);
    }

    @Override
    public void afterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response,
                                               Object handler) throws Exception {
        System.out.println("afterConcurrentHandlingStarted 方法。。。");
        super.afterConcurrentHandlingStarted(request, response, handler);
    }
}

preHandle:预处理回调方法,实现处理器的预处理(如登录检查),第三个参数为响应的处理器返回值:true表示继续流程(如调用下一个拦截器或处理器);false表示流程中断(如登录检查失败),不会继续调用其他的拦截器或处理器,此时我们需要通过response来产生响应。

postHandle:后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时我们可以通过modelAndView(模型和视图对象)对模型数据进行处理或对视图进行处理,modelAndView也可能为null。

afterCompletion:整个请求处理完毕回调方法,即在视图渲染完毕时回调,如性能监控中我们可以在此记录结束时间并输出消耗时间,还可以进行一些资源清理,类似于try-catch-finally中的finally,但仅调用处理器执行链中preHandle返回true的拦截器才会执行。

  3)访问url 接口拦截:

  

三、自定义数据转换器

传送门:springmvc自定义数据转换器

Springboot项目中,这里定义字符串日期转换为Date转换器,全局的配置。

@Component
public class StringToDateConverter implements Converter<String, Date> {
    // 这里约定日期时间格式为:yyyy-MM-dd HH:mm:ss
    private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    private static final String DATE_FORMAT = "yyyy-MM-dd";
    private final String DATE_REG = "^\\d+$";

    @Override
    public Date convert(String value) {
        if (StringUtils.isBlank(value)) {
            return null;
        }
        value = value.trim();
        try {
            if (value.contains("-")) {
                SimpleDateFormat format;
                if (value.contains(":")) {
                    // 表示传入的是日期时间
                    format = new SimpleDateFormat(DATETIME_FORMAT);
                } else {
                    // 表示传入的是日期
                    format = new SimpleDateFormat(DATE_FORMAT);
                }
                return format.parse(value);
            } else if (value.matches(DATE_REG)) {
                // 表示传入的是时间戳
                Long lDate = new Long(value);
                return new Date(lDate);
            }
        } catch (Exception e) {
            throw new RuntimeException(String.format("parse %s to Date fail", value));
        }
        return null;
    }

controller中

    @GetMapping("/stringToDate")
    @ResponseBody
    public User stringToDate(User user){
        return user;
    }
// http://127.0.0.1:8080/stringToDate?id=5&name=李四&birthday=2018-10-22

如果不使用全局配置,对每个pojo,可以使用注解单独配置,这里使用的是jackson组件

    @JsonFormat(shape = JsonFormat.Shape.STRING, timezone = "GMT+8", pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    @JsonSerialize(using = DateSerializer.class)
    private Date birthday;

四、SpringBoot定义系统启动任务

如果想在项目启动阶段需要做一些数据初始化的操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行。

在Servlet项目中,会想到web基础中的三大组件( Servlet、Filter、Listener )中的 Listener 处理,一般定义一个 ServletContextListener,然后就可以监听到项目启动和销毁,进而做出相应的数据初始化和销毁操作。比如:

public class MyListener implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("服务器启动时触发,可以做数据初始化等操作");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("服务器关闭时触发,可以做数据备份等操作");
    }
}

@Configuration
public class WebConfig {

    @Bean
    public ServletListenerRegistrationBean myListernerBean(){
        return new ServletListenerRegistrationBean(new MyListener());
    }
}

在 SpringBoot项目中,使用更为简便。Spring Boot 中针对系统启动任务提供了两种解决方案,分别是 CommandLineRunner 和 ApplicationRunner。两者用法基本一致,主要体现在对参数的处理上,可以根据项目中的实际情况选择合适的解决方案。

1、方式一:CommandLineRunner

使用 CommandLineRunner时,需要注意:这里参数传递时没有key,直接写value即可。

自定义 MyCommandLineRunner 类并实现 CommandLineRunner 接口即可。

@Component
@Order(999)
public class MyCommandLineRunner implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println(Arrays.toString(args));
    }
}
  • @Compoent 注解将 MyCommandLineRunner1 注册为Spring容器中的一个 Bean。
  • @Order注解,表示这个启动任务的执行优先级,因为在一个项目中,启动任务可能有多个,所以需要有一个排序。@Order 注解中,数字越小,优先级越大,默认情况下,优先级的值为 Integer.MAX_VALUE,表示优先级最低。
  • 在 run 方法中,写启动任务的核心逻辑,当项目启动时,run方法会被自动执行。
  • run 方法的参数,来自于项目的启动参数,即项目入口类中。启动类中main方法的参数会被传到这里。

当项目启动时,这里的 run 方法就会被自动执行。

如果在 IDEA 中,我们可以通过如下方式来传入参数:

如果将项目打包,在命令行中启动项目,可以在启动时的命令行后面传入参数:

2、方式二:ApplicationRunner

ApplicationRunner 可以接收更多类型的参数(ApplicationRunner 除了可以接收 CommandLineRunner 的参数之外,还可以接收 key/value形式的参数)。

自定义 MyApplicationRunner类并实现 ApplicationRunner 接口即可。

@Component
@Order(1000)
public class MyApplicationRunner implements ApplicationRunner {
    @Override
    public void run(ApplicationArguments args) throws Exception {
        List<String> nonOptionArgs = args.getNonOptionArgs();
        System.out.println("nonOptionArgs==" + nonOptionArgs);

        String[] sourceArgs = args.getSourceArgs();
        System.out.println("sourceArgs==" + Arrays.toString(sourceArgs));

        Set<String> optionNames = args.getOptionNames();
        for (String optionName : optionNames) {
            System.out.println("key==" + optionName + ",value==" + args.getOptionValues(optionName));
        }
    }
}

ApplicationArguments中的几个方法:

  • args.getNonOptionArgs();可以用来获取命令行中的无key参数(和CommandLineRunner一样)。
  • args.getOptionNames();可以用来获取所有key/value形式的参数的key。
  • args.getOptionValues(key));可以根据key获取key/value 形式的参数的value。
  • args.getSourceArgs(); 表示获取命令行中的所有参数。

当项目启动时,这里的 run 方法就会被自动执行。

如果在 IDEA 中,我们可以通过如下方式来传入参数:

如果将项目打包,在命令行中启动项目,可以在启动时的命令行后面传入参数:

五、SpringBoot定义关闭系统任务

Spring Boot 中针对系统关闭任务提供了两种解决方案:

方式一:实现DisposableBean接口

@Component
public class MyDisposableBean implements DisposableBean, ExitCodeGenerator {
    @Override
    public void destroy() throws Exception {
        System.out.println("服务器被关闭了>>>>>>>>>>>>>>>");
    }

    @Override
    public int getExitCode() {
        return 5;
    }
}

方式二:使用@PreDestroy注解

@Component
public class MyDisposableBean2 {
    @PreDestroy
    public void myDestory() {
        System.out.println("服务器被关闭了>>>>>>>>>>使用@PreDestroy>>>>>");
    }
}

 

参考文章:https://blog.csdn.net/She_lock/article/details/86241685

ends ~

 

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值