跟我学SpringBoot之MVC的自动配置

只需低头努力,剩下的交给时光,时间会公平地帮你处理一切

一个简单的例子

public class MvcModel {
    private String modelName;
    private Integer modelType;
    /**省略geter、setter方法**/
}

@RestController
@EnableAutoConfiguration
public class SpringMvcGuide {

    @RequestMapping("/getModel")
    public MvcModel getMvcModel(){
        MvcModel mvcModel = new MvcModel();
        mvcModel.setModelName("小明");
        mvcModel.setModelType(1);
        return mvcModel;
    }

    public static void main(String[] args){
        SpringApplication.run(SpringMvcGuide.class,args);
    }

}

启动服务,访问http://localhost:8080/getModel可以看到页面显示

{"modelName":"小明","modelType":1}

页面上展示会将MvcModel对象转换成json字符串,这是我们最常用的格式,后台统一返回json格式,前台接收到json格式后进行解析

在实际开发过程中,还有一些老的系统在使用xml格式来传输数据,SpringBoot也提供了xml格式数据的返回,只需要小小的改动,就可以实现

增加依赖

compile 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.11.2'
compile 'org.glassfish.jaxb:jaxb-runtime:2.3.3'

将实体类打上@XmlRootElement注解

@XmlRootElement
public class MvcModel {
    private String modelName;
    private Integer modelType;
    /**省略geter、setter方法**/
}

重新启动项目,访问http://localhost:8080/getModel可以看到页面显示

<MvcModel>
<modelName>小明</modelName>
<modelType>1</modelType>
</MvcModel>

从上面的例子可以看出来,想返回xml格式的数据只需要引入相应的jar包就行了,无需修改任何配置

Spring MVC自动配置

SpringBoot为SpringMVC提供了自动配置,除了SpringMVC默认的配置外还提供了以下配置:

  • 引入ContentNegotiatingViewResolver和BeanNameViewResolver beans。
  • 对静态资源的支持,包括对WebJars的支持
  • 自动注册Converter,GenericConverter,Formatter beans。
  • 对HttpMessageConverters的支持。
  • 自动注册MessageCodeResolver。
  • 对静态index.html的支持。
  • 对自定义Favicon的支持。
  • 自动使用ConfigurableWebBindingInitializer bean。

如果你想保留SpringBoot MVC的特性,只需要增加相应的MVC配置(如拦截器、格式化处理器、视图控制器),如果你想全面的控制Spring MVC,也可以实现自己的配置,并使用@EnableWebMvc注解

HttpMessageConverters

Spring MVC使用HttpMessageConverter来转换HTTP请求和响应中的数据,比如对象自动转换成JSON或XML对象,这些转换的处理类都是SpringBoot默认都配置好了,你不需要做任何配置就可以实现数据的转换,当然也提供了自定义HttpMessageConverters的方法,上下文中出现的所有HttpMessageConverter bean都会被添加到converter列表,你可以通过这种方式来覆盖默认的转换器列表。下面通过一个例子来演示一下如何自定义HttpMessageConverter

默认转换json的转换器是使用的jackson,我们先来看看默认的例子

@RestController
@SpringBootApplication
public class SpringMvcGuide {
    @RequestMapping("/getStudent")
    public Student getStudent(){
        Student stu = new Student();
        stu.setName("小明");
        return stu;
    }

    public static void main(String[] args){
        SpringApplication.run(SpringMvcGuide.class,args);
    }


}
public class Student {
    private String name;
    private int age;
    private String address;
    /** 省略getter、setter方法 **/
}

启动程序,访问http://localhost:8080/getStudent ,页面显示

{"name":"小明","age":0,"address":null}

可以看到Student对象被转换成json字符串,age默认值为0,address默认为null

下面我们替换成fastjson,并且String类型的默认值为空字符串

首先引入依赖

compile 'com.alibaba:fastjson:1.2.58'

添加HttpMessageConverter配置类

@Configuration
public class HttpMessageConverterConfig {

    @Bean
    public HttpMessageConverter fastJsonHttpMessageConverter(){
        FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter();
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        SerializerFeature[] serializerFeatures = new SerializerFeature[]{
                SerializerFeature.QuoteFieldNames,//输出Key是否包含双引号
                SerializerFeature.WriteMapNullValue,//是否输出为null的字段,若为null则显示该字段
                SerializerFeature.WriteNullNumberAsZero,//数字若为null,输出0
                SerializerFeature.WriteNullListAsEmpty, //list为null,输出[]
                SerializerFeature.WriteNullStringAsEmpty,//String为null,输出""
                SerializerFeature.WriteNullBooleanAsFalse,//boolean为null,输出false
                SerializerFeature.WriteDateUseDateFormat,//Date的日期转换器
                SerializerFeature.DisableCircularReferenceDetect //循环引用
        };
        fastJsonConfig.setSerializerFeatures(serializerFeatures);
        fastJsonConfig.setCharset(Charset.forName("UTF-8"));
        fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig);
        List<MediaType> mediaTypeList = new ArrayList<MediaType>();
        mediaTypeList.add(MediaType.APPLICATION_JSON);
        fastJsonHttpMessageConverter.setSupportedMediaTypes(mediaTypeList);
        return fastJsonHttpMessageConverter;
    }
}

重新启动程序,访问http://localhost:8080/getStudent,页面显示

{"address":"","age":0,"name":"小明"}

可以看到address默认值已经变成空字符串,说明我们引入的fastjson生效了

自定义Json序列化和反序列化

如果你使用Jackson来序列化和反序列化json数据,你可能需要写自己的JsonSerializer和JsonDeserializer类,自定义序列化器通常通过Module注册到Jackson,但SpringBoot提供了@JsonComponent注解能轻松的将序列化器注册为Spring Bean

您可以直接在JsonSerializer、JsonDeserializer或KeyDeserializer实现上使用@JsonComponent注释。还可以在包含序列化器/反序列化器的内部类上使用它,如下面的示例所示

@JsonComponent
public class Example {

    public static class Serializer extends JsonSerializer<SomeObject> {
        // ...
    }

    public static class Deserializer extends JsonDeserializer<SomeObject> {
        // ...
    }

}

ApplicationContext中的所有@JsonComponent bean都会自动注册到Jackson中。
因为@JsonComponent是用@Component进行元注释的,所以通常的组件扫描规则也适用。

Spring Boot还提供了JsonObjectSerializer和JsonObjectDeserializer基类,在序列化对象时为标准Jackson版本提供了有用的替代方案。详情可以自行查阅JsonObjectSerializer和JsonObjectDeserializer,这里不再展开

静态内容

默认情况下,Spring Boot从类路径中的/static(/public,/resources,/META-INF/resources)目录或ServletContext的根目录中提供静态内容。它是使用Spring MVC中的ResourceHttpRequestHandler来实现的,
这样你就可以通过添加自己的WebMvcConfigurer和覆盖addResourceHandlers方法来进行自定义

在独立的web应用程序中,容器中的默认servlet也被启用,并充当后备,如果Spring决定不处理ServletContext,则从ServletContext的根提供内容。大多数情况下,这种情况不会发生(除非您修改了默认的MVC配置),因为Spring总是可以通过DispatcherServlet处理请求

默认情况下,资源映射到/**上,但是您可以使用spring.mvc.static-path-pattern属性来进行调整。例如,将所有资源重新定位到/resources/**,可以通过如下配置实现

spring:
  mvc:
    static-path-pattern: "/resources/**"

还可以使用spring.web.resources来定制静态资源位置,除了前面提到的静态资源位置之外,Webjars内容也是一个特殊情况,任何/webjars/**路径的资源都是从jar文件中提供的,前提是它们是以webjars格式打包的

模板引擎

除了REST web服务之外,还可以使用Spring MVC来提供动态HTML内容。Spring MVC支持多种模板技术
(包括Thymeleaf、FreeMarker和jsp),
此外,许多其他模板引擎也包含它们自己的Spring MVC集成。

Spring Boot支持以下模板引擎的自动配置:

  • FreeMarker
  • Groovy
  • Thymeleaf
  • Mustache

当您使用上述模板引擎之一时,将会自动从src/main/resources/templates目录下获取模板

异常/错误的处理

默认情况下,Spring Boot提供了一个/error映射,它以一种合理的方式处理所有错误,并在servlet容器中注册为一个“全局”错误页面。对于机器客户端来说,它生成一个JSON响应,其中包含错误、HTTP状态和异常消息的详细信息。对于浏览器客户端,有一个“whitelabel”错误视图,它以HTML格式呈现相同的数据

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed Mar 03 22:46:49 CST 2021
There was an unexpected error (type=Not Found, status=404).

对于返回json格式的请求来说,可以定义一个带@ControllerAdvice注释的类,来处理特定的Controller异常信息,如下面的示例所示

@ControllerAdvice(basePackageClasses = AcmeController.class)
public class AcmeControllerAdvice extends ResponseEntityExceptionHandler {

    @ExceptionHandler(YourException.class)
    @ResponseBody
    ResponseEntity<?> handleControllerException(HttpServletRequest request, Throwable ex) {
        HttpStatus status = getStatus(request);
        return new ResponseEntity<>(new CustomErrorType(status.value(), ex.getMessage()), status);
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }

}

对于返回页面的请求,我们一般会定制自己的异常页面,例如404、500这些异常的状态码都会定位到对应的页面。

比如要对404定制一个html页面,可以把页面放到对应的目录下

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- public/
             +- error/
             |   +- 404.html
             +- <other public assets>

再比如要对500定制一个FreeMarker页面

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 500.ftlh
             +- <other templates>

对于更复杂的映射,您还可以自己实现ErrorViewResolver接口,如下面的示例所示:

public class MyErrorViewResolver implements ErrorViewResolver {

    @Override
    public ModelAndView resolveErrorView(HttpServletRequest request,
            HttpStatus status, Map<String, Object> model) {
        // Use the request or status to optionally return a ModelAndView
        return ...
    }

}

你也可以使用Spring MVC的常规特性,比如@ExceptionHandler方法和@ControllerAdvice

跨域支持

跨源资源共享(CORS)是由大多数浏览器实现的W3C规范,它允许您以灵活的方式指定哪种跨域请求得到授权,而不是使用一些不太安全、功能不太强大的方法,如IFRAME或JSONP。

从4.2版开始,Spring MVC支持CORS。在Spring Boot应用程序中使用带有@CrossOrigin注释的Controller方法不需要任何特定的配置。通过使用自定义的addcorsmapping (CorsRegistry)方法注册WebMvcConfigurer bean,可以定义全局CORS配置,如下面的示例所示:

@Configuration(proxyBeanMethods = false)
public class MyConfiguration {

    @Bean
    public WebMvcConfigurer corsConfigurer() {
        return new WebMvcConfigurer() {
            @Override
            public void addCorsMappings(CorsRegistry registry) {
                registry.addMapping("/api/**");
            }
        };
    }
}

如果感觉对你有些帮忙,请收藏好,你的关注和点赞是对我最大的鼓励!
如果想跟我一起学习,坚信技术改变世界,请关注【Java天堂】公众号,我会定期分享自己的学习成果,第一时间推送给您

在这里插入图片描述

posted @ 2021-03-03 23:08  果子爸聊技术  阅读(6)  评论(0编辑  收藏  举报