《Spring Boot+Vue全栈开发实战》读书笔记
傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。——–王小波
写在前面
- 嗯,回家处理一些事,所以离职了,之前的公司用开源技术封装了一套自己的低代码平台,所以之前学的spring Boot之类的东西都忘了很多,蹭回家的闲暇时间复习下。
- 笔记整体以 Spring Boot+Vue全栈开发实战一书为方向,中间穿插一些其他视频(原书作者的视频)的知识点。
- 嗯,生活加油,这段时间好好休养,笔记在更新中..整装待发 ^ _ ^,加油生活…
我年青时以为金钱至上,而今年事已迈,发现果真如此 —王尔德
使用XML配置搭建SSM项目
代码详见:https://github.com/LIRUILONGS/SSM-XML.git
新建一个maven工程,构造SSM目录结构
添加依赖,构建配置文件
SpringMVC是Spring的子容器,所以SpringMVC子容器可以访问Spring父容器,反之则不行。所以Spring的配置文件扫描除了Controller的bean,SpringMVC扫描controller的东西。
使用 Java配置类搭建SSM项目
代码详见:https://github.com/LIRUILONGS/SSM-java.git
- @Configuration 注解表示这是一个配置类,在我们这里,这个配置的作用类似于 applicationContext.xml
- @ComponentScan 注解表示配置包扫描,里边的属性和 xml 配置中的属性都是一一对应的,useDefaultFilters 表示使用默认的过滤器,然后又除去 Controller 注解,即在 Spring 容器中扫描除了 Controller 之外的其他所有 Bean 。
- 使用 Java 代码去代替 web.xml 文件,这里会用到 WebApplicationInitializer ,WebInit 的作用类似于 web.xml,这个类需要实现 WebApplicationInitializer 接口,并实现接口中的方法,当项目启动时,onStartup 方法会被自动执行,我们可以在这个方法中做一些项目初始化操作,例如加载 SpringMVC 容器,添加过滤器,添加 Listener、添加 Servlet 等。具体定义如下:

注意:
由于我们在 WebInit 中只是添加了 SpringMVC 的配置,这样项目在启动时只会去加载 SpringMVC 容器,而不会去加载 Spring 容器,如果一定要加载 Spring 容器,需要我们修改 SpringMVC 的配置,在 SpringMVC 配置的包扫描中也去扫描 @Configuration 注解,进而加载 Spring 容器,还有一种方案可以解决这个问题,就是直接在项目中舍弃 Spring 配置,直接将所有配置放到 SpringMVC 的配置中来完成,这个在 SSM 整合时是没有问题的,在实际开发中,较多采用第二种方案,第二种方案,SpringMVC 的配置如下:
静态资源过滤:重写 addResourceHandlers 方法,在这个方法中配置静态资源过滤,这里我将静态资源放在 resources 目录下,所以资源位置是 classpath:/ ,当然,资源也可以放在 webapp 目录下,此时只需要修改配置中的资源位置即可。如果采用 Java 来配置 SSM 环境,一般来说,可以不必使用 webapp 目录,除非要使用 JSP 做页面模板,否则可以忽略 webapp 目录。
视图解析器
1
2
3
4<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>1
2
3
4
5
6
7
8
public class SpringMVCConfig extends WebMvcConfigurationSupport {
protected void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/jsp/", ".jsp");
}
}路径映射:控制器的作用仅仅只是一个跳转,就像上面小节中的控制器,里边没有任何业务逻辑,像这种情况,可以不用定义方法,可以直接通过路径映射来实现页面访问。如果在 XML 中配置路径映射
1
<mvc:view-controller path="/hello" view-name="hello" status-code="200"/>
这行配置,表示如果用户访问 /hello 这个路径,则直接将名为 hello 的视图返回给用户,并且响应码为 200,这个配置就可以替代 Controller 中的方法。
1
2
3
4
5
6
7
8
public class SpringMVCConfig extends WebMvcConfigurationSupport {
protected void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/hello3").setViewName("hello");
}
}JSON 配置SpringMVC 可以接收JSON 参数,也可以返回 JSON 参数,这一切依赖于 HttpMessageConverter。HttpMessageConverter 可以将一个 JSON 字符串转为 对象,也可以将一个对象转为 JSON 字符串,实际上它的底层还是依赖于具体的 JSON 库。
所有的 JSON 库要在 SpringMVC 中自动返回或者接收 JSON,都必须提供和自己相关的 HttpMessageConverter 。
SpringMVC 中,默认提供了 Jackson 和 gson 的 HttpMessageConverter ,分别是:MappingJackson2HttpMessageConverter 和 GsonHttpMessageConverter 。
正因为如此,我们在 SpringMVC 中,如果要使用 JSON ,对于 jackson 和 gson 我们只需要添加依赖,加完依赖就可以直接使用了。具体的配置是在 AllEncompassingFormHttpMessageConverter 类中完成的。
如果开发者使用了 fastjson,那么默认情况下,SpringMVC 并没有提供 fastjson 的 HttpMessageConverter ,这个需要我们自己提供,如果是在 XML 配置中,fastjson 除了加依赖,还要显式配置 HttpMessageConverter,如下:
1 | <mvc:annotation-driven> |
第1章Spring Boot入门
- 提供一个快速的Spring项目搭建渠道
- 开箱即用,很少的Spring 配置就能运行一个Java EE项目。
- 提供了生产级的服务监控方案。
- 内嵌服务器,可以快速部署。
- 提供了一系列非功能性的通用配置。
- 纯Java配置,没有代码生成,也不需要XML配置。
第2章 Spring Boot基础配置
工程创建的三种方式:
- 在线创建
- 通过 IDE 来创建(IntelliJ IDEA、STS)
- 通过改造一个普通的 Maven 工程来实现
2.1不使用spring-boot-starter-parent
spring-boot-starter-parent主要提供了如下默认配置:
- Java版本默认使用1.8.编码格式
- 默认使用UTF-8.
- 提供Dependency Management进行项目依赖的版本管理。
- 默认的资源过滤与插件配置
2.2 @Spring BootApplication.
1 |
|
@Spring BootApplication 是一个组合注解:
- @SpringBootConfiguration原来就是一个@Configuration,所以@Spring BootConfiguration的功能就是表明这是一个配置类。开发者可以在这个类中配置Bean。从这个角度来讲,这个类所扮演的角色有点类似于Spring中applicationContext.xml文件的角色。
- 第二个注解@EnableAutoConfiguration表示开启自动化配置。 Spring Boot中的自动化配置是非侵入式的,在任意时刻,开发者都可以使用自定义配置代替自动化配置中的某一个配置。
- 第三个注解@ComponentScan完成包扫描,也是Spring中的功能。由于@ComponentScan注解默认扫描的类都位于当前类所在包的下面,因此建议在实际项目开发中把项目启动类放在根包。
2.3定制banner
- Spring Boot项目在启动时会打印一个banne
- 定制网站:http://patorjk.com/software/taag
1
2
3
4
5
6
7
8
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplicationBuilder builder = new SpringApplicationBuilder(SpringBootDemoApplication.class);
builder.bannerMode(Banner.Mode.OFF).run(args);
}
}
2.4 Web容器配置
2.4.1 Tomcat配置
1 | ##配置了Web容器的端口号。 |
HTTPS的配置:

1 | ## 密匙文件 |
Spring Boot不支持同时在配置中启动HTTP和HTTPS,这个时候可以配置请求重定向,将HTTP请求重定向为HTTPS请求。配置方式如下:
1 |
|
这里首先配置一个TomcatServletWebServerFactory,然后添加一个Tomcat中的Connector (监听8080端口) ,并将请求转发到8081上去。
2.4.2 Jetty配置
除了Tomcat外,也可以在Spring Boot中嵌入Jetty,从spring-boot-starter-web中除去默认的Tomcat,然后加入Jetty的依赖即可配置方式如下:
1 | <dependencies> |
2.4.3 Undertow配置
Undertow是一个红帽公司开源的Java服务器,具有非常好的性能,在Spring Boot中也得到了很好的支持,配置方式与Jetty类似。
2.5 Properties配置
Spring Boot项目中的·application.properties配置文件一共可以出现在如下4个位置:加载的优先级从1到4依次降低
- 项目根目录下的config文件夹中。
- 项目根目录下。
- classpath 下的config文件夹中。
- classpath 下
application.yml配置文件的优先级与上面一致默认情况下, 如果开发者不想使用application.properties作为配置文件名,也可以自己定义。例如,在resources目录下创建一个配置文件app.properties,然后将项目打成jar包,打包成功后,使用如下命令运行:
2.6类型安全配置属性.
Spring提供了@Value注解以及EnvironmentAware接口来将Spring Environment中的数据注入到属性上, Spring Boot对此进一步提出了类型安全配置属性(Type-safe ConfigurationProperties) ,这样即使在数据量非常庞大的情况下,也可以更加方便地将配置文件中的数据注入Bean中.
yml类型配置文件:
1 | my: |
1 | /** |
2.7 YAML配置
YAML是JSON的超集,简洁而强大,是一种专门用来书写配置文件的语言,可以替代application.properties。在创建一个Spring Boot项目时,引入的spring-boot-starter-web依赖间接地引入了snakeyaml依赖, snakeyaml会实现对YAML配置的解析。YAML的使用非常简单,利用缩进来表示层级关系,并且大小写敏感。在Spring Boot项目中使用YAML只需要在resources目录下创建一个application.yml文件即可,然后向application.yml中添加配置:
1 | server: |
2.8 Profile
开发者在项目发布之前,配置需要频繁更改,例如数据库配置、redis配置、mongodb配置、jms配置等。频·繁修改带来了巨大的工作量, Spring对此提供了解决方案(@Profile注解) , Spring Boot则更进一步提供了更加简洁的解决方案, Spring Boot中约定的不同环境下配置文件名称规则为application-{profile}.properties, profile占位符表示当前环境的名称,具体配置步骤如下:
不同的环境指定不同的配置文件
1 | spring.profiles.active=dev |

第3章Spring Boot整合视图层技术
Spring Boot官方推荐使用的模板引擎是Thymeleaf,不过像FreeMarker也支持, JSP技术在这里并不推荐使用。下面分别向读者介绍Spring Boot整合Thymeleaf和FreeMarker两种视图层技术。
3.1整合Thymeleaf
Thymeleaf是新一代Java模板引擎,类似于Velocity, FreeMarker等传统Java模板引擎。与传统Java模板引擎不同的是, Thymeleaf支持HTML原型,既可以让前端工程师在浏览器中直接打开查看样式,也可以让后端工程师结合真实数据查看显示效果。同时, Spring Boot提供了Thymeleaf自动化配置解决方案,因此在Spring Boot中使用Thymeleaf非常方便。Spring Boot整合Thymeleaf主要可通过如下步骤:
1 | <dependency> |
2.配置Thymeleaf
Spring Boot为Thymeleaf提供了自动化配置类ThymeleafAutoConfiguration,相关的配置属性在ThymeleatProperties类中, ThymeleafProperties部分源码如下:
如果开发者想对默认的Thymeleaf配置参数进行自定义配置,那么可以直接在application.properties中进行配置,部分常见配置如下:
1 | #是否开启缓存,开发时可设置为false,默认为true |
3.2整合FreeMarke
FreeMarker是一个非常古老的模板引擎,可以用在Web环境或者非Web环境中。与Thymeleaf不同, FreeMarker需要经过解析才能够在浏览器中展示出来。FreeMarker不仅可以用来配置HTML页面模板,也可以作为电子邮件模板、配置文件模板以及源码模板等。Spring Boot中对FreeMarker整合也提供了很好的支持.
配置FreeMarker
Spring Boot对FreeMarker也提供了自动化配置类FreeMarkerAutoConfiguration,相关的配置属性在FreeMarkerProperties 中,
1 | #HttpServletRequest的属性是否可以覆盖controller中model的同名项 |


官网:https://freemarker.apache.org/
3.3 整合 JSP
1 | <dependency> |
1 | package com.liruilong.spring_boot_demo.config; |
第4章 Spring Boot整合Web开发.
4.1返回JSON数据
4.1.1 默认实现
JSON是目前主流的前后端数据传输方式, Spring MVC中使用消息转换器HttpMessageConverter对JSON的转换提供了很好的支持,在Spring Boot中更进一步,对相关配置做了更进一步的简化。默认情况下,当开发者新创建一个Spring Boot项目后,添加Web依赖,
这个依赖中默认加入了jackson-databind作为JSON处理器,此时不需要添加额外的JSON处理器就能返回一段JSON了.
如果需要频繁地用到@ResponseBody注解,那么可以采用@RestController 组合注解代替@Controller和@ResponseBody
这是Spring Boot自带的处理方式。如果采用这种方式,那么对于字段忽略、日期格式化等常见需求都可以通过注解来解决。这是通过Spring中默认提供的
MappingJackson2HttpMessageConverter来实现的.HttpMessageConverter,看名字就知道,这是一个消息转换工具,有两方面的功能:
将服务端返回的对象序列化成 JSON 字符串将前端传来的 JSON 字符串反序列化成 Java 对象
所有的 JSON 生成都离不开相关的HttpMessageConverter,SpringMVC 自动配置了Jackson和Gson的 HttpMessageConverter,Spring Boot 中又对此做了自动化配置:org.springframework.boot.autoconfigure.http.JacksonHttpMessageConvertersConfigurationorg.springframework.boot.autoconfigure.http.GsonHttpMessageConvertersConfiguration所以,如果用户使用
jackson和gson的话,没有其他额外配置,则只需要添加依赖即可。
修改转化器
添加一个MappingJackson2HttpMessageConverter,由@ConditionalOnMissingBean确定。
嗯,我们温习一下条件化注解吧
当然这里我们也可以只定义一个ObjectMapper
1 | package com.liruilong.spring_boot_demo.config; |
4.1.2 自定义转换器
当然开发者在这里也可以根据实际需求自定义JSON转换器。常见的JSON处理器除了jackson-databind之外,还有Gson和fastison,这里针对常见用法分别举例.
Gson
Gson是Google的一个开源JSON解析框架。使用Gson,需要先除去默认的jackson-databind,然后加入Gson依赖
1 | <dependency> |
由于Spring Boot中默认提供了Gson的自动转换类GsonHttpMessageConvertersConfiguration,因此Gson的依赖添加成功后,可以像使用jackson-databind那样直接使用Gson。但是在Gson进行·转换时,如果想对日期数据进行格式化,那么还需要开发者自定义HttpMessageConverter.自定义HttpMessageConverter可以通过如下方式。也可以直接使用Gson对象。
1 |
|
fastison
fastjson是阿里巴巴的一个开源JSON解析框架,是目前JSON解析速度最快的开源框架,该框架也可以集成到Spring Boot中。不同于Gson, fastjson继承完成之后并不能立马使用,需要开发者提供相应的HttpMessageConverter后才能使用,集成fastison的步骤如下。
1 | <dependency> |
1 | spring.http.encoding.force-response=true |
对于FastlsonHttpMessageConverter的配置,除了FastJsonHttpMessageConverter 这种方式之外,还有另一种方式。在Spring Boot项目中,当开发者引入spring-boo-starter-web依赖之后,该依赖又依赖了spring-boot-autoconfigure,在这个自动化配置中,有一个webMvcAutoConfiguration类提供了对Spring MVC最基本的配置,如果某一项自动化配置不满足开发需求,开发者可以针对该项自定义配置,只需要实现WebMveConfigurer接口即可(在Spring 5.0之前是通过继承WebMvcConfigurerAdapter类来实现的) ,代码如下:
1 |
|
4.2静态资源访问
在Spring MVC中,对于静态资源都需要开发者手动配置静态资源过滤。Spring Boot中对此也提供了自动化配置,可以简化静态资源过滤配置。
Spring MVC中的配置:
xml
1 | <mvc:resources mapping="/js/**" location="/js/"/> |
由于这是一种Ant风格的路径匹配符,/** 表示可以匹配任意层级的路径,因此上面的代码也可以像下面这样简写:
1 | <mvc:resources mapping="/**" location="/"/> |
java:重写 WebMvcConfigurationSupport 类中的addResourceHandlers方法,在该方法中配置静态资源位置即可
4.2.1默认策略
Spring Boot中对于Spring MVC的自动化配置都在webMvcAutoConfiguration类中,因此对于默认的静态资源过滤策略可以从这个类中一窥究竟。在WebMvcAutoConfiguration类中有一个静态内部类webMvcAutoConfigurationAdapter,实现了4.1节提到的WebMvcConfigurer接口。webMvcConfigurer接口中有一个方法addResourceHandlers是用来配置静态资源过滤的。方法在WebMvcAutoConfigurationAdapter类中得到了实现,部分核心代码如下
Spring Boot在这里进行了默认的静态资源过滤配置,其中staticPathPattern默认定义在WebMvcProperties 中
registration.addResourceLocations(this.resourceProperties.getStaticLocations());获取到的默认静态资源位置定义在ResourceProperties
在一个新创建的Spring Boot项目中,添加了
spring-boot-starter-web依赖之后,在resources目录下分别创建4个目录, 4个目录中放入同名的静态资源(如图4-4所示,数字表示不同位置资源的优先级)
4.2.2自定义策略
自定义静态资源过滤策略有以下两种方式;
在配置文件中定义可以在
application.properties中直接定义过滤规则和静态资源位置,1
2
3
4# 静态资源位置
spring.web.resources.static-locations=classpath:/static/
# 过滤规则
spring.mvc.static-path-pattern=/static/**
Java编码定义也可以通过Java编码方式来定义,此时只需要实现WebMveConfigurer接口即可,然后实现该接口的addResourceHandlers方法,代码如下:1
2
3
4
5
6
7
public class WebMvcConfig implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
}
}
4.3文件上传.
Spring MVC对文件上传做了简化,在Spring Boot中对此做了更进一步的简化,文件上传更为方便。Java中的文件上传一共涉及两个组件,一个是CommonsMultipartResolver,另一个是StandardServletMultipartResolver.
其中CommonsMultipartResolver使用commons-fileupload来处理multipart请求,而StandardServletMultipartResolver则是基于Servlet 3.0来处理multipart请求的,因此若使用StandardServletMultipartResolver,则不需要添加额外的jar包。Tomcat 7.0开始就支持Servlet3.0.
Spring Boot提供的文件上传自动化配置类
MultiparAutoConfiguraton中,默认也是采用StandardServletMultipartResolver
1 | spring.servlet.multipart.max-file-size=1KB |
4.3.1单文件上传
1 |
|
1 | DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("/yyyy/MM/dd/"); |
4.3.2多文件上传
1 |
|
1 |
|
1 |
|
1 |
|
4.3.3AJAX文件上传
1 |
|
4.4 @ControllerAdvice
顾名思义, @ControllerAdvice就是@Controller的增强版。@ControllerAdvice主要用来处理全局数据,一般搭配@ExceptionHandier. @ModelAttribute以及@InitBinder使用。
4.4.1 全局异常处理
上传文件大小超出限制。
1 |
|
4.4.2 添加全局数据
@ControllerAdvice是一个全局数据处理组件,因此也可以在@ControllerAdvice中配置全局数据,使用@ModelAtribute注解进行配置,代码如下:
1 |
|
在全局配置中添加mydata方法,返回一个map.该方法有一个注解@ModelAttribute,其中的value属性表示这条返回数据的key,而方法的返回值是返回数据的value,此时在任意请求的Controller中,通过方法参数中的Model都可以获取info的数据。
4.4.3 请求参数预处理
@ControllerAdvice结合@InitBinder还能实现请求参数预处理,即将表单中的数据绑定到实体类上时进行一些额外处理。
多个实体类存在相同的字段时,会合并字段值,使用ControllerAdvice来做预处理。
1 |
|
1 |
|
在GlobalConfig类中创建两个方法,
- 第一个@InitBinder(“b”)表示该方法是处理@ModelAttribute(“)对应的参数的,
- 第二个@nitBinder(“a”)表示该方法是处理@ModelAttribute(“a”)对应的参数的。
在WebDataBinder对象中,还可以设置允许的字段、禁止的字段、必填字段以及验证器等。
4.5 自定义错误页
Spring Boot中的全局异常处理。在处理异常时,开发者可以根据实际情况返回不同的页面,但是这种异常处理方式一般用来处理应用级别的异常,有一些容器级别的错误就处理不了,例如Filter 中抛出异常,使用@ControllerAdvice定义的全局异常处理机制就无法处理。
因此, Spring Boot中对于异常的处理还有另外的方式,这就是本节要介绍的内容。在Spring Boot 中,默认情况下,如果用户在发起请求时发生了404错误, Spring Boot会有一个默认的页面展示给用户.
Spring Boot中的错误默认是由BasicErrorController类来处理的,该类中的核心方法主要有两个:
·errorHtml方法用来返回错误HTML页面, error用来返回错误JSON,具体返回的是HTML还是JSON,则要看请求头的Accept参数。返回JSON的逻辑很简单,不必过多介绍,返回HTML的逻辑稍微有些复杂,在errorHtml方法中,通过调用resolveErrorView方法来获取一个错误视图的ModelAndView,而resolveErrorView方法的调用最终会来到DefaultErrorViewResolver类中。DefaultErrorViewResolver类是Spring Boot中默认的错误信息视图解析器,部分源码如下:
4.5.1 简单配置.静态页面
要自定义错误页面其实很简单,提供4xx和Sxx页面即可。如果开发者不需要向用户展示详细的错误信息,那么可以把错误信息定义成静态页面,直接,在resources/static 录下创建error目录,然后在error目录中创建错误展示页面。错误展示页面的命名规则有两种:
- 一种是
4xx.html、5xx.html; - 另一种是直接使用响应码命名文件,例如
404.html.405.html, 500.html.第二种命名方式划分得更细,当出错时,不同的错误会展示不同的错误页面
.模板页面
Spring Boot在这里一共返回了5条错误相关的信息,分别是timestamp, status, error, message以及path
若用户定义了多个错误页面,则响应码html页面的优先级高于4xx.html. Sxx.tml页面的优先级,即若当前是一个404错误,则优先展示404.html而不是4xx.html;动态页面的优级高于静态页面,即若resources/templates和resource/static 同时定义了4xx.html,则优先展示resources/templates/4xx.html.
4.5.2 复杂配置
上面这种配置还是不够灵活,只能定义HTML页面,无法处理JSON的定制。Spring Boot中支持对Error信息的深度定制,接下来将从三个方面介绍深度定制:自定义Error数据、自定义Error视图以及完全自定义。
1.自定义Error数据
自定义Error数据就是对返回的数据进行自定义。Spring Boot返回的Error信息一共有5条,分别是timestamp, status, error, message以及path,在BasicErrorController的errorHtml方法和error方法中,都是通过getErrorAttributes方法获取Error信息的。该方法最终会调用到DefaultErrorAttributes类的getErrorAttributes方法,而DefaultErrorAttributes类是在ErrorMvcAutoConfiguration中默认提供的.ErrorMvcAutoConfiguration类的errorAttributes方法源码如下:
源码中可以看出,当系统没有提供ErrorAttributes时才会采用DefaultErrorAttributes.因此自定义错误提示时,只需要自己提供一个ErrorAttributes 可,而DefaultErroAttributes是ErrorAttributes的子类,因此只需要继承DefaultErrorAttributes即可
1 |
|
2,自定义Error视图
Error视图是展示给用户的页面,在BasicErrorController 的errorHtml方法中调用resolveErrorView方法获取一个ModelAndView实例。 resolveErrorView方法是由ErrorViewResolver提供的,通过ErrorMvcAutoConfiguration类的源码可以看到Spring Boot默认采用的ErrorViewResolver是DefaultErrorViewResolver. ErrorMvcAutoConfiguration部分源码如下:
1 |
|
3,完全自定义
前面提到的两种自定义方式都是对BasicErrorController类中的某个环节进行修补。查看Error自动化配置类ErrorMvcAutoConfiguration,读者可以发现BasicErrorController 身只是一个默认的配置,相关源码如下:
从这段源码中可以看到,若开发者没有提供自己的ErrorController,则Spring Boot提供BasicErrorController作为默认的ErrorController,因此,如果开发者需要更加灵活地对Error视图和数据进行处理,那么只需要提供自己的ErrorController即可。提供自己的ErrorController有两种方式:一种是实现ErrorController接口,另一种是直接继承BasicErrorController,由于ErorController接口只提供一个待实现的方法,而BasicErrorController已经实现了很多功能,因此这里选择第二种方式,即通过继承BasicErrorController来实现自己的ErrorController.具体定义如下:
1 |
|
- 自定义
MyErrorController继承自BasicErrorController并添加@Controller注解,将MyErrorController注册到Spring MVC容器中· - 由于
BasicErrorController没有无参构造方法,因此在创建BasicErrorController实例时需要传递参数,在MyErrorController的构造方法上添加@Autowired注解注入所需参数。 - 参考BasicErrorController中的实现,
重写errorHtml和error方法,对Error的视图和数据进行充分的自定义。
4.6 CORS支持
CORS (Cross-Origin Resource Sharing)是由w3C制定的一种跨域资源共享技术标准,其目的就是为了解决前端的跨域请求。在Java EE开发中,最常见的前端跨域请求解决方案是JSONP,但是JSONP只支持GET请求,这是一个很大的缺陷,而CORS则支持多种HTTP请求方法。以CORS
响应头中有一个
Access-Control-Allow-Origin字段,用来记录可以访问该资源的域。当浏览器收到这样的响应头信息之后,提取出Access-Control-Allow-Origin字段中的值,发现该值包含当前页面所在的域,就知道这个跨域是被允许的,因此就不再对前端的跨域请求进行·限制。这就是GET请求的整个跨域流程,在这个过程中,前端请求的代码不需要修改,主.要是后端进行处理。这个流程主要是针对GET,POST以及HEAD请求,并且没有自定义请求头,如果用户发起一个DELETE请求、PUT请求或者自定义了请求头,流程就会稍微复杂一些。以
DELETE请求为例,当前端发起一个DELETE请求时,这个请求的处理会经过两个步骤。第一步:发送一个OPTIONS请求。代码如下:
这个请求将向服务端询问是否具备该资源的DELETE权限,服务端会给浏览器一个响应,代码如下:
服务端给浏览器的响应,Allow头信息表示服务端支持的请求方法,这个请求相当于一个探测请求,当浏览器分析了请求头字段之后,知道服务端支持本次请求,则进入第二步。第二步:发送DELETE请求。接下来浏览器就会发送一个跨域的DELETE请求。
在传统的Java EE开发中,可以通过过滤器统一配置,而Spring Boot中对此则提供了更加简洁的解决方案。在Spring Boot中配置CORS的步骤如下:
3.配置跨域
跨域有两个地方可以配置:
- 一个是直接在相应的请求方法上加注解: 这种配置方式是一种
细粒度的配置.可以控制到每一个方法上。
@CrossOrigin中的value表示支持的域,这里表示来自http://ocalhost:8081域的请求是支持跨域的.maxAge表示探测请求的有效期,在前面的讲解中,读者已经了解到对于DELETE,PUT请求或者有自定义头信息的请求,在执行过程中会先发送探测请求,探测请求不用每次都发送,可以配置一个有效期,有效期过了之后才会发送探测请求。这个属性默认是1800秒,即30分钟。allowedHeaders表示允许的请求头,*表示所有的请求头都被允许。
1 |
|
- 另一种全局配置,代码如下:全局配置需要自定义类实现
1
2
3
4
5
6
7
8
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedHeaders("*")
.allowedMethods("*")
.allowedOrigins("http://localhost:8081")
.maxAge(1800);
}WebMvcConfigurer接口,然后实现接口中的addCorsMappings方法。,在addCorsMappings方法中
addMapping表示对哪种格式的请求路径进行跨域处理;allowedHeaders表示允许的请求头,默认允许所有的请求头信息;allowedMethods表示允许的请求方法,默认是GET. POST和HEAD,*表示支持所有的请求方法;- maxAge表示探测请求的有效期;
- allowedOrigins表示支持的域。
4.7配置类与XML配置.
Spring Boot推荐使用Java来完成相关的配置工作。在项目中,不建议将所有的配置放在一个配置类中,可以根据不同的需求提供不同的配置类,例如专门处理Spring Security的配置类、提供Bean的配置类、Spring MVC相关的配置类。这些配置类上都需要添加@Configuration注解。@ComponentScan注解会扫描所有的Spring组件,也包括@Configuration,@ComponentScan注解在项目入口类的@Spring BootApplication注解中已经提供,因此在实际项目中只需要按需提供相关配置类即可。Spring Boot中并不推荐使用XML配置,建议尽量用Java配置代替XML配置,本书中的案例都是以Java配置为主。
如果开发者需要使用XML配置,只需在resources目录下提供配置文件,然后通过@ImportResource加载配置文件即可。例如,有一个Book类如下:
4.8注册拦截器
Spring MVC中提供了AOP风格的拦截器,拥有更加精细的拦截处理能力。Spring Boot中拦.截器的注册更加方便,步骤如下:
创建拦截器实现Handlerinterceptor接口
1 | ublic class MyInterceptor implements HandlerInterceptor { |
拦截器中的方法将按preHandle-Controller-postHandle-afterCompletion的顺序执行。注意,只有preHandle方法返回true时后面的方法才会执行。当拦截器链内存在多个拦截器时, postHandler在拦截器链内的所有拦截器返回成功时才会调用,而afterCompletion只有preHandle返回true才调用,但若拦截器链内的第一个拦截器的preHandle方法返回false,则后面的方法都不会执行。
配置拦截器。定义配置类进行拦截器的配置,代码如下:
自定义类实现webMveConfigurer接口,实现接口中的addInterceptors方法。其中,addPathPatterns 表示拦截路径, excludePathPatterns表示排除的路径。
1 |
|
4.9启动系统任务
有一些特殊的任务需要在系统启动时执行,例如配置文件加载、数据库初始化等操作。如果没有使用Spring Boot,这些问题可以在Listener中解决。Spring Boot对此提供了两种解决方案:CommandLineRunner和ApplicationRunner. CommandLineRunner和ApplicationRunner基本一致,差别主要体现在参数上。
4.9.1 CommandLineRunner
Spring Boot项目在启动时会遍历所有CommandLineRunner的实现类并调用其中的run方法,如果整个系统中有多个CommandLineRunner的实现类,那么可以使用@Order注解对这些实现类的调用顺序进行排序。
4.9.2 ApplicationRunner
ApplicationRunner的用法和CommandLineRunner基本一致,区别主要体现在run方法的参数上。
1 |
|
1 |
|
@Order注解依然是用来描述执行顺序的,数字越小越优先执行。不同于CommandLineRunner中run方法的String数组参数,这里run方法的参数是一个ApplicationArguments对象,如果想从ApplicationArguments对象中获取入口类中1main方法1接收的参数,调用ApplicationArguments中的getNonOptionArgs方法即可. ApplicationArguments中的getOptionNames方法用来获取项目启动命令行中参数的key,例如将本项目打成jar包,运行java-jar xxx.jar-name-Michael命令来启动项目,此时getOptionNames方法获取到的就是name,而getOptionValues方法则是获取相应的value.
4.10整合Servlet, Filter和Listener.
Spring Boot中对于整合这些基本的Web组件也提供了很好的支持。在一个Spring Boot Web项目中添加如下三个组件:
1 |
|
1 |
|
1 |
|
启动类需要的配置:
在项目入口类上添加@ServletComponentScan注解,实现对Servlet, Filter以及Listener的扫描,代码如下:
1 |
|
4.11 路径映射.
有一些页面在控制器中不需要加载数据,只是完成·简单的跳转,对于这种页面,可以直接配置路径映射,提高访问速度。例如,有两个Thymeleaf做模板的页面login.html和index.tml,直接在MVC配置中重写addViewControllers方法配置映射关系即可:
1 |
|
4.12 配置AOP
4.12.1 AOP简介
AOP中的相关知识
4.12.2 Spring Boot支持
Spring Boot在Spring的基础上对AOP的配置提供了自动化配置解决方案spring-boot-starter-aop,使开发者能够更加便捷地在Spring Boot项目中使用AOP,配置步骤如下。
1 | <dependency> |
1 |
|
4.13 其他
4.13.1 自定义欢迎页
Spring Boot项目在启动后,首先会去静态资源路径下查找index.html作为首页文件,若查找不到,则会去查找动态的index文件作为首页文件.
- 使用
静态的index.html页面作为项目首页,那么只需在resources/static目录下创建index.html文件即可。 - 若想使用动态页面作为项目首页,则需在
resources/templates目录下创建index.html(使用Thymeleaf模板)或者index.fl (使用FreeMarker模板),然后在Controller中返回逻辑视图名,代码如下:
1 |
|
4.13.2 自定义favicon
favicon.ico是浏览器选项卡左上角的图标,可以放在静态资源路径下或者类路径下,静态资源路径下的favicon.ico优先级高于类路径下的favicon.ico。
在线转换网站http:/inaconvert.com/cn/convert-to-ico.php将一张普通图片转为.ico图
4.13.3 除去某个自动配置
Spring Boot中提供了大量的自动化配置类,例如上文提到过的ErrorMvcAutoConfiguration、ThymeleafAutoConfiguration, FreeMarkerAutoConfiguration, MultipartAutoConfiguration等,这些自动化配置可以减少相应操作的配置,达到开箱即用的效果。在Spring Boot的入口类上有一个@Spring BootApplication注解。该注解是一个组合注解, 由@Spring BootConfiguration、@EnableAutoConfiguration以及@ComponentScan组成,其中@EnableAutoConfiguration注解开启自动化配置,相关的自动化配置类就会被使用。如果开发者不想使用某个自动化配置,按如下方式除去相关配置即可.
1 |
|
4.13.4 使用类型转化器
1 |
|
第5章Spring Boot整合持久层技术.
Spring Boot中对常见的持久层框架都提供了自动化配置,例如JabcTemplate, JPA等, MyBatis的自动化配置则是MyBatis官方提供的。
5.1 整合JdbcTemplate
JdbcTemplate是Spring提供的一套JDBC模板框架,利用AOP技术来解决直接使用JDBC时大量重复代码的问题。JdbcTemplate虽然没有MyBatis那么灵活,但是比直接使用JDBC要方便很多。Spring Boot中对JdbcTemplate的使用提供了自动化配置类JdbcTemplateConfiguration,部分源码如下:
1 |
|
1 |
|
需要的依赖:
1 | <dependency> |
spring-bool-starter-jdbc 中提供了spring-jdbc,另外还加入了数据库驱动依赖和数据库连接池依赖
1 | # 数据源1 |
- 创建BookDao,注入
JdbcTemplate.由于已经添加了spring-jdbc相关的依赖,JabcTemplate会被自动注册到Spring容器中,因此这里可以直接注入JdbcTemplate使用。 - 在
JdbcTemplate中,增删改三种类型的操作主要使用update和batchUpdate方法来完成.query和queryForObject方法主要用来完成查询功能。另外,还有execute方法可以用来执行任意的sQL.call方法用来调用存储过程等。 - 在执行查询操作时,需要有一个
RowMapper将查询出来的列和实体类中的属性-一对应起来。如果列名和属性名都是相同的,那么可以直接使用BeanPropertyRowMapper;如果列名和属性名不同,就需要开发者自己实现RowMapper接口,将列和实体类属性-一对应起来。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class BookDao {
JdbcTemplate jdbcTemplate;
public int addBook(Book book) {
return jdbcTemplate.update("INSERT INTO book(name,author) VALUES (?,?)",
book.getName(), book.getAuthor());
}
public int updateBook(Book book) {
return jdbcTemplate.update("UPDATE book SET name=?,author=? WHERE id=?",
book.getName(), book.getAuthor(), book.getId());
}
public int deleteBookById(Integer id) {
return jdbcTemplate.update("DELETE FROM book WHERE id=?", id);
}
public Book getBookById(Integer id) {
return jdbcTemplate.queryForObject("select * from book where id=?",
new BeanPropertyRowMapper<>(Book.class), id);
}
public List<Book> getAllBooks() {
return jdbcTemplate.query("select * from book",
new BeanPropertyRowMapper<>(Book.class));
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14public int addUser2(User user) {
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
int result = jdbcTemplate.update(new PreparedStatementCreator() {
public PreparedStatement createPreparedStatement(Connection connection) throws SQLException {
PreparedStatement ps = connection.prepareStatement("insert into user (username,address) values(?,?)", Statement.RETURN_GENERATED_KEYS);
ps.setString(1, user.getUsername());
ps.setString(2, user.getAddress());
return ps;
}
}, keyHolder);
user.setId(keyHolder.getKey().longValue());
return result;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16public List<User> getAllUsers() {
List<User> list = jdbcTemplate.query("select * from user", new RowMapper<User>() {
public User mapRow(ResultSet resultSet, int i) throws SQLException {
String username = resultSet.getString("username");
String address = resultSet.getString("address");
long id = resultSet.getLong("id");
User user = new User();
user.setId(id);
user.setUsername(username);
user.setAddress(address);
return user;
}
});
return list;
}
5.2整合MyBatis
MyBatis是一款优秀的持久层框架,原名叫作iBaits, 2010年由ApacheSoftwareFoundation迁移到Google Code并改名为MyBatis, 2013年又迁移到GitHub上。MyBatis支持定制化SQL、存储过程以及高级映射。MyBatis几乎避免了所有的JDBC代码手动设置参数以及获取结果集。在传统的SSM框架整合中,使用MyBatis需要大量的XML配置,而在Spring Boot中, MyBatis官方提供了一套自动化配置方案,可以做到MyBatis开箱即用。具体使用步骤如下。
- 添加MyBatis依赖、数据库驱动依赖以及数据库连接池
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.9</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>1
2
3
4spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.url=jdbc:mysql:///chapter05
spring.datasource.username=root
spring.datasource.password=123
方法一
1 |
|
- 一种简单的方式是在配置类上添加
@MapperScan("org.sang.mapper")注解,表示扫描org.sang.mapper包下的所有接口作为Mapper,这样就不需要在每个接口上配置@Mapper注解了。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public interface UserMapper {
User getUserById(Long id);
List<User> getAllUsers();
Integer addUser(User user);
Integer deleteById(Long id);
Integer updateById(String username, Long id);
}
方法二
指明该类是一个Mapper:第一种如前面的代码所示,在BookMapper上添加@Mapper注解,表明该接口是一个MyBatis中的Mapper,这种方式需要在每一个Mapper上都添加注解;
1 |
|
1 |
|
- 针对
BookMapper接口中的每一个方法都在BookMapper.xml中列出了实现 #{}用来代替接口中的参数,实体类中的属性可以直接通过#(实体类属性名}获取。
配置pom.xml文件
在Maven工程中, XML配置文件建议写在resources目录下(同包同级目录),当Mapper.xml文件写在包下, ·Maven在运行时会忽略包下的XML文件,因此需要在pom.xml文件中重新指明资源文件位置,配置如下:
1 | <build> |
也可以自定义resources下mapper位置
1 | mybatis.mapper-locations=classpath:mapper/*.xml |
5.3整合Spring Data JPA
JPA (Java Persistence API)和Spring Data是两个范畴的概念。JPA则是一种ORM规范, JPA和Hibernate的关系就像JDBC与JDBC驱动的关系,即JPA制定了ORM规范,而Hibernate是这些规范的实现(事实上,是先有Hibernate后有JPA, JPA规范的起草者也是Hibernate的作者) ,因此从功能上来说, JPA相当于Hibernate的一个子集。
Spring Data是Spring的一个子项目,致力于简化数据库访问,通过规范的方法名称来分析开发者的意图,进而减少数据库访问层的代码量。Spring Data不仅支持关系型数据库,也支持非关系型数据库。Spring Data JPA可以有效 简化 关系型数据库访问代码。Spring Boot整合Spring Data JPA的步骤如下:
1 | <dependency> |
1 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource |
@Entity注解表示该类是一个实体类,在项目启动时会根据该类自动生成一张表,表的名称即@Entity注解中name的值,如果不配置name,默认表名为类名。所有的实体类都要有主键,@ld注解表示该属性是一个主键,@GeneratedValue注解表示主键自动生成,strategy则表示主键的生成策略。默认情况下,生成的表中字段的名称就是实体类中属性的名称,通过@Column注解可以定制生成的字段的属性,name表示该属性对应的数据表中字段的名称,nullable表示该字段非空。@Transient注解表示在生成数据库中的表时,该属性被忽略,即不生成对应的字段。1
2
3
4
5
6
7
8
9
10
11
12
13
public class Book {
private Integer id;
private String name;
private String author;
private Float price;
private String description;
//省略getter/setter
}- 自定义
BookDao继承自JpaRepository.JpaRepository中提供了一些基本的数据操作方法,有基本的增删改查、分页查询、排序查询等。 - 第
2行定义的方法表示查询以某个字符开始的所有书。· - 第
3行定义的方法表示查询单价大于某个值的所有书。 - 在
Spring Data JPA中,只要方法的定义符合既定规范,Spring Data就能分析出开发者的意图,从而避免开发者定义SQL所谓的既定规范,就是一定的方法命名规则。1
2
3
4
5
6
7
8
9
10public interface BookDao extends JpaRepository<Book,Integer>{
List<Book> getBooksByAuthorStartingWith(String author);
List<Book> getBooksByPriceGreaterThan(Float price);
Book getMaxIdBook();
List<Book> getBookByIdAndAuthor( String author, Integer id);
List<Book> getBooksByIdAndName(String name, Integer id);
}支持的命名规则如表所示:1
2
3
4
5
6
7
8
9
10public interface BookDao extends JpaRepository<Book,Long> {
List<Book> getBookByAuthorIs(String author);
Book maxIdBook();
void updateBookById(String name, Long id);
}
部分方法直接由JpaRepository1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class BookService {
BookDao bookDao;
public void addBook(Book book) {
bookDao.save(book);
}
public Page<Book> getBookByPage(Pageable pageable) {
return bookDao.findAll(pageable);
}
public List<Book> getBooksByAuthorStartingWith(String author){
return bookDao.getBooksByAuthorStartingWith(author);
}
public List<Book> getBooksByPriceGreaterThan(Float price){
return bookDao.getBooksByPriceGreaterThan(price);
}
public Book getMaxIdBook(){
return bookDao.getMaxIdBook();
}
public List<Book> getBookByIdAndAuthor(String author, Integer id){
return bookDao.getBookByIdAndAuthor(author, id);
}
public List<Book> getBooksByIdAndName(String name, Integer id){
return bookDao.getBooksByIdAndName(name, id);
}
}1
2
3
4
5
6
7
8
9
10
11
public void findAll() {
PageRequest pageable = PageRequest.of(2, 3);
Page<Book> page = bookService.getBookByPage(pageable);
System.out.println("总页数:"+page.getTotalPages());
System.out.println("总记录数:"+page.getTotalElements());
System.out.println("查询结果:"+page.getContent());
System.out.println("当前页数:"+(page.getNumber()+1));
System.out.println("当前页记录数:"+page.getNumberOfElements());
System.out.println("每页记录数:"+page.getSize());
}
5.4多数据源.
所谓多数据源,就是一个Java EE项目中采用了不同数据库实例中的多个库,或者同一个数据库实例中多个不同的库。一般来说,采用MyCat等分布式数据库中间件是比较好的解决方案,这样可以把数据库读写分离、分库分表、备份等操作交给中间件去做, Java代码只需要专注于业务即可。不过,这并不意味着无法使用Java代码解决类似的问题,在Spring Framework中就可以配置多数据源, Spring Boot继承其衣钵,只不过配置方式有所变化。
5.4.1 JdbcTemplate多数据源
JdbcTemplate多数据源的配置是比较简单的,因为一个JdbcTemplate对应一个DataSource,开发者只需要手动提供多个DataSource,再手动配置JdbcTemplate即可。具体步骤如下。
1 | # 数据源1 |
DataSourceConfig中提供了两个数据源:dsOne和dsTwo,默认方法名即实例名。@ConfigurationProperties注解表示使用不同前缀的配置文件来创建不同的DataSource实例。1
2
3
4
5
6
7
8
9
10
11
12
13
public class DataSourceConfig {
DataSource dsOne() {
return DruidDataSourceBuilder.create().build();
}
DataSource dsTwo() {
return DruidDataSourceBuilder.create().build();
}
}1
2
3
4
5
6
7
8
9
10
11
public class JdbcTemplateConfig {
JdbcTemplate jdbcTemplateOne( DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
JdbcTemplate jdbcTemplateTwo( DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}JdbcTemplateConfig中提供两个JdbcTemplate实例。每个JdbcTemplate实例都需要提供-DataSource,由于Spring容器中有两个DataSource实例,因此需要通过方法名查找。@Qualifier注解表示查找不同名称的DataSource实例注入进来1
2
3
4
5
6
7
// @Autowired
JdbcTemplate jdbcTemplate;
JdbcTemplate jdbcTemplateTwo;
5.4.2 MyBatis多数据源
1 | # 数据源1 |
1 |
|
1 |
|
1 |
|
5.4.3 JPA多数据源
1 | spring.datasource.one.password=123 |
这里的配置与配置单独的JPA有区别,因为在后文的配置中要从JpaProperties中的getProperties方法中获取所有JPA相关的配置, 因此这里的属性前缀都是spring.jpa.properties
1 |
|
1 |
|
- 使用
@EnableJpaRepositories注解来进行JPA的配置,该注解中主要配置三个属性:basePackages,entityManagerFactoryRef以及transactionManagerRef.其中,basePackages用来指定Repository所在的位置,entityManagerFactoryRef用来指定实体类管理工厂Bean的名称,transactionManagerRef则用来指定事务管理器的引用名称,这里的引用名称就是JpaConfigOne类中注册的Bean的名称(默认的Bean名称为方法名) - 创建
LocalContainerEntityManagerFactoryBean,该Bean将用来提供EntityManager实例,在该类的创建过程中,首先配置数据源,然后设置JPA相关配置(JpaProperties由系统自动加载),再设置实体类所在的位置,最后配置持久化单元名,若项目中只有一个EntityManagerFactory, 则persistenceUnit可以省略掉,若有多个,则必须明确指定持久化单元名。 - 由于项目中会提供两个
LocalContainerEntityManagerFactoryBean实例,第12行的注解@Primary表示当存在多个LocalContainerEntityManagerFactoryBean实例时,该实例将被优先使用。
+PlatformTransactionManager表示创建一个事务管理器。JpaTransactionManager提供对单个EntityManagerFactory的事务支持,专门用于解决JPA中的事务管理。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class JpaConfigTwo {
DataSource dsTwo;
JpaProperties jpaProperties;
LocalContainerEntityManagerFactoryBean entityManagerFactoryBeanTwo(
EntityManagerFactoryBuilder builder) {
return builder.dataSource(dsTwo)
.properties(jpaProperties.getProperties())
.packages("org.sang.model")
.persistenceUnit("pu2")
.build();
}
PlatformTransactionManager platformTransactionManagerTwo(
EntityManagerFactoryBuilder builder) {
LocalContainerEntityManagerFactoryBean factoryTwo = entityManagerFactoryBeanTwo(builder);
return new JpaTransactionManager(factoryTwo.getObject());
}
}
第6章Spring Boot整合NosQL
NoSQL是指非关系型数据库,非关系型数据库和关系型数据库两者存在许多显著的不同点,,其中最重要的是NoSQL不使用SQL作为查询语言。其数据存储可以不需要固定的表格模式,一般.都有水平可扩展性的特征。NoSQL主要有如下几种不同的分类:
Key/Value键值存储。这种数据存储通常都是无数据结构的,一般被当作字符串或者二进制数据,但是数据加载速度快,典型的使用场景是处理高并发或者用于日志系统等,这一类的数据库有Redis.Tokyo Cabinet等.列存储数据库。列存储数据库功能相对局限,但是查找速度快,容易进行分布式扩展,一般用于分布式文件系统中,这一类的数据库有HBase,Cassandra等。文档型数据库 。和`Key/Value`键值存储类似,文档型数据库也没有严格的`数据格式`,这既是缺点也是优势,因为不需要预先创建表结构,数据格式更加灵活,一般可用在`Web`应用中,这一类数据库有`MongoDB`, `CouchDB`等。图形数据库 。图形数据库专注于`构建关系图谱`,例如`社交网络`,`推荐系统`等,这一类的数据库有`Neo4J`、`DEX`等。
6.1整合Redis
Redis是一个使用C编写的基于内存的NoSQL数据库,它是目前最流行的键值对存储数据库。Redis由一个Key, Value映射的字典构成,与其他NoSQL不同, Redis中Value的类型不局限于字符串,还支持列表、集合、有序集合、散列等。
6.1.1 Redis简介
Redis不仅可以当作缓存使用,也可以配置数据持久化后当作NoSQL数据库使用, 目前支持两种持久化方式:快照持久化和AOF持久化。另一方面, Redis也可以搭建集群或者主从复制结构,在高并发环境下具有高可用性。
6.1.2 Redis安装
1 | Loaded plugins: fastestmirror, product-id, search-disabled-repos, subscription-manager |
6.1.3 Redis整合Spring Boot
Redis的Java客户端有很多,例如Jedis、JRedis、 Spring Data Redis等, Spring Boot借助于Spring. Data Redis为Redis提供了开箱即用自动化配置,开发者只需要添加相关依赖并配置Redis连接信息即可,具体整合步骤如下。
添加如下依赖:
1 | <dependency> |
默认情况下, spring-boot-starter-data-redis使用的Redis工具是Lettuce,考虑到有的开发者习惯使用Jedis,因此可以从spring-boot-starter-data-redis中排除Lettuce并引入Jedis,修改为如下依赖:
配置Redis接下来在application.properties 中配置Redis连接信息
1 | #基本连接信息配置 |
在·Spring Boot·的自动配置类中提供了·RedisAutoConfiguration·进行Redis的配置,部分源码
由这一段源码可以看到, application.properties中配置的信息将被注入RedisProperties中,如果开发者自己没有提供RedisTemplate或者StringRedis Template实例,则Spring Boot默认会提供这两个实例, RedisTemplate和StringRedisTemplate实例则提供了Redis的基本操作方法。
1 |
|
StringRedisTemplate是RedisTemplate的子类,StringRedisTemplate中的key和value都是字符串,采用的序列化方案是StringRedisSerializer,而RedisTemplate则可以用来操作对象,RedisTemplate采用的序列化方案是JdkSerializationRedisSerializer.无论是StringRedis Template还是RedisTemplate,操作Redis的方法都是一致的。StringRedisTemplate和RedisTemplate都是通过opsForValue,opsForZSet或者opsForSet等方法首先获取一个操作对象,再使用该操作对象完成数据的读写。- 第10行向Redis中存储一条记录,第11行将之读取出来,第18行向Redis中存储一个对象,第19行将之读取出来。
6.1.4 Redis集群整合Spring Boot.
1,搭建Redis集群
·(1)集群原理·在Redis集群中,所有的Redis节点彼此互联,节点内部使用二进制协议优化传输速度和带宽。当一个节点挂掉后,集群中超过半数的节点检测失效时才认为该节点已失效。不同于Tomcat集群需要使用反向代理服务器, Redis集群中的任意节点都可以直接和Java客户端连接。
Redis集群上的数据分配则是采用哈希槽(HASH SLOT) , Redis集群中内置了16384个哈希槽,当有数据需要存储时, Redis会首先使用CRC16算法对key进行计算,将计算获得的结果对16384取余,这样每一个key都会对应一个取值在0-16383之间的哈希槽, Redis则根据这个余数将该条数据存储到对应的Redis节点上,开发者可根据每个Redis实例的性能来调整每个Redis实例上哈希槽的分布范伟
6.2 整合MongoDB.
6.2.1 MongoDB简介
·MongoDB·是一种面向文档的数据库管理系统,它是一个介于关系型数据库和非关系型数据库,之间的产品, ·MongoDB·功能丰富,它支持一种类似JSON的BSON数据格式,既可以存储简单的数据格式,也可以存储复杂的数据类型。·MongoDB·最大的特点是它支持的查询语言非常强大,并且还支持对数据建立索引。总体来说, ·MongoDB·是一款应用相当广泛的NosQL数据库。
6.2.2 MongoDB安装
關於Mongodb的學習《MongoDB大数据处理权威指南》读书笔记:https://blog.csdn.net/sanhewuyang/article/details/107597408
6.2.3 MongoDB整合Spring Boot.
借助于Spring Data MongoDB, Spring Boot为MongoDB也提供了开箱即用的自动化配置方案,具体配置步骤如下
1 | <dependency> |
1 | spring.data.mongodb.authentication-database=admin |
1 | public interface BookDao extends MongoRepository<Book,Integer> { |
使用MongoTemplate除了继承MongoRepository外,Spring Data MongoDB还提供了MongoTemplate用来方便地操作MongoDB。在Spring Boot中,若添加了MongoDB相关的依赖,而开发者并没有提供MongoTemplate ,则默认会有一个MongoTemplate注册到Spring容器中,相关配置源码在MongoDataAutoConfiguration类中。因此,用户可以直接使用MongoTemplate,在Controller中直接注入MongoTemplate就可以使用了,添加如下代码到第5步的Controller中:
1 |
|
6.3 Session共享
正常情况下, HttpSession是通过Servlet容器创建并进行管理的,创建成功之后都是保存在内存中。如果开发者需要对项目进行横向扩展搭建集群,那么可以利用一些硬件或者软件工具来做负载均衡,此时,来自同一用户的HTTP请求就有可能被分发到不同的实例上去,如何保证各个实例之间Session的同步就成为一个必须解决的问题。
Spring Boot提供了自动化的Session共享配置,它结合Redis可以非常方便地解决这个问题。使用Redis解决Session共享问题的原理非常简单,就是把原本存储在不同服务器上的Session拿出来放在一个独立的服务器上.
当一个请求到达Nginx服务器后,首先进行请求分发,假设请求被real serverl处理了, real server在处理请求时,无论是存储Session还是读取Session,都去操作Session服务器而不是操作自身内存中的Session,其他real server在处理请求时也是如此,这样就可以实现Session共享了
6.3.1 Session共享配置
1 | <dependency> |
除了Redis依赖之外,这里还要提供spring-session-data-redis依赖, Spring Session可以做到透·明化地替换掉应用的Session容器。项目创建成功后,在application.properties中进行Redis基本连接信息配置,代码如下:
1 | spring.redis.database=0 |
添加··@EnableRedisHttpSession
1 | /** |
- maxInactiveIntervalInSeconds: 设置 Session 失效时间,使用 Redis Session 之后,原 Spring Boot 的server.session.timeout 属性不再生效。
- 经过上面的配置后,Session调用就会自动去Redis存取。另外,想要达到Session共享的目的,只需要在其他的系统上做同样的配置即可。
@EnableRedisHttpSession源码
1 |
|
测试一下
1 |
|
6.3.2 Nginx负载均衡
关于Nginx,可以访问Nginx 学习笔记(《深入理解Nginx:模块开发与架构解析》读书笔记):https://blog.csdn.net/sanhewuyang/article/details/114488191nginx.conf·配置文件修改:
1 | upstream backend { |
第7章构建RESTful服务
7.1 REST简介
REST (Representational State Transfer)是一种Web软件架构风格,它是一种风格,而不是标准,匹配或兼容这种架构风格的网络服务称为REST服务。REST服务简洁并且有层次, REST通常基于HTTP,URI和XML以及HTML这些现有的广泛流行的协议和标准。
在REST中,资源是由URI来指定的,对资源的增删改查操作可以通过HTTP协议提供的GET, POST, PUT, DELETE等方法实现。使用REST可以更高效地利用缓存来提高响应速度,同时REST中的通信会话状态由客户端来维护,这可以让不同的服务器处理一系列请求中的不同请求,进而提高服务器的扩展性。在前后端分离项目中,一个设计良好的Web软件架构必然要满足REST风格。在Spring MVC框架中,开发者可以通过@RestController注解开发一个RESTful服务,不过,Spring Boot对此提供了自动化配置方案,开发者只需要添加相关依赖就能快速构建一个RESTful服务。
7.2 JPA实现REST
在Spring Boot 中,使用Spring Data JPA和Spring Data Rest可以快速开发出一个RESTful应用。接下来向读者介绍Spring Boot中非常方便的RESTful应用开发。
7.2.1 基本实现
这里的依赖除了数据库相关的依赖外,还有Spring Data JPA的依赖以及Spring Data Rest的依赖。项目创建完成后,在application.properties 中配置基本的数据库连接信息:
1 | <dependency> |
这里的依赖除了数据库相关的依赖外,还有Spring Data JPA的依赖以及Spring Data Rest的依赖。项目创建完成后,在application.properties中配置基本的数据库连接信息:
1 | spring.datasource.type=com.alibaba.druid.pool.DruidDataSource |
创建实体类,创建BookRepository类继承JpaRepository, JpaRepository中默认提供了一些基本的操作方法,代码如下:
1 | public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { |
7.2.2 自定义请求路径
默认情况下,请求路径都是实体类名小写加s,如果开发者想对请求路径进行重定义,通过@RepositoryRestResource注解即可实现,下面的案例只需在BookRepository上添加@RepositoryRestResource注解即可:
1 |
|
@RepositoryRestResource·注解的·path·属性表示将所有请求路径中的books都修改为bs,如http://ocalhost: 8080/bs:collectionResourceRel属性表示将返回的JSON集合中book集合的key修改为bs;itemResourceRel表示将返回的JSON集合中的单个book的key修改为b,
7.2.3 自定义查询方法.
默认的查询方法支持分页查询、排序查询以及按照id查询,如果开发者想要按照某个属性查询,只需在BookRepository中定义相关方法并暴露出去即可,代码如下:
1 |
|
- ·
自定义查询只需要在BookRepository中定义相关查询方法即可,方法定义好之后可以不添加@RestResource注解,默认路径就是方法名。以第4行定义的方法为例,若不添加@RestResource注解, 则默 认 该方法的调用路径为http://ocalhost:8080/bs/search/indByAuthorContains?author=鲁迅。如果想对查询路径进行自定义,只需要添加@RestResource注解即可,path属性即表示最新的路径。还是以第4行的方法为例,添加@RestResource(path = "author",rel = "author")注解后的查询路径为”http://ocalhost:8080/bs/search/author?author=鲁迅". - 用户可以直接访问
http/ocalhost:8080/bs/search路径查看该实体类暴露出来了哪些查询方法,默认情况下,在查询方法展示时使用的路径是方法名,通过@RestResource注解中的rel属性可以对这里的路径进行重定义,如图7-6所示。
7.2.4 隐藏方法
默认情况下,凡是继承了Repository接口(或者Repository的子类)的类都会被暴露出来,即开发者可执行基本的增删改查方法。以上文的BookRepository为例,如果开发者提供了BookRepository继承自Repository,就能执行对Book的基本操作,如果开发者继承了Repository但是又不想暴露相关操作,做如下配置即可:
1 | //@RepositoryRestResource(exported = false) |
将·@RepositoryRestResource注解中的exported属性置为false之后,则增删改查接口都会失效, BookRepository类中定义的相关方法也会失效。若只是单纯地不想暴露某个方法,则在方法上进行配置即可,例如开发者想屏蔽DELETE接口.
7.2.5 配置CORS
在4.6节已经向读者介绍了CORS两种不同的配置方式,一种是直接在方法上添加@CrosSorigin注解,另一种是全局配置。全局配置在这里依然适用,但是默认的RESTful工程不需要开发者自己提供Controller,因此添加在Controller的方法上的注解可以直接写在BookRepository上,代码如下:接口跨域:@CrossOrigin注解添加到某一个方法上即可。
1 | //@CrossOrigin |
7.2.6其他配置
application.properties配置
1 | ##每页默认记录数,缺省值为20 |
当然,这些XML配置也可以在Java代码中配置,且代码中配置的优先级高于application.properties配置的优先级,代码如下
1 |
|
7.2.7 JPA使用rest自定义链接
1 |
|
7.3 MongoDB实现REST
MongoDB整合Spring Boot,而使用Spring Boot快速构建RESTful·服务除了结合Spring Data JPA之外,也可以结合Spring Data MongoDB实现。使用Spring DataMongoDB构建RESTful服务也是三个步骤,分别如下。
1 | <dependency> |
这里Spring Data Rest的依赖和7.2节中的一致,只是将Spring Data JPA的依赖变为Spring DataMongoDB的依赖。项目创建成功后,在application.properties中配置MongoDB的基本连接信息,
1 | spring.data.mongodb.authentication-database=test |
1 | public interface BookRepository extends MongoRepository<Book,Integer> { |
第8章开发者工具与单元测试
8.1 devtools简介
Spring Boot中提供了一组开发工具spring-boot-devtools,可以提高开发者的工作效率,开发者可以将该模块包含在任何项目中, spring-boot-devtools最方便的地方莫过于热部署了。
8.2 devtools实战
8.2.1 基本用法
1 | <dependency> |
- 这里多了一个optional选项,是为了防止将
devtools依赖传递到其他模块中。当开发者将应用打包运行后,devtools会被自动禁用。 - 当开发者将
spring-boot-devtools引入项目后,只要classpath路径下的文件发生了变化,项目就会自动重启,这极大地提高了项目的开发速度。
8.2.2 基本原理
Spring Boot中使用的自动重启技术涉及两个类加载器,一个是baseclassloader,用来加载不会变化的类,例如项目引用的第三方的jar;另一个是restartclassloader,用来加载开发者自己写的会·变化的类。当项目需要重启时, restartclassloader将被一个新创建的类加载器代替,而baseclassloader则继续使用原来的,这种启动方式要比冷启动快很多,因为baseclassloader已经存在并且已经加载好
8.3单元测试
8.3.1 基本用法
当开发者使用Intelli IDEA或者在线创建一个Spring Boot项目时,创建成功后,默认都添加了spring-bool-starter-est依赖,并且创建好了测试类。
1 |
|
@RunWith注解,该注解将JUnit执行类修改为SpringRunner,而SpringRunner是Spring Framework中测试类SpringJUnit4ClassRunner的别名。@Spring BootTest注解除了提供Spring TestContext中的常规测试功能之外,还提供了其他特性:提供默认的ContextLoader, 自动搜索@Spring BootConfiguration、自定义环境属性、为不同的webEnvironment模式提供支持,这里的webEnvironment模式主要有4种.這裏不説了。
8.3.2 Service测试
1 |
|
1 |
|
8.3.3 Controller测试.
1 |
|
1 |
|
1 | MockMvc mockMvc; |
除了MockMvc这种测试方式之外, Spring Boot还专门提供了TestRestTemplate用来实现集成测试,若开发者使用了@Spring BootTest注解,则TestRestTemplate将自动可用,直接在测试类中注入即可。注意,如果要使用TestRestTemplate进行测试,需要将@Spring BootTest注解中webEnvironment属性的默认值由WebEnvironment.MOCK修改为webEnvironment.DEFINED PORT或者WebEnvironment.RANDOM PORT,因为这两种都是使用一个真实的Servlet环境而不是模拟的Serlet环境。其代码如下:
1 |
1 |
|
- test2方法演示了POST请求如何传递JSON数据,首先在32行将一个book对象转为一段JSON,然后在36行设置请求的contentType为APPLICATION-JSON,最后在37行设置content为上传的JSON即可。
8.3.4 JSON测试
开发者可以使用@JsonTest测试JSON序列化和反序列化是否工作正常,该注解将自动配置Jackson ObjectMapper.@JsonComponent以及Jackson Modules.如果开发者使用Gson代替Jackson,该注解将配置Gson,具体用法如下:
1 |
|
第9章Spring Boot缓存
Spring 3.1中开始对缓存提供支持,核心思路是对方法的缓存,当开发者调用一个方法时,将方法的参数和返回值作为key/value缓存起来,当再次调用该方法时,如果缓存中有数据,就直接,从缓存中获取,否则再去执行该方法。但是, Spring中并未提供缓存的实现,而是提供了一套缓存API,开发者可以自由选择缓存的实现, 目前Spring Boot支持的缓存有如下几种:Cache (JSR-107)、EhCache 2.x、 Hazelcast、Infinispan、Couchbase 、Redis、Caffeine、Simple
9.1 Ehcache 2.x缓存.
Ehcache缓存在Java开发领域已是久负盛名,在Spring Boot中,只需要一个配置文件就可以将Ehcache集成到项目中。Ehcache 2.x的使用步骤如下。
1 | <dependency> |
2.添加缓存配置文件如果Ehcache的依赖存在,并且在classpath下有一个名为ehcache2.xml的Ehcache配置文件,那么EhCacheCacheManager将会自动作为缓存的实现。因此,在resources目录下创建ehcache.xml文件作为Ehcache缓存的配置文件,代码如下:
1 | <ehcache> |
这是一个常规的Ehcache配置文件,提供了两个缓存策略,一个是默认的,另一个名为book-cache.其中,
name表示缓存名称;maxElementsInMemory表示缓存最大个数:eternal表示缓存对象是否永久有效,一旦设置了永久有效,timeout将不起作用;timeToldleSeconds表示缓存对象在失效前的允许闲置时间(单位:秒) ,当eternal-false对象不是永久有效时,该属性才生效;timeToLiveSeconds表示缓存对象在失效前允许存活的时间(单位:秒),当eternal-false对象不是永久有效时,该属性才生效;overflowToDisk表示当内存中的对象数量达到maxElementsInMemory时, Ehcache是否将对象写到磁盘中;diskExpiryThreadIntervalSeconds表示磁盘失效线程运行时间间隔。
另外,如果开发者想自定义Ehcache配置文件的名称和位置,可以在application.properties中添加如下配置:
1 | spring.cache.ehcache.config=classpath:ehcache2.xml |
1 |
|
1 |
|
9.2 Redis单机缓存
9.3 Redis集群缓存
9.3.1 搭建Redis集群.
9.3.2 配置缓存
9.3.3 使用缓存
第10章 Spring Boot安全管理…
《Spring Boot+Vue全栈开发实战》读书笔记
https://liruilongs.github.io/2021/06/18/Java/《Spring Boot+Vue全栈开发实战》读书笔记/











