spring boot 2.0之web应用开发

简介

spring boot 非常适合进行web程序开发。可以通过使用spring-boot-starter-web快速创建一个内嵌tomcat或Jetty,或netty的应用。也可以通过使用spring-boot-starter-webflux创建交互式的应用。

Spring Web MVC框架

springMVC框架是一个基于“model,view,controller"的web框架,spring MVC让你可以@controller 或者 @RestControllerbeans 去处理http的请求。在你的control的方法中将会使用@RequestMapping 映注解映射成URL。
以下是@RestController 列子处理json数据:代码如下:
@RestController
@RequestMapping(value="/users")
public class MyRestController {

	@RequestMapping(value="/{user}", method=RequestMethod.GET)
	public User getUser(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}/customers", method=RequestMethod.GET)
	List<Customer> getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@RequestMapping(value="/{user}", method=RequestMethod.DELETE)
	public User deleteUser(@PathVariable Long user) {
		// ...
	}

}

01. spring mvc的自动配置
 为大多数的应用都配置了spring mvc自动配置  。其自动配置默认在spring的基础上增加了如下特性:
  •  包含了ContentNegotiatingViewResolver(根据请求头输出不同的形式:例如xml,json)BeanNameViewResolver(返回的逻辑视图名称去匹配定义好的视图bean对象)
  •  支持服务静态资源(包括WebJars 
  • 自动注册ConverterGenericConverter, 与 Formatter  beans
  • 支持 HttpMessageConverters 
  • 自动注册 MessageCodesResolver 
  • 静态index.html支持
  • 自定义 Favicon支持
  • 自动使用ConfigurableWebBindingInitializer
如果想保持Spring Boot MVC特性,你想要添加附加的MVC 配置(interceptors, formatters, view controllers, 与其他配置)。你可以不使用@EnableWebMvc,而是添加其@Configuration配置类其。如果你希望提供自定义的RequestMappingHandlerMappingRequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver的实例。可以使用WebMvcRegistrationsAdapter提供组件。
如果想完全控制MVC,通过使用@Configuration与 @EnableWebMvc  。

02. httpMessageConverters
Spring MVC 使用httpMessageConverters来转换http请求与响应。合理的默认值应该包含哪些不确定的情况,例如:对象可能会自动的被转换为JSON或者XML。默认情况下使用UTF-8.
如果要添加或者自定义的转换器,可以使用Spring Boot的 HttpMessageConverters类 其代码如下:
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);
	}

}

03. 自定义json serializer与json deserializer
 如果使用Jackson去串行化一个数据或对象话一个json 数据,可能需要些自己的json对象转换器。自定义的json转换器通过一个module的形式注册到JsonComponent ,其提供了 @JsonComponent 使其能够快速注册到json上去。你可以使用@JsonComponent 直接进行JsonSerializer or JsonDeserializer 的转换,也可以使用内部类的形式:代码如下
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 会自动注册到jackson,因为@JsonComponent 的元数据使用@Component,数,component-scanning能够被应用。

04. messageCodeResolver
spring mvc 提供了 MessageCodesResolver来根据产生的错误码来提示对应的错误信息。如果你设置了spring.mvc.message-codes-resolver.format属性 PREFIX_ERROR_CODE 或者是POSTFIX_ERROR_CODE

05.静态内容
默认情况下,spring boot 将根据经下的/static ( /public , /resources , /META-INF/resources)作为静态资源路径,它使用来自于from Spring WebFlux的ResourceWebHandler以便能修改其行为。
默认情况下,资源被映射成 /**,,但是可以通过设置spring.webflux.static-path-pattern 进行调整,例如将资源重定位到 /resources/** 下,可以使用如下配置
spring.webflux.static-path-pattern=/resources/**
通过使用 spring.resources.static-locations 可以自定义资源路径位置。也可以通过使用webjar的方式如果其打包为jar。
Spring Boot 也支持spring mvc支持的资源特性。允许使用cache-busting静态资源或者是对于Webjars使用未知版本资源。对于使用未知版本的webjar资源,需要添加webjars-locator 依赖。比如:使用jquery为例:使用"/webjars/jquery/dist/jquery.min.js" 的结果为 "/webjars/jquery/x.y.z/dist/jquery.min.js".。如果使用jboss的话还需要依赖 webjars-locator-jboss-vfs ,否则会报404错误。
使用缓存清楚(cache busting),接下来的配置配置了对所有静态资源缓存清楚。高效的添加hash值内容。例如,在URL中的内容:<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>,、其主要配置为:
spring.resources.chain.strategy.content.enabled=true
spring.resources.chain.strategy.content.paths=/**
当动态加载资源的时候,js模块加载,文件命名是不打开的,那就是为什么其他策略被支持并且能够被组合。一种修订的策略是在URL中 "fixed"中修定一个静态版本,不用更改其名字。如下配置:
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版本使用 "/js/lib/" 使用上述配置之后为 ("/v12/js/lib/mymodule.js"),其他的资源内容也是如下 (<link href="/css/spring-2a2d595e6ed9a0b24f027f2b63b134d6.css"/>).

06. 开始页
Spring Boot支持静态的和模板的开始页。其首先在配置静态内容中寻找index.html.如果没有发现,则查找使用静态模板。

07. 自定义收藏夹图标
Spring Boot 寻找收藏夹图标在静态位置或者是classpath的根路径。

08. 配置web绑定初始化
Spring MVC使用WebBindingInitializer 去初始化WebDataBinder初和特殊的请求。如果你创建ConfigurableWebBindingInitializer@bean,Spring Boot自动配置 Spring MVC 去配置它。

09. 模板引擎
REST 的web service一样,你可以使用 Spring MVC 动态填充内容。spring mvc支持不同的模板技术:Thymeleaf, FreeMarker, 与JSPs。包括其spring mvc自身的操作。
包括自动配置的支持的模板引擎如下:
如果使用默认的模板位置的话:其配置路径如下: src/main/resources/templates 

10. 错误处理
默认情况下, Spring Boot以一种合理的方式提供了/error mapping的映射处理。其在servlet container中作为一种全局的错误页,对于机器的客户端,其产生一个json格式的错误信息(包括http状态,以及异常信息)。对于浏览器客户端,有一种叫做“whitelabel”的错误,以html的格式渲染。完全替换默认的行为,可以实现一个ErrorController 注册一个bean的类型并且添加一个 ErrorAttributes 的bean通过替换成内容去实现已存在的机制。
可以通过使用注解 @ControllerAdvice去自定义一个json文档返回一个特别的控制或者是异常类型。如下例子:

@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);
	}

}
10.1 自定义错误页
如果想要对给定的错误状态展示一个自定义的错误页。可以添加一个 /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 ...
	}

}
10.2 非spring mvc映射错误文件
对于没有使用spring mvc的应用,可以通过实现接口 ErrorPageRegistrar 指向错误页面,如下代码所示:
@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"));
	}

}
如果注册的错误文件的路径在一个过滤器里面,其Filter 要指定错误的分发:如下代码
@Bean
public FilterRegistrationBean myFilter() {
	FilterRegistrationBean registration = new FilterRegistrationBean();
	registration.setFilter(new MyFilter());
	...
	registration.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
	return registration;
}
10.3在websphere上处理错误
默认情况下,WebSphere 8.0以后的版本通过servlet的服务方法能够完全完成,需要将其 com.ibm.ws.webcontainer.invokeFlushAfterService设置为false。

11. spring hateoas
如果使用超文本开发api,spring boot 为Spring HATEOAS提供了自动配置来很好的为应用程序服务。其自动配置使用 @EnableHypermediaSupport替换了 需求,和注册了一系列的bean使超文本易于构建。包括LinkDiscoverers 与ObjectMapper 的配置去编排成想要的结果信息。其 ObjectMapper 通过设置spring.jackson.* 来进行个性化。
可以通过使用 @EnableHypermediaSupport来配置HATEOAS’s配置。这种方式可以让 ObjectMapper 较早的使用。

12.cors 支持(跨域访问的支持
Cross-origin resource sharing (CORS)是被大多数的浏览器通过w3c的方式,允许你指定一种灵活的方式对于跨越资源的请求的授权。代替使用更弱的方式实现(例如 IFRAME or JSONP
从spring 4.2开始,spring mvc 支持了跨越访问。通过使用 @CrossOrigin 配置,不需要使用其他的任何的特殊的配置。可以通过自定义的addCorsMappings(CorsRegistry) 注册方法注册 WebMvcConfigurer bean,如下代码:
@Configuration
public class MyConfiguration {

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

Spring WebFlux框架

spring webflux是在spring 5.0中引入的响应式的web编程框架。不像spring mvc,其不需要servlet api。其是完全异步并且是非阻塞的。通过交互式流实现交互式流的标准。
spring webflux带来的两大特点:功能性以及其基于注解。基于注解这块与spring mvc比较的类似,如下代码:
@RestController
@RequestMapping("/users")
public class MyRestController {

	@GetMapping("/{user}")
	public Mono<User> getUser(@PathVariable Long user) {
		// ...
	}

	@GetMapping("/{user}/customers")
	Flux<Customer> getUserCustomers(@PathVariable Long user) {
		// ...
	}

	@DeleteMapping("/{user}")
	public Mono<User> deleteUser(@PathVariable Long user) {
		// ...
	}

}
其功能性的变量“WebFlux.fn”:将实际处理请求与路由配置进行分离。如下代码:
@Configuration
public class RoutingConfiguration {

	@Bean
	public RouterFunction<ServerResponse> monoRouterFunction(UserHandler userHandler) {
		return route(GET("/{user}").and(accept(APPLICATION_JSON)), userHandler::getUser)
				.andRoute(GET("/{user}/customers").and(accept(APPLICATION_JSON)), userHandler::getUserCustomers)
				.andRoute(DELETE("/{user}").and(accept(APPLICATION_JSON)), userHandler::deleteUser);
	}

}

@Component
public class UserHandler {

	public Mono<ServerResponse> getUser(ServerRequest request) {
		// ...
	}

	public Mono<ServerResponse> getUserCustomers(ServerRequest request) {
		// ...
	}

	public Mono<ServerResponse> deleteUser(ServerRequest request) {
		// ...
	}
}
通用使用spring-boot-starter-webflux 配置,可以添加webflux(注意:通过添加spring-boot-starter-web 与 spring-boot-starter-webflux将会导致webflux不会生效)。

01. 自动配置
自动配置除了支持spring的基本特性外,还添加了如下特性:
  • 配置HttpMessageReader 与 HttpMessageWriter 与实例
  • 支持静态资源(包括webjar)
如果想完全控制spring WebFlux,可以通过使用 @EnableWebFlux配置。

02. http解码器httpmessageheader与httpmessagewriter
Spring WebFlux使用HttpMessageReader 与HttpMessageWriter 转换器请求。他们通过用CodecConfigurer在类路径中配置。spring boot 通过使用 CodecCustomizer实例。例如:spring.jackson.*,配置主键被应用于Jackson 中。如果想自定义转码为其,可以通过创建 CodecCustomizer 来处理:
import org.springframework.boot.web.codec.CodecCustomizer;

@Configuration
public class MyConfiguration {

	@Bean
	public CodecCustomizer myCodecCustomizer() {
		return codecConfigurer -> {
			// ...
		}
	}

}

03. 静态内容
通过指定静态路径配置对应的路径信息:spring.webflux.static-path-pattern=/resources/**

04. 模板引擎

05. 错误处理
    

06. 自定义错误页面
  与spring mvc类似

JAX-RS与JERSEY

如果你更喜欢 JAX-RS的restful endpoint编程模型,你可以使用它代替spring mvc。如果你在你的应用程序中注册他们的servlet或者是filter作为一个bean,Jersey 1.x 与 Apache CXF 会工作的更好。Jersey 2.x提供了对spring的支持,因此我们可以将其封装成一个starter。
在使用 Jersey 2.x的时候,需要依赖spring-boot-starter-jersey 。你需要一个 ResourceConfig的类型的bean注册到所有的端点。如下代码:
@Component
public class JerseyConfig extends ResourceConfig {

	public JerseyConfig() {
		register(Endpoint.class);
	}

}
你可以注册任意多的bean去实现多个高级化的配置。所有的注册的endpoints必须使用 @Components,如下代码所示:
@Component
@Path("/hello")
public class Endpoint {

	@GET
	public String message() {
		return "Hello";
	}

}
因为 Endpoint 是一个 spring Endpoint ,其生命周期是被spring进行管理。可以使用自动注解@Autowired以及@Value 去注入外部配置。默认 Jersey servlet被注册并且被mapping成为“/*”.可以在 ResourceConfig中通过添加@ApplicationPath 改变其mapping。
默认情况下:Jersey 安装成一个ServletRegistrationBean 的名字为jerseyServletRegistration的bean。默认,其servlet是lazily。你可以通过配置 spring.jersey.servlet.load-on-startup改变其行为。你可以停用或者是通过定义相同的名字覆盖其配置。也可以通过设置 spring.jersey.type=filter 使用filter进行替换。

内嵌容器的支持

默认的内嵌容器:tomcat,默认的端口为8080.

01. servlets,filters,listener.
当使用内嵌容器的时候,也可以通过servlet标准定义servlets,filter与listener

02. 容器初始化
内嵌的容器不是执行servlet 3.0+,javax.servlet.ServletContainerInitializer 或者是org.springframework.web.WebApplicationInitializer 接口。这减少地方包在运行一个war包范围内的情况下,会损坏spring boot。
如果执行容器初始化,需要注册一个实现org.springframework.boot.web.servlet.ServletContextInitializer 的bean。其启动方法提供了 ServletContext 的链接以及如果必要,能够被很容易实现已经存在的WebApplicationInitializer的实现。

扫描servlets,filters,listerners:
可以通过 @WebServlet@WebFilter, 与@WebListener自动完成扫描

03. 自定义内嵌的容器
通用的servlet容器配置可以通过spring的环境变量配置。通常,你可以在application.properties中进行设置。
通用的设置包括:
  • 网络设置(包括:server.port与server.address)
  • session设置(server.session.persistence,server.session.timeout以及server.session.store-dir与)
  • 错误管理(server.error.path:错误信息地址)
  • SSL
  • HTTP compression
程序自定义
可以通过实现WebServerFactoryCustomizer接口,其通过了对ConfigurableServletWebServerFactory的链接。包括自定义的配置:其代码如下:
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.stereotype.Component;

@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {

	@Override
	public void customize(ConfigurableServletWebServerFactory server) {
		server.setPort(9000);
	}

}
自定义话configuration目录,其代码如下:
@Bean
public ConfigurableServletWebServerFactory webServerFactory() {
	TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
	factory.setPort(9000);
	factory.setSessionTimeout(10, TimeUnit.MINUTES);
	factory.addErrorPages(new ErrorPage(HttpStatus.NOT_FOUND, "/notfound.html"));
	return factory;
}

04. JSP限制
当使用内嵌容器的时候,这儿有一些JSP支持方面的限制:
  • tomcat 如果使用war包的话,它也应该能够工作。既一个war包可以部署到单独的容器中。一个单独的executable jar将不会工作。
  • Jetty 使用war包也能够工作
  • Undertow 不支持jsp
  • 自定义的错误页面不应该覆盖默认的错误页面

以上内容参考https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-error-handling
上一篇:spring boot 2.0特性之外部化配置


下一篇:spring boot 2.0特性之profile与日志