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让你可以@c
ontroller
 或者 
@RestController
beans 去处理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
配置类
其。如果你希望提供自定义的
RequestMappingHandlerMapping

RequestMappingHandlerAdapter
, 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 de
serializer
 如果使用
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

点赞