3、SpringMVC的注解

使用前提

如果需要使用MVC相关注解,需要在Spring核心配置文件applicationContext.xml中开启注解驱动

<!-- 开启MVC注解支持 -->
<mvc:annotation-driven></mvc:annotation-driven>

常用注解

注意@Controller@Service@Repository等注解并非SpringMVC声明,而是由Spring声明。

@RequestMapping

@RequestMapping注解的作用就是将请求和处理请求的控制器方法关联起来,建立映射关系。

可以用来标识类和方法,当标识类的时候,则为设置该类中所有控制器方法的基础请求路径与其他请求限制;当标识方法的时候,则为设置该控制器方法的请求路径与其他请求限制。

@Controller
@RequestMapping("/info")
public class InfoController{
    @RequestMapping("/test")
    public String test(){
        return "test";
    }
}

如上代码所示,test()方法映射的路径为/info/test

value属性

value属性必须设置,表示通过请求路径映射,是一个字符串类型的数组,表示该请求映射能够匹配多个请求地址所对应的请求,等同于path属性

@RequestMapping({"/info","/infomation"})
public class InfoController{}

method属性

通过请求的请求方式映射,例如常见的GETPOST,method属性是一个RequestMethod类型的数组,表示该请求映射能够匹配多种请求方式的请求

若当前请求的请求地址满足请求映射的value属性,但是请求方式不满足method属性,则浏览器报错405:Request method 'POST' not supported

@RequestMapping(
        value = "/testRequestMapping",
        method = {RequestMethod.GET, RequestMethod.POST}
)
public String testRequestMapping(){
    return "success";
}

consumes和produces属性

这两个属性都是用来指定Content-Type

produces指定返回值类型,不仅可设置返回值类型,还可设定返回值的字符编码

consumes指定可以处理请求的提交内容类型

@RequestMapping(
    value = "/pets", 
    method = RequestMethod.GET, 
    produces="application/json;charset=utf-8",
    consumes="application/json"
) 

params属性

通过请求的请求参数匹配请求映射,params属性是一个字符串类型的数组,可以通过四种表达式设置请求参数和请求映射的匹配关系

如果请求不满足params属性,此时页面回报错400:Parameter conditions "username, password!=123456" not met for actual request parameters: username={admin}, password={123456}

headers属性

通过请求的请求头信息匹配请求映射,headers属性是一个字符串类型的数组,可以通过四种表达式设置请求头信息和请求映射的匹配关系

若当前不满足headers属性,此时页面显示404错误,即资源未找到。

派生注解

SpringMVC基于@RequestMapping做为元注解派生除了特定请求方式的注解,例如@GetMapping@PostMapping@PutMapping等,例如@GetMapping

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@RequestMapping(
    method = {RequestMethod.GET}
)
public @interface GetMapping {}

这些注解使用方式和@RequestMapping一样,只是不可以声明在类上

@RequestParam

是将请求参数?传参)和控制器方法的形参创建映射关系,作用于控制层方法形参

value属性

指定为形参赋值的请求参数的参数名

required属性

设置是否必须传输此请求参数,默认值为true

若设置为true时,则当前请求必须传输value所指定的请求参数,若没有传输该请求参数,且没有设置defaultValue属性,则页面报错400:Required String parameter 'xxx' is not present;若设置为false,则当前请求不是必须传输value所指定的请求参数,若没有传输,则注解所标识的形参的值为null

defaultValue属性

不管required属性值为true或false,当value所指定的请求参数没有传输或传输的值为""时,则使用默认值为形参赋值

@RequestHeader

是将请求头信息和控制器方法的形参创建映射关系,共有三个属性:valuerequireddefaultValue,用法同@RequestParam

@CookieValue

是将Cookie数据和控制器方法的形参创建映射关系,共有三个属性:valuerequireddefaultValue,用法同@RequestParam

@RequestBody

可以获取请求体,需要在控制器方法设置一个形参,使用@RequestBody进行标识,当前请求的请求体就会为当前注解所标识的形参赋值,但是使用时需要额外引入HttpMessageConverter,例如解析JSON则需要引入jackson依赖

@ResponseBody

用于标识一个控制器方法,可以将该方法的返回值直接作为响应报文的响应体响应到浏览器

如果是对象类型,则需要配置类型转换器HttpMessageConverter,否则可能会报500:No converter found for return value of type,常见的就是使用jackson

@RestController

@RestController注解是springMVC提供的一个复合注解,标识在控制器的类上,就相当于为类添加了@Controller注解,并且为其中的每个方法添加了@ResponseBody注解

完全注解开发

完全注解开发也就是替换掉Spring核心配置文件applicationContext.xml以及web.xml文件,采用配置类的方式对DispatcherServlet、Spring、SpringMVC进行配置

applicationContext.xml

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop" 
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans.xsd 
                           http://www.springframework.org/schema/aop 
                           http://www.springframework.org/schema/aop/spring-aop.xsd 
                           http://www.springframework.org/schema/context 
                           http://www.springframework.org/schema/context/spring-context.xsd 
                           http://www.springframework.org/schema/mvc
                           http://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <!-- 配置自动扫描注解路径 -->
    <context:component-scan base-package="top.ygang.*"></context:component-scan>
    <!-- 开启MVC注解支持 -->
    <mvc:annotation-driven></mvc:annotation-driven>
    <!--
        将静态资源交给SpringMVC处理
		location:指的是静态资源存放路径,多个路径可以使用逗号分隔
		mapping:指的是以static开头的url资源路径
 	-->
    <mvc:resources mapping="/static/**" location="/static/"></mvc:resources>
    <!-- 视图解析器、设置controller转发、重定向路径默认前缀后缀,可选 -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/"></property>
        <property name="suffix" value=".jsp"></property>
    </bean>
</beans>
@Configuration
@ComponentScan("top.ygang.springmvc_demo")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
	// 配置视图解析器
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
    // 配置静态资源处理方式,等价于mvc:resources
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

@EnableWebMvc

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
// 引入DelegatingWebMvcConfiguration类
@Import(DelegatingWebMvcConfiguration.class)
public @interface EnableWebMvc {
}

是一个Spring MVC框架提供的注解,它的作用是启用Spring MVC框架的默认配置,例如消息转换器,格式化器和验证器等。它还启用了Spring MVC的注解驱动,这样就可以使用注解来处理HTTP请求和响应。

WebMvcConfigurer

实现WebMvcConfigurer接口其实是Spring MVC内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制,可以自定义一些HandlerInterceptorViewResolverMessageConverter

使用时需要创建一个配置类(使用@Configuration注解)并实现WebMvcConfigurer接口

在Spring Boot 1.5版本都是靠重写WebMvcConfigurerAdapter的方法来添加自定义拦截器,消息转换器等。SpringBoot 2.0 后,该类被标记为@Deprecated(弃用)。官方推荐直接实现WebMvcConfigurer或者直接继承WebMvcConfigurationSupport

@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer{
    //根据需求重写方法
}
addInterceptors

配置拦截器

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new TestInterceptor())
            .addPathPatterns("/**")
            .excludePathPatterns("/js/**","/css/**","/images/**");
}
addViewControllers

控制页面访问规则,例如下面,访问/infomation即可访问/info.jsp

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/infomation").setViewName("info");
}
addResourceHandlers

配置静态资源处理方式,等价于mvc:resources

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
configureDefaultServletHandling

注册一个默认的Handler:DefaultServletHttpRequestHandler,这个Handler也是用来处理静态文件的,它会尝试映射/

等价于:mvc:default-servlet-handler

@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
}
configureViewResolvers

配置视图解析器,默认会自动找Spring容器中的InternalResourceViewResolver实例

@Bean
public InternalResourceViewResolver internalResourceViewResolver(){
    InternalResourceViewResolver resolver = new InternalResourceViewResolver();
    resolver.setPrefix("/");
    resolver.setSuffix(".jsp");
    return resolver;
}

@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
    registry.viewResolver(internalResourceViewResolver());
}
addCorsMappings

配置跨越相关

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
            .allowedOrigins("*")
            .allowedMethods("POST", "GET", "PUT", "OPTIONS", "DELETE")
            .allowCredentials(true)
            .allowedHeaders("*")
            .maxAge(3600);
}
configureMessageConverters

配置自定义消息转换器,例如使用fastjson作为json消息转换器

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    //创建fastJson消息转换器
    FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
    //创建配置类
    FastJsonConfig fastJsonConfig = new FastJsonConfig();
    //修改配置返回内容的过滤
    fastJsonConfig.setSerializerFeatures(
            SerializerFeature.DisableCircularReferenceDetect,
            SerializerFeature.WriteMapNullValue,
            SerializerFeature.WriteNullStringAsEmpty
    );
    fastConverter.setFastJsonConfig(fastJsonConfig);
    //将fastjson添加到视图消息转换器列表内
    converters.add(fastConverter);

}

web.xml

在Servlet3.0环境中,容器会在类路径中查找实现javax.servlet.ServletContainerInitializer接口的类,如果找到的话就用它来配置Servlet容器。 Spring提供了这个接口的实现,名为SpringServletContainerInitializer,这个类反过来又会查找实现WebApplicationInitializer的类并将配置的任务交给它们来完成。Spring3.2引入了一个便利的WebApplicationInitializer基础实现,名为AbstractAnnotationConfigDispatcherServletInitializer,当我们的类扩展了AbstractAnnotationConfigDispatcherServletInitializer并将其部署到Servlet3.0容器的时候,容器会自动发现它,并用它来配置Servlet上下文。

public class WebInit extends AbstractAnnotationConfigDispatcherServletInitializer {

    /**
     * 指定spring的配置类
     * @return
     */
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    /**
     * 指定SpringMVC的配置类
     * @return
     */
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{SpringMvcConfig.class};
    }

    /**
     * 指定DispatcherServlet的映射规则,即url-pattern
     * @return
     */
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }

    /**
     * 乱码过滤器
     * @return
     */
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        encodingFilter.setForceRequestEncoding(true);
        HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
        return new Filter[]{encodingFilter, hiddenHttpMethodFilter};
    }
}