1、SpringMvc自动配置

Spring Boot 为SpringMvc提供了自动配置。

自动配置包含Spring的以下特征:

(1)视图解析器ContentNegotiatingViewResolver或BeanNameViewResolver。

(2)支持静态文件,包含对WebJar支持。

(3)自动注册转换器Converter、GenericConverter、Formatter。

(4)支持HttpMessageConverters(转换request、response的数据格式)

(5)注册MessageCodesResolver(转换错误代码)

(6)支持静态index.html

(7)支持Favicon

(8)支持自动使用数据绑定器ConfigurableWebBindingInitializer

如果你想保持上述的特征并加入SpringMvc的其他配置(如interceptors、formatters、view controllers等),你要加入你自己的带有@Configuration注解的WebMvcConfigurerAdapter,且要有注解@EnableWebMvc。如果你想提供常用的句柄如RequestMappingHandlerMapping、RequestMappingHandlerAdapter、ExceptionHandlerExceptionResolver,你可以定义一个WebMvcRegistrationsAdapter来提供这样的组件(component)。

2、HttpMessageConverters

SpringMvc利用HttpMessageConverter接口来转换HTTP request和response。对象会被自动转换为JSON(使用Jackson),或者XML(用Jackson XML或JAXB)。字符串通常默认UTF-8编码。

import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.context.annotation.*;
import org.springframework.http.converter.*;

@Configuration
public class MyConfiguration {

    @Bean
    public HttpMessageConverters customConverters() {
        HttpMessageConverter<?> additional = ...
        HttpMessageConverter<?> another = ...
        return new HttpMessageConverters(additional, another);
    }

}

任何Context中定义的HttpMessageConverter将会被添加到converters列表中。

3、JSON序列化和反序列化

如果你用Jackson进行数据序列化和反序列化,你可能会想建立自己的工具。其实Spring提供@JsonComponent来使对应类(实现serializers/deserializers接口)的Bean可以直接转换为JSON。也可以对内部类为serializers/deserializers的类进行注解。

import java.io.*;
import com.fasterxml.jackson.core.*;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.*;

@JsonComponent
public class Example {

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

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

}

所有@JsonComponent注解的beans会自动被Jackson注册。

4、MessageCodesResolver

 MessageCodesResolver可以将错误代码转换为错误信息。只要你设置spring.mvc.message-codes-resolver.format的值为PREFIX_ERROR_CODE或POSTFIX_ERROR_COD(DefaultMessageCodesResolver.Format中的枚举),Spring Boot 会帮你创建一个。

5、静态文件区

Spring Boot 会默认的classpath或应用根目录下的/static(或者/public、/resources、/META-INF/resources)视为静态文件区。他默认使用Spring Mvc的ResourceHttpRequestHandler,你可以通过在自己的WebMvcConfigurerAdapter添加一个并重写addResourceHandlers实现修改默认的。

默认的,资源文件会匹配/**,你可以通过spring.mvc.static-path-pattern来设置,例如,设置resource下的所有文件为静态可设置为:

spring.mvc.static-path-pattern=/resources/**

你也可以通过设置spring.resources.static-locations的值来定制静态资源区。

Spring Boot还支持WebJar目录,/webjars/**下的任何以WebJar形式打包的文件都会被以jar形式来获取。

 

Spring Boot支持对静态文件进行版本管理,例如我们加入webjars-locator依赖后,"/webjars/jquery/dist/jquery.min.js"文件将会以地址"/webjars/jquery/x.y.z/dist/jquery.min.js"进行访问,"x.y.z"是WebJar的版本。

如果你使用JBoss,你要用webjars-locator-jboss-vfs依赖代替webjars-locator依赖。某则你的/wenjars/**会一直报404。

可以通过以下配置来配置缓存碎片,有效地在URL上加入文件区哈希码,如<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**

fixed策略将会只给URL增加版本但是不改变它的名称。

spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
spring.resources.chain.strategy.fixed.enabled=true
spring.resources.chain.strategy.fixed.paths=/js/lib/
spring.resources.chain.strategy.fixed.version=v12

上面的配置中,/js/lib/mymodule.js会变为/v12/js/lib/mymodule.js。

6、favicon.ico

Spring Boot 会自动在静态文件区根目录和classpath根目录寻找favicon.ico文件,一旦找到,将之作为图标。

7、ConfigurableWebBindingInitializer

SpringMvc通过使用WebBindingInitializer初始化一个WebDataBinder来处理特定的请求。你可以建立自己的ConfigurableWebBindingInitializer Bean,Spring Boot将会自动配置SpringMvc来使用它。

8、模板引擎

SpringBoot会自动使用下列模板引擎

FreeMaker

Groovy

Thymeleaf

Mustache

模板文件通常放在classpath*:templates目录下。

9、错误处理

Spring Boot 提供/error 匹配所有的错误信息使得它们可视化。对于机器客户端,页面返回的是一个JSON字符串,包含状态和异常信息;对于浏览器客户端,页面返回的是一个错误数据渲染的错误页面(你可以通过自己定义/error controller来覆盖)。如果你想要完全覆盖其所有的行为,你可以实现ErrorController并注册对应实现类的bean,你也可以通过定义ErrorAttributes类的bean,保留原来的机制,替换content(错误信息)。

你可以通过@ControllerAdvice来给指定的controller或exception类型。

@ControllerAdvice(basePackageClasses = FooController.class)
public class FooControllerAdvice 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);
    }

}

在上面的例子中,如果一个在FooController在的包下的Controller抛出YourException,返回结果将由基于ErrorAttributes的结果表现变成基于CustomerErrorType的JSON字符串。

自定义错误页面

你可以在/error下定义错误页面。错误页面既不能为静态HTML(即在任何静态资源目录下)也不能为模板。文件名应该为错误代码值或错误代码匹配值。

例如,404错误

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

5xx错误

src/
 +- main/
     +- java/
     |   + <source code>
     +- resources/
         +- templates/
             +- error/
             |   +- 5xx.ftl
             +- <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 ...
    }

}

匹配SpringMvc外部的错误

对于不在SpringMvc内部的错误,你可以用ErrorPageRegistrar接口直接注册错误页面。该接口直接作用于嵌入的容器,因此即使你不创建DispatcherServlet它也能正常工作。

@Bean
public ErrorPageRegistrar errorPageRegistrar(){
    return new MyErrorPageRegistrar();
}

// ...

private static class MyErrorPageRegistrar implements ErrorPageRegistrar {

    @Override
    public void registerErrorPages(ErrorPageRegistry registry) {
        registry.addErrorPages(new ErrorPage(HttpStatus.BAD_REQUEST, "/400"));
    }

}

注:你注册的错误页面最终将被过滤器处理,过滤器会被注册为一个错误分发者(ERROR dispatcher)

@Bean
public FilterRegistrationBean myFilter() {
    FilterRegistrationBean registration = new FilterRegistrationBean();
    registration.setFilter(new MyFilter());
    ...
    registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
    return registration;
}

10、Spring HATEOAS

如果你正在编辑使用超媒体的RESTful API,Spring 为Spring HATEOAS提供自动配置,且能很好地与大部分应用工作。

使用@EnableHypermediaSupport注解可以使应用支持Spring HATEOAS。

11、支持CORS(跨域)

Spring 提供了对跨域的支持。

可以在Controller添加注解方式实现

@RestController
@RequestMapping("/account")
public class AccountController {

    @CrossOrigin
    @RequestMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

也可以设置全局的

@Configuration
public class MyConfiguration {

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