componentscan注解的用法和作用_Springmvc注解版开发

搭建原理

653f3b48cb2e41e780d6a31f91fd2501.png

springMVC版本

  • 此次使用的版本是Spring 5.1.8

配置内嵌tomcat

  • 为了简化开发,使用tomcat插件实现web项目的运行,只需要在pom.xml中配置一个插件即可,如下:
<plugins>
        <plugin>
          <groupId>org.apache.tomcat.maven</groupId>
          <artifactId>tomcat7-maven-plugin</artifactId>
          <version>2.1</version>
            <configuration>
                <port>8080</port>
                <path>/</path>
                <uriEncoding>UTF-8</uriEncoding>
            </configuration>
        </plugin>
</plugins>
  • 之后在IDEA右侧的maven处可以看见tomcat7这个插件了,点击run即可运行

配置DispatcherServlet初始化器

  • 配置的方式有多种,但是根据Spring文档推荐的方式如下:
import cn.tedu.demo.config.AppConfig;
import cn.tedu.demo.config.WebMvcConfig;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
​
/**
 * 配置DispatcherServlet初始化器,在容器启动的时候会加载初始化
 * 入口就是/org/springframework/spring-web/5.1.8.RELEASE/spring-web-5.1.8.RELEASE.jar!/META-INF/services/javax.servlet.ServletContainerInitializer
 * web容器在启动的时候会加载META-INF/service下的文件
 */
public class StrartWebApplicationInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
​
    /**
     * 配置主配置类,主配置类的作用就是配置业务所需要的各种Bean,比如dao,service
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{AppConfig.class};
    }
​
    /**
     * 配置MVC所需的配置类,该配置类的作用就是扫描controller,配置mvc的各种组件,比如视图解析器,拦截器等
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebMvcConfig.class};
    }
​
    /**
     * 配置servletMapping,相当于在DispatcherServlet中配置的url
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}

主配置文件

  • 主配置文件主要的作用就是配置业务需求的Bean,比如dao,service层的
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
​
/**
 * 业务逻辑的配置类,扫描所有的业务Bean,比如dao,service,排除所有的controller
 */
@Configuration
@ComponentScan(basePackages = {"cn.tedu.demo"},excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})})
public class AppConfig {
}

MVC配置类

  • MVC配置类主要的作用就是扫描Controller,配置各种组件,比如视图解析器,拦截器等等
  • 重要的两点如下:
    • 使用@EnableWebMvc注解开启MVC功能,相当于xml文件中的<mvc:annotation-driven/>
    • 配置类需要实现WebMvcConfigurer,该接口下有各种方法,开发者可以实现其中的方法完成相关组件的生成
import cn.tedu.demo.interceptor.CustomInterceptor;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.stereotype.Controller;
import org.springframework.web.servlet.config.annotation.*;
​
/**
 * MVC的配置类,扫描所有的controller,排除所有的业务类
 * @EnableWebMvc 注解开启mvc功能
 * @ComponentScan 注解中的属性useDefaultFilters(默认是true,扫描全部的Bean),这里我们定义了只扫描controller,因此要设置该属性为false,否则不起作用,排除Bean则不需要
 */
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = {"cn.tedu.demo"},includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})},useDefaultFilters = false)
public class WebMvcConfig implements WebMvcConfigurer {
}

配置拦截器

  • 自定义一个拦截器,如下:
/**
 * 自定义一个拦截器,实现HandlerInterceptor
 */
@Component
public class CustomInterceptor implements HandlerInterceptor {
    /**
     * 在拦截器方法之前执行
     * @param request request
     * @param response response
     * @param handler 拦截的handler
     * @return 如果返回false,后续的拦截器和拦截的handler不执行
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("在之前执行");
        return true;
    }
}
  • 在配置类设置自定义的拦截器,使得起作用
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //创建
        CustomInterceptor customInterceptor = new CustomInterceptor();
        //添加自定义的拦截器
        registry.addInterceptor(customInterceptor).addPathPatterns("/**");
    }
  • 自定义的拦截器的真实实现类其实是MappedInterceptor,在源码中获取处理器执行链的时候会将其添加到执行链中。

配置过滤器

  • 过滤器不属于SpringMVC,而是属于Servlet中的组件,因此配置过滤器使用的并不是MVC的配置,但是在Servlet3.0中也是提供了注解版的Servlet和Filter的生成方式,我们使用注解生成一个Filter,如下:
/**
 * 自定义过滤器
 */
@WebFilter(filterName = "customFilter",urlPatterns = "/*")
public class CustomFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }
​
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("过滤器执行");
        chain.doFilter(request,response);
    }
​
    @Override
    public void destroy() {
        System.out.println("过滤器销毁");
    }
}
​

配置视图解析器

 @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.jsp("/WEB_INF/",".jsp");
    }

配置ViewController

@Override
    public void addViewControllers(ViewControllerRegistry registry) {
        //定义一个controller,访问路径是/index.do,跳转的视图是index.jsp
        registry.addViewController("/index.do").setViewName("index");
    }

配置MessageConverters

  • 消息转换器用于对Request和Response的消息进行处理,比如将Response中的消息转换为指定JSON字符串的形式
  • 默认的消息转换器对于日期的类型的转换是时间戳,即是返回的JSON字符串的日期类型是时间戳,接收的日期类型参数也只能是时间戳
  • 如何配置消息转换器,只需要重写springmvc配置类中的方法即可。
  • 我们使用的是MappingJackson2HttpMessageConverter这类转换器,但是其中依赖的是ObjectMapper,因此我们比如引入依赖,如下:
   <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.9</version>
    </dependency>
  • 在上述的MVC配置类中重写如下方法:
    • 设置日期的格式化格式是yyyy-MM-dd,此时返回和接收的格式就是yyyy-MM-dd
    • 在配置类中配置的消息转换器属于全局配置,所有的消息都会遵循这种配置。
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                //指定格式化的日期,这里只是举例,不建议在此处全局配置
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
                //设置时区,默认是UTC,需要修改成北京时间
                .timeZone("GMT+8");
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
    }

注解版

  • 在实际的项目中这种方式太鸡肋,实际的需求有实际的变化,因此我们最好能够寻找一种灵活的处理方式,类似注解的方式。
  • jackson-databind中提供了许多的注解,可以供我们使用,可以覆盖全局配置,和全局配置形成一种互补的作用
  • @JsonFormat:日期格式化注解,如下:
//timeZone如果在全局配置过,可以不写 
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date birthDay;
  • @JsonIgnore:在返回的JSON字符串中不显示
    @JsonIgnore
    private String name;
  • 其他的注解请参考https://blog.51cto.com/7308310/2310930?source=dra

异常处理器

  • springMvc处理异常有三种方式,分别为:
    • ExceptionHandlerExceptionResolver:通过调用或 类中的@ExceptionHandler方法来解决异常,可以结合@ControllerAdvice
    • DefaultHandlerExceptionResolver:对一些特殊的异常进行处理
    • ResponseStatusExceptionResolver:使用@ResponseStatus解析异常,并根据注解中的值将它们映射到HTTP状态代码
    • SimpleMappingExceptionResolver:异常和视图的映射,可以自定义指定的异常对应的视图
  • 原理:主要的解析逻辑都是在doResolveException方法中完成的。

异常处理器执行的顺序

  • 异常处理器的执行是有顺序的,优先级高的执行完之后,如果有对应的处理,那么后续的就不再执行。
  • 异常处理器的执行顺序如下:
    • ExceptionHandlerExceptionResolver
    • DefaultHandlerExceptionResolver
    • ResponseStatusExceptionResolver
    • SimpleMappingExceptionResolver
  • 四种异常处理器的顺序执行可以形成一种互补的配置。

SimpleMappingExceptionResolver

  • 在配置中配置即可
@Bean
    public SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
        //设置默认的视图,如果有的异常没有指定处理,那么使用默认的视图
        resolver.setDefaultErrorView("index");
        //设置排除的异常
//        resolver.setExcludedExceptions();
        //指定异常视图映射
        Properties properties=new Properties();
        properties.put(RuntimeException.class.getName(),"error");
        resolver.setExceptionMappings(properties);
        return resolver;
    }

DefaultHandlerExceptionResolver

  • 此类异常解析器只能针对一些特殊的异常进行处理,如下:
ExceptionHTTP Status CodeHttpRequestMethodNotSupportedException405 (SC_METHOD_NOT_ALLOWED)HttpMediaTypeNotSupportedException415 (SC_UNSUPPORTED_MEDIA_TYPE)HttpMediaTypeNotAcceptableException406 (SC_NOT_ACCEPTABLE)MissingPathVariableException500 (SC_INTERNAL_SERVER_ERROR)MissingServletRequestParameterException400 (SC_BAD_REQUEST)ServletRequestBindingException400 (SC_BAD_REQUEST)ConversionNotSupportedException500 (SC_INTERNAL_SERVER_ERROR)TypeMismatchException400 (SC_BAD_REQUEST)HttpMessageNotReadableException400 (SC_BAD_REQUEST)HttpMessageNotWritableException500 (SC_INTERNAL_SERVER_ERROR)MethodArgumentNotValidException400 (SC_BAD_REQUEST)MissingServletRequestPartException400 (SC_BAD_REQUEST)BindException400 (SC_BAD_REQUEST)NoHandlerFoundException404 (SC_NOT_FOUND)AsyncRequestTimeoutException503 (SC_SERVICE_UNAVAILABLE)
  • 不需要声明,默认存在

ResponseStatusExceptionResolver

  • 在自定义的异常类上标注@ResponseStatus注解,当抛出此种异常的时候,将会响应定义的状态码和提示语
@ResponseStatus(code = HttpStatus.FORBIDDEN,reason = "没有权限")
public class CustomException extends  RuntimeException {
​
}

ExceptionHandlerExceptionResolver

  • 集合@ControllerAdvice@RestControllerAdvice使用
  • 方法中能够自动赋值的参数和返回值的类型都在Spring文档上有详细的记载,参考https://docs.spring.io/spring/docs/5.1.8.RELEASE/spring-framework-reference/web.html#mvc-ann-exceptionhandler-args
  • 详细的使用如下:
@ControllerAdvice
public class ExceptionController {
​
    /**
     *
     *处理FileNotFoundException,返回JSOn数据
     */
    @ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
    @ResponseBody
    public Object handleFileNotFoundException(Exception ex, HttpServletRequest request, HandlerMethod method){
        System.out.println(request.getRequestURI());
        System.out.println(method);
        System.out.println(ex);
        return "index";
    }
​
    @ExceptionHandler(value = Exception.class)
    public Object handleException(Exception ex, HttpServletRequest request, HandlerMethod method){
        System.out.println(request.getRequestURI());
        System.out.println(method);
        System.out.println(ex);
        return "index";
    }
}

配置跨域请求

使用注解

  • 使用注解@CrossOrigin,可以标注在Controller上,也可以标注在方法上,如下:
    @CrossOrigin
    @PostMapping("/getObj")
    public Object getObject(@RequestBody AdminReq req){
        System.out.println(req);
        return new Admin("陈加兵",22,new Date(),new Date());
    }
  • 该注解中可以配置各种属性,这里不再细讲,在下面的全局配置中会涉及到。

全局配置

  • 全局配置就是在MVC的配置文件中重写方法即可,如下:
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                //允许的源
                .allowedOrigins("https://domain2.com")
                //允许请求跨域的请求类型
                .allowedMethods("PUT", "DELETE")
                //允许的请求头
                .allowedHeaders("header1", "header2", "header3")
                //暴露的请求头
                .exposedHeaders("header1", "header2")
                //允许携带cookie等用户信息,这样才能实现登录
                .allowCredentials(true).maxAge(3600);
    }

配置静态资源解析

  • springmvc中的DispatcherServlet如果设置了拦截的请求是/,那么也会拦截静态资源,但是我们可以在配置文件中配置,如下:
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        //拦截的请求
        registry.addResourceHandler("/resources/**")
                //资源的位置
                .addResourceLocations("/public", "classpath:/static/")
                //缓存的时间,单位秒
                .setCachePeriod(31556926);
    }
  • 该配置会在ioc中注册一个ResourceHttpRequestHandler,封装在SimpleUrlHandlermapping中。

高级配置

  • @EnableMvc注解其实就是注入了一个配置类DelegatingWebMvcConfiguration,那么我们可以将自定义的配置类实现该类即可完成MVC的高级功能,此时就不需要使用该注解了,如下:
@Configuration
@ComponentScan(basePackages = {"cn.tedu.demo"},includeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Component.class})},useDefaultFilters = false)
public class AdvanceConfig extends DelegatingWebMvcConfiguration {
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值