Spring boot实战阅读笔记(一)

最近在读springBoot实战的书,然而读者却有点费力,一方面是他竟然用了kotlin我相对来说不太了解这个语言,但是也是把书给慢的啃下了,这里做一个简单地记录。其中所介绍内容与书中一致,尚未加入一些自己的想法。

 Web MVC配置简介

Spring MVC为我们提供了一个WebMvcConfigurationSupport类和一个注解@Enable-WebMvc以帮助我们减少配置Bean的声明。WebMvcConfigurationSupport提供的常用配置方法如表8-1所示。

表8-1 WebMvcConfigurationSupport中常用的配置方法

Spring boot实战阅读笔记(一)_第1张图片

另外,WebMvcConfigurerAdapter也可以配置MVC。WebMvcConfigurerAdapter是一个实现了WebMvcConfigurer接口的抽象类。对于这两种方式,Spring Boot都提供了默认的配置类,如果想具体了解配置可以去阅读一下源码。

下面我们简单说明一下如何自定义一个继承自WebMvcConfigurationSupport的配置类WebMvcConfig。

首先,使用@Configuration将WebMvcConfig类标注为Spring配置类,代码如下:

 

@Configuration

public class WebMvcConfig: WebMvcConfigurationSupport() {

//覆盖写配置方法

}

然后,通过重写以下配置方法:addCorsMappings()、addFormatters()、addInterceptors()、addViewControllers()实现自定义的配置。

当我们使用Java Config方式来启用Spring MVC配置,还需要启用WebMvc的配置,我们可以将@EnableWebMvc添加到SpringBootApplication入口类上,代码如下:

@SpringBootApplication

@ServletComponentScan(basePackages = ["com.easy.springboot.demo_spring_mvc.filter"])

@EnableAutoConfiguration(exclude = [ErrorMvcAutoConfiguration::class])

@EnableWebMvc // 启用Spring MVC配置

open class DemoSpringMvcApplication

fun main(args: Array) {

SpringApplicationBuilder().initializers(

beans {

bean {

ApplicationRunner {

initUser()

initCategory()

}

}

}

).sources(DemoSpringMvcApplication::class.java).run(*args)

}

这样我们就可以实现自定义的WebMvc配置了。

下面我们来具体介绍一下WebMvc配置中的静态资源、拦截器、跨域、视图控制器、消息转换器、数据格式化器、视图解析器等配置方法。

8.1.1 静态资源配置

Spring Boot中默认的静态资源配置,是把类路径下的/static、/public、/resources和/META-INF/resources文件夹的静态文件直接映射为/**。我们可以通过覆盖写addResourceHandlers来定制静态资源路径映射,使用注册类ResourceHandlerRegistry添加相应的ResourceHandler。示例代码如下:

 

override fun addResourceHandlers(registry: ResourceHandlerRegistry) {

super.addResourceHandlers(registry)

registry.addResourceHandler("/app/**")

.addResourceLocations("classpath:/static/app/")

 

registry.addResourceHandler("/bower_components/**")

.addResourceLocations("classpath:/static/bower_components/")

}

上面的代码把来自浏览器的静态资源请求/app/**、/bower_components/**映射到Web工程中的类路径下面的/static/app/、/static/bower_components/目录。

override fun addInterceptors(registry: InterceptorRegistry) {

super.addInterceptors(registry)

//注册自定义拦截器,添加拦截路径和排除拦截路径

registry.addInterceptor(loginSessionHandlerInterceptor).

addPathPatterns("/**").

excludePathPatterns(

"/index",

"/login",

"/doLogin",

"/logout",

"/register",

"/doRegister",

"/**/*.js",

"/**/*.css",

"/**/*.css.map",

"/**/*.jpeg",

"/**/*.ico",

"/**/*.jpg",

"/**/*.png",

"/**/*.woff",

"/**/*.woff2"

)

}

默认拦截所有请求/**,白名单在excludePathPatterns中配置。其中,loginSessionHan-dlerInterceptor是实现了HandlerInterceptor的拦截器。完整代码参考示例工程LoginSession-HandlerInterceptor.kt。

8.1.3 跨域配置

通过重写addCorsMappings方法实现跨域配置的支持,使用CorsRegistry注册类添加路径映射,代码示例如下:

 

override fun addCorsMappings(registry: CorsRegistry) {

super.addCorsMappings(registry)

 

registry.addMapping("/**")

.allowedOrigins("*")

.allowedMethods("PUT, POST, GET, DELETE, OPTIONS")

.allowedHeaders("*")

}

其中

❑addMapping:配置允许跨域的路径。

❑allowedMethods:配置允许访问该跨域资源服务器的请求方法,如:POST、GET、PUT、DELETE等。

❑allowedOrigins:配置允许访问的跨域资源的请求域名。

❑allowedHeaders:配置允许请求header的访问,如:X-TOKEN。

8.1.4 视图控制器配置

通过重写addViewControllers方法,使用ViewControllerRegistry实现视图控制器配置,代码示例如下:

override fun addViewControllers(registry: ViewControllerRegistry) {

super.addViewControllers(registry)

registry.addViewController("/").setViewName("/index")

registry.addViewController("/index").setViewName("/index")

registry.addViewController("/about").setViewName("/about")

registry.addViewController("/error/403").setViewName("/error/403")

registry.addViewController("/error/500").setViewName("/error/500")

}

上面的代码实现与下面的代码在逻辑上是一样的:



@GetMapping(value = ["/", "/index"])

fun index(): String {

return "index"

}

@GetMapping(value = ["/about"])

fun about(): String {

return "about"

}

@GetMapping(value = ["/error/403"])

fun error_403(): String {

return "error/403"

}

@GetMapping(value = ["/error/500"])

fun error_500(): String {

return "error/500"

}

8.1.5 消息转换器配置

HttpMessageConverters(消息转换器)是在HttpMessageConvertersAutoConfiguration类中自动注册的。与HttpMessageConverters(消息转换器)相关的类如下:

StringHttpMessageConverter是Spring Boot默认自动配置的HttpMessageConverter。除了默认的StringHttpMessageConverter,在HttpMessageConvertersAutoConfiguration的自动配置类里还使用了@Import注解,引入了JacksonHttpMessageConvertersConfiguration和Gs-onHttpMessageConverterConfiguration。自动配置的逻辑如下:

1)若jackson的jar包在类路径上,则Spring Boot通过JacksonHttpMessageConverterConfiguration增加MappingJackson2HttpMessage Converter和MappingJackson2XmlHttpMessageConverter。

2)若gson的jar包在类路径上,则Spring Boot通过GsonHttpMessageConverterConfiguration增加GsonHttpMessageConverter。

在Spring Boot中,如果要新增自定义的HttpMessageConverter,则只需定义一个自己的HttpMessageConverters的Bean,然后在此Bean中注册自定义HttpMessageConverter即可。通过覆盖重写configureMessageConverters方法来配置消息转换器。代码示例如下:

 

override fun configureMessageConverters(converters: MutableList

Converter<*>>) {

super.configureMessageConverters(converters)

//创建fastjson消息转换器: FastJsonHttpMessageConverter

val fastConverter = FastJsonHttpMessageConverter()

//创建FastJsonConfig配置类

val fastJsonConfig = FastJsonConfig()

//定制过滤JSON返回

fastJsonConfig.setSerializerFeatures(

SerializerFeature.WriteNullNumberAsZero,

SerializerFeature.DisableCircularReferenceDetect,

SerializerFeature.WriteMapNullValue,

SerializerFeature.WriteNullStringAsEmpty

)

fastConverter.setFastJsonConfig(fastJsonConfig)

//将fastConverter添加到视图消息转换器列表内

converters.add(fastConverter)

}

8.1.6 数据格式化器配置

通过覆盖重写addFormatters方法来添加数据格式化器。Spring MVC接收HTTP请求会把请求参数自动绑定映射到Controller请求参数上。Spring中没有默认配置将字符串转换为日期类型。这个时候,可以通过添加一个DateFormatter类来实现自动转换。

例如,把来自Controller请求参数中String类型的日期数据格式化为Date日期类型,代码如下:

 

override fun addFormatters(registry: FormatterRegistry) {

super.addFormatters(registry)

registry.addFormatter(DateFormatter("yyyy-MM-dd"))

}

8.1.7 视图解析器配置

Spring MVC提供了一个特殊的视图解析器协调类ContentNegotiatingViewResolver,它通过代理给不同的ViewResolver来处理不同的视图。通过覆盖重写configureView-Resolvers()方法来配置视图解析器。下面我们来配置一个FreeMarker的视图解析器,代码如下:

 

override fun configureViewResolvers(registry: ViewResolverRegistry) {

super.configureViewResolvers(registry)

registry.viewResolver(freeMarkerViewResolver())

}

其中,freeMarkerViewResolver()是FreeMarker视图解析器配置,代码如下:

/**

* FreeMarker视图解析器配置

* 配置了@Bean注解,该注解会将方法返回值加入Spring Ioc容器。

* @return

*/

@Bean

open fun freeMarkerViewResolver(): FreeMarkerViewResolver {

val viewResolver = FreeMarkerViewResolver()

// freemarker本身配置了templateLoaderPath而在viewResolver中不需要配置prefix,且路

径前缀必须配置在templateLoaderPath中

viewResolver.setPrefix("")

viewResolver.setSuffix(".ftl")

viewResolver.isCache = false

viewResolver.setContentType("text/html; charset=UTF-8")

viewResolver.setRequestContextAttribute("requestContext")

// 为模板调用时,调用request对象的变量名

viewResolver.order = 0

viewResolver.setExposeRequestAttributes(true);

viewResolver.setExposeSessionAttributes(true);

return viewResolver

}

另外,我们还需要声明一个FreeMarkerConfigurer Bean,这个类是FreeMarker配置类。我们还可以在这里添加自定义的内置变量,以便在前端ftl模板代码中使用。代码如下:

@Bean

open fun freemarkerConfig(): FreeMarkerConfigurer {

val freemarkerConfig = FreeMarkerConfigurer()

freemarkerConfig.setDefaultEncoding("UTF-8")

freemarkerConfig.setTemplateLoaderPath("classpath:/templates/")

var configuration: Configuration? = null

try {

configuration = freemarkerConfig.createConfiguration()

configuration.defaultEncoding = "UTF-8"

} catch (e: IOException) {

log.error("freemarker配置bean, IO异常: {}", e)

} catch (e: TemplateException) {

log.error("freemarker配置bean, TemplateException异常: {}", e)

}

val freemarkerVars = mutableMapOf()

freemarkerVars["rootContextPath"] = environment.getProperty("root.context.path")

freemarkerConfig.setFreemarkerVariables(freemarkerVars)

return freemarkerConfig

}

其中,freemarkerConfig.setTemplateLoaderPath("classpath:/templates/")设置ftl模板文件的加载路径。在FreeMarker中添加内置变量rootContextPath,代码是:



freemarkerVars["rootContextPath"] = environment.getProperty("root.context.path")

freemarkerConfig.setFreemarkerVariables(freemarkerVars)

在前端ftl模板代码中使用的例子是:





<#include 'layout/foot.ftl'>

异常处理实例

下面给出一个实现HandlerExceptionResolver接口的异常处理实例。

首先定义一个使用@Component标注的类WikiHandlerExceptionResolver,该类实现Handler-ExceptionResolver接口中的resolveException()方法,代码如下:



@Component

class WikiHandlerExceptionResolver : HandlerExceptionResolver {

var log = LoggerFactory.getLogger(WikiHandlerExceptionResolver::class.java)

override fun resolveException(httpServletRequest: HttpServletRequest, httpServlet-

Response: HttpServletResponse, o: Any, e: Exception): ModelAndView? {

var ex: Exception = Exception()

// 先处理UndeclaredThrowableException

if (e is UndeclaredThrowableException) {

ex = e.undeclaredThrowable as Exception



}

//这里可根据不同异常引起的类做不同处理方式

val exceptionName = ClassUtils.getShortName(ex::class.java)

if ("NoPermissionException" == exceptionName) {

log.info("WikiHandlerExceptionResolver NoPermissionException ===> {}",

exceptionName)

e.printStackTrace()

//向前台返回错误信息

val model = HashMap()

model.put("stackTrace", e.stackTrace)

model.put("errorMessage", e.message)

model.put("url", httpServletRequest.requestURL)

return ModelAndView("forward:/error/403", model)

}

return null

}

}

你可能感兴趣的:(阅读笔记,springboot,框架,javaweb)