精通SpringMVC4

 

第1章 快速搭建Spring Web应用

1.1 Spring Tool Suite简介

 

如果你是一个喜欢用spring的人,你可能会在欣赏spring的强大功能外,对其各样的配置比较郁闷,尤其是相差较大的版本在配置文件方面会存在差异,当然你可以去花不少的时间去网上查找相关的资料,当你准备使用更高版本spring的时候,但这无异会让人感觉烦恼。spring其实也早就意识到了这一点,并针对此给出了很好的解决方法,那就是在基于Eclipse的基础上,spring提供了针对Spring开发的Spring Tool Suite集成开发工具,通过该工具,可以很轻易地生成一个spring的工程,比如web工程,最令人兴奋的是工程里的配置文件都会自动为你生成,你再也不用操心配置文件的格式及各种配置文件了。

Spring Tool Suite的官方下载地址是:

http://www.springsource.org/downloads/sts-ggts

1.2 IntelliJ简介

1.3 start.Spring.io简介

https://start.spring.io/

1.4 命令行方式简介

可以使用 curl http://start.Spring.io的方式

在控制台采用这种方式的话,将会需要使用一些指令,帮助我们组织curl请求;

这样可以不离开控制台就能开始使用Spring。

Git使用

GIT学习推荐地址:

https://learngitbranching.js.org/

一个很好的交互式教程,可以引导你在线学习git命令;

https://try.github.io/

1.5 正式开始

【可以运行的JAR】

Spring Boot主要的一个优势在于将应用所需要的所有内容都放到一个易于重发布的JAR文件中,其中包含了Web服务器。如果你运行该jar,Tomcat将会启动运行,如果要将其部署到生产环境或者云中,这都是非常便利的;

1 Gradle 构建

Gradle可以视为Maven的继承者,它是一个现代化的构架工具,与Maven类似,它会使用约定,Gradle真正的闪光点在于,它允许我们使用Groovy DSL编写自己的构建任务。默认库使得管理文件、声明任务之间的依赖以及增量执行job都变得非常容易;

可以使用Gradle运行应用,替换借助IDE来执行应用的方式

2. 代码

@SpringBootApplication注解:

@SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfiguration + @ComponentScan

@Configuration   @EnableAutoConfiguration   @ComponentScan

1@Configuration的注解类标识这个类可以使用Spring IoC容器作为bean定义的来源。@Bean注解告诉Spring,一个带有@Bean的注解方法将返回一个对象,该对象应该被注册为在Spring应用程序上下文中的bean

2@EnableAutoConfiguration:能够自动配置spring的上下文,试图猜测和配置你想要的bean类,通常会自动根据你的类路径和你的bean定义自动配置。

如果你将其移除的话,就无法从Spring Boot的自动配置中收益了。

3@ComponentScan:会自动扫描指定包下的全部标有@Component的类,并注册成bean,当然包括@Component下的子注解@Service,@Repository,@Controller

在默认情况下,@ComponentScan注解会扫描当前包以及该包下的所有子包;

 

1.6 幕后的Spring Boot

使用Spring MVC应用,使用XML配置或者java注解配置类搭建的过程一般为:

详细步骤参考如下链接:

  1. 初始化Spring MVC 的DispatcherServlet;
  2. 搭建转码过滤器,保证客户端请求进行正确的转码;

可以使用org.springframework.web.filter.CharacterEncodingFilter

         注意:

                   如果使用@ResponseBody出现了中文乱码,则可以通过配置RequestMappingHanlderAdapter中配置messageConverters设置StringHttpMessageConverter的supportedMediaTypes的value为:text/html;charset=UTF-8

  1. 搭建视图解析器(View Resolver),告诉Spring去哪里查找视图,以及它们是使用哪种方言编写的(JSP、Thymeleaf等);
  2. 配置静态资源的位置(CSS、JS);

注意:可以自定义过滤器Filter对静态资源进行压缩,使用response.setHeader(“Content-Encoding”,GZIP); 需要先判断浏览器是否支持GZIP

  1. 配置所支持的地域以及资源bundle;
  2. 配置multipart解析器,保证文件上传能够正常工作;
  3. 将Tomcat或者Jetty包含进来,从而能够在Web服务器上运行;
  4. 建立错误页面如(404);

例如:

在web.xml中配置如下:

<error-page>

         <error-code>404</error-code>

         <location>/err/404.jsp</location>

</error-page>

不过,Spring Boot为我们处理了所有的事情,因为这些配置一般是与应用相关的,所以你可以无限制的将它们组合;

在一定程度上,Spring Boot是带有一定程度倾向性的Spring项目配置器,它基于约定,并且默认会在你的项目中使用这些约定;

【application.properties配置详解】

http://blog.csdn.net/je_ge/article/details/54783184

Spring Boot 整合Spring MVC

SpringBoot上实现自定义Starter功能应该都是如下套路: 
1、在自定义的XXAutoConfigurationImport一个ImportBeanDefinitionRegistrar来注入指定Bean 
2
、添加自定义的BeanPostProcessorBean初始化之前或之后完成配置功能或初始化某些依赖功能

1 分发器和multipart配置

  1. 分发器的配置

@Order(Ordered.HIGHEST_PRECEDENCE)

@Configuration

@ConditionOnWebApplication

@ConditionOnClass(DispatcherServlet.class)

@AutoConfigureAfter(EmbeddServletContainerAutoConfiguration.class)

public class DispatcherServletAutoConfiguration{}

Spring Boot中通过DispatcherServletAutoConfiguration类完成DispatcherServlet的功能,替代了原来在web.xml中配置分发器的步骤;

说明:

  1. 与其他的Spring配置类相同,它使用了@configuration注解;
  2. 一般会通过@Order注解来声明优先等级,可以看到DispatcherServletAutoConfiguration需要优先进行配置;
  3. 使用@AutoConfiguration或者@AutoConfigureBefore从而进一步细化配置处理的顺序;
  4. 通过使用@ConfigurationOnClass(DispatcherServlet.class)这个特殊的配置,能够确保我们的类路径下包含DispatcherServlet,这能很好的表明Spring MVC位于类路径中,并且希望将其启动;
  5. multipart的配置

通过了解DispatcherServletAutoConfiguration代码,便可以了解为什么不需要在SpringBoot中配置,便拥有分发器Servlet和multipart解析器;

Spring Boot仅仅是基于常见的使用场景,帮助我们对应用进行配置,不过,可以在任意的地方覆盖掉这些值,并声明自己的配置;

2 视图解析器、静态资源以及区域配置

WebMvcAutoConfiguration声明了视图解析器、地域解析器(localeresolver)以及静态资源的位置。

该类中对于视图解析器的配置没有什么特殊之处,使用了配置属性,从而允许用户对其进行自定义;

@Value(“${spring.view.prefix:}”)

@Value(“${spring.view.suffix:}”)

资源位置的声明有些复杂,但是通过它,可以了解到两点:

  1. 对带有“webjar”前缀的资源访问将会在类路径中解析,这样就可以使用Maven中央仓库中预先打包好的JavaScript依赖;
  2. 静态资源需要放在类路径中,并且需要放置在以下4个目录中的一个任意一个:

/META-INF/resources/

/resources/

/static/

/public/

提示:WebJars是JAR包格式的客户端JavaScript库,可以通过Maven中央仓库来获取

在WebMvcAutoConfiguration类文件中,还专门声明了一个地域管理:

localResolver

默认的地域解析器只会处理一个地域,并且允许我们通过spring.mvc.local配置属性来进行定义;

1.7 错误和转码配置

ErrorMvcAutoConfiguration

配置介绍:

  1. 定义了一个DefaultErrorAttributes,它通过特定的属性暴露了有用的错误信息,这些属性包括状态、错误码和相关的栈跟踪信息;
  2. 定义了一个BasicErrorController bean,这是一个MVC控制器,负责展现我们看到的错误页面;
  3. 允许我们将Spring Boot中的whitelabel错误页面设置为无效,这需要将配置文件application.properties中的error.whitelable.enabled设置为false;
  4. 我们还可以通过借助模板引擎提供自己的错误页面。例如:ErrorTemplateMissingCondition条件会对此进行检查;

至于转码的问题,HttpEncodingAutoConfiguration将会负责处理先关的事宜,这是通过提供Spring的CharacterEncodingFilter类来实现的。通过spring.http.encoding.charset配置,默认编码为UTF-8

也可以通过spring.http.encoding.enabled禁用这项配置;

1.8 嵌入式Servlet容器(Tomcat)的配置

默认情况下,Spring Boot在打包和运行应用的时候,会使用Tomcat嵌入式API(Tomcat embedded API)

使用的类为:EmbeddedServletContainerAutoConfiguration

可以将Spring Boot与Tomcat、tc-server、Jetty或者Undertow结合使用。

服务器可以很容易的进行切换,只需要将spring-boot-starter-tomcat JAR依赖移除掉,并将其替换为Jetty或者Undertow对应的依赖即可;

1. HTTP端口

通过在application.properties文件中定义server.port属性或者定义名为SERVER_PORT的环境变量,我们可以修改默认的HTTP端口;

通过将该变量设置为-1,可以禁用HTTP,或者将其设置为0,这样就会在随机的端口上启动应用,对于测试,是非常便利的;

2. SSL配置

配置SSL是一项很麻烦的事情,但是在Spring Boot中有一项很简单的解决方案。我们只需要一点属性,就可以保护服务器了:

server.port = 8443

server.ssl.key-store = classpath:keystore.jks

server.ssl.key-store-password = secret

server.ssl.key-password = another-secret

不过为了使上面的例子运行起来,我们需要生成一个可以keystore文件;

3. 其他配置

我们可以通过简单的声明@Bean元素来添加典型的Java Web元素,如Servlet、Filter和ServletContextListener

除此之外:Spring Boot还为我们提供了内置3项功能:

  1. 在JacksonAutoConfiguration中,声明使用Jackson进行JSON序列化;
  2. 在HttpMessageConvertersAutoConfiguration中,声明了默认的HttpMessageConverter;
  3. 在JMXAutoConfiguration中,声明了JMX功能;

1.9 小结

通过将spring-boot-starter-actuator依赖,可以获取更多有意思的功能;

Spring Boot如何运行的图书推荐:Learning Spring Boot作者:Greg Turnquist

 

第2章 精通MVC 架构

2.1 MVC架构

MVC背后的理念是将视图与模型进行解耦,模型必须是自包含的并且与UI无关,这样的话,就基本可以实现相同的数据跨多个视图的重用,其实,这些视图就是以不同的方式来查看数据。通过钻取(Drill down)或者使用不同的渲染器(HTML、PDF),可以很好的阐述这一原则;

控制器作为用户和数据之间的协调者,它的角色就是控制终端用户的行为,并且引导它们在应用的不同视图之间跳转;

2.2对MVC的质疑及其最佳实践

1.贫血的领域模型

推荐的图书:《领域驱动设计》(Domain Driven Design,DDD)该书中定义了一组架构规则,可以指导我们更好的将业务领域集成到代码领域之中;

贫血的领域驱动设计症状:

  1. 模型是由老式的Java对象(Plain old java object,POJO)所构成的,只有getter和setter方法;
  2. 所有的业务逻辑都是在服务层处理的;
  3. 对模型的校验会在本模型的外部进行,例如在控制器中;

避免领域贫血的途径如下:

  1. 服务层适合进行应用级别的抽象(例如事务处理),而不是业务逻辑;
  2. 领域对象应该始终处于合法的状态,通过校验器(validator)或者JSR-303的校验注解,让校验过程在表单对象中进行;
  3. 将输入转换成有意思的领域对象;
  4. 将数据层按照Repository的方式来实现,Repository中会包含领域查询
  5. 将领域逻辑与底层持久化框架解耦;
  6. 尽可能使用设计的对象,例如操作FirstName类而不是操作Spring;

DDD 中有很多的原则:实体(Entity)、值类型(value type)、通用语言(Ubiquitous Language)、界限上下文(Bounded Context)、洋葱架构(Onion Architecture)以及防腐化层(anti corruption layer),在构建Web应用程序的时候,应该努力的遵循上述原则;

2.从源码中学习

https://github.com/spring-io/sagan

  1. 该项目包含了很多特性:
  2. 基于Gradle的多模块项目;
  3. 集成了安全;
  4. 集成了GitHub;
  5. 集成了Elasticsearch;
  6. JavaScript前端应用;

2.3 Spring MVC 1-0-1

Spring MVC中,模型是由Spring MVC 的Model或者ModelAndView封装的简单Map;

它可以来源于数据库、文件、外部服务等,这取决你如何获取数据,并将其放入到模型中;

与数据层进行交互推荐使用Spring Data库:Spring Data JPA、Spring Data MongoDB等;

2.4 使用Thymeleaf

Thymeleaf是一个模板引擎,在Spring社区中,备受关注;

它的成功之处最大是归因于对用户优化的语法(几乎就是HTML)以及扩展的便利性;

入门指南:

http://www.thymeleaf.org/doc/tutorials/2.1/thymeleafspring.html

Thymeleaf有很多实用的扩展:并且可以与Spring Boot继承:

例如:

  1. 布局  thymeleaf-layout-dialect
  2. HTML 5 data-*属性 thymeleaf-extras-data-attribute
  3. Internet Explorer 的条件注释 thymeleaf-extras-conditionalcomments
  4. 对Spring Security 的支持: thymeleaf-extras-springsecurity3

在build.gradle中添加

compile ‘org.springframework.boot:spring-boot-starter-thymeleaf’

对于Web开发人员来讲,Thymeleaf有一项很大的优势,就是在服务器没有运行的时候,模板中所有的动态内容都可以采用一个默认值。资源URL可以采用相对路径来指定,每个标签都可以包含占位符。

可设置spring-thymeleaf.cache= false,这样会禁用缓存,每次访问的时候都会重新加载模板;

注意:部署到生产环境中,需要禁用该配置;

2.5 Spring MVC架构

1.DisparcherServlet

每个Spring Web应用的入口都是DispatcherServlet

它会将HTTP请求分发给HandlerMapping,HandlerMapping会将资源(URL)与控制器关联起来;

控制器上对应的方法(也就是带有@RequestMapping注解的方法)将会被调用,在这个方法中,控制器会设置模型数据并将视图名称返回给分发器;

然后,DispatcherServlet将会查询ViewResolver接口,从而得到对应的视图的实现;

ThymeleafAutoConfiguration将会为我们搭建视图解析器;

2.将数据传递给视图

2.6 Spring表达式语言

当使用${}的语法的时候,我们实际上使用的是Spring表达式语言(SpringException Language ,SPEL),关于EL,有很多不同的变种,而SpEL是其中威力强大的一种;

SpELl的用处不局限与视图中,可以将它用在Spring框架的各种地方,在通过@Value注解往bean中注入属性的时候,也可是使用SpEL;

访问列表元素:list[0]

访问map条目:map[key]

三元运算符:condition?’yes’:’no’

Elvis运算符:person?:default           如果person的值为空的时候,将会返回default

安全导航:person?.name              如果person为空或者其name为空的话,返回null

模板:’Your name is #{person.name}’    

投影:${persons.![name]}              抽取所有persons的name,并将其放到一个列表中

选择:persons.?[name==’Bob’]          返回列表中name为Bob的person

函数调用:person.sayHello()

2.7 结束Hello World,开始获取Tweet

Spring Social是一组项目,提供了对各种社交网络公开API的访问功能,Spring Boot内置了对Twitter、Facebook额LinkedIn的支持。Spring Social一共包含了大约30个项目;

提示:

     th:each是由Thymeleaf所定义的标签,它允许我们遍历一个集合并且能够在循环中的每个值赋给一个变量;

2.8 Java 8 的流和lambda表达式

在Java 8中,每个集合都会有一个默认的方法stream(),它能够实现函数式的风格的操作;

这些操作可以是中间操作(intermediate_operation),它会返回一个流,这样就可以将其连接起来,也可以是终止操作(terminal operation),这样的话会返回一个值;

中间操作:

  1. map:它会为列表中的每个元素都应用某个方法,并返回结果多组成的列表;
  2. filter:它会返回匹配断言的所有元素;
  3. reduce:它会借助一个操作和累加器(accumulator)将一个列表聚合到单个值上;

Lambda是函数表达式的便捷语法,它可以用到单个的抽象方法(Single Abstract Method)之中,也就是只包含一个函数的接口;

例如:我们可以按照如下的方式来实现Comparator接口:

Comparator<Integer> c  = (e1,e2) -> e1-e2;

在lambda表达是总,return关键字就是最后的表达式;

使用的双冒号操作符是引用类函数的快捷方式:

Tweet::getText

等价于:

(Tweet t) -> t.getText()

collect 方法允许我们调用一个终止操作。Collectors类是一组终止操作,它会将结果放到列表、集合或者Map之中,允许进行分组(grouping)、连接(joining)等操作;

调用collect(Collectors.list())方法将会产生一个列表,其中包含了流中的每个元素;

2.9 使用WebJars实现质感设计

Materialize是一个非常漂亮的CSS和JavaScript库,与BootStrap库类似;

添加Jquery 和Materialize CSS:

compile ‘org.webjars:materializecss:0.96.0’

compile ‘org.webjars:jquery:2.1.4’

每个WebJar的结构都是标准的,每个库的JS和CSS文件都会位于/webjars/{lib}/{version}/*.js

例如:如果需要在页面中引入jquery,则只需要:

<script src=”/webjars/jquery/2.1.4/jquery.js”></script>

1. 使用布局

<html

         xmlns:th=”http://www.thymeleaf.org”

         xmlns:layout=http://www.ultraq.net.nz/thymeleaf/layout

         layout:decorator=”layout/default”

>

其中layout:decorator=”layout/default能够表明去哪里查找模板,这样,我们可以将内容注入到布局的不同layout:fragment区域中。需要注意的是,每个模板都是合法的HTML文件,我们可以非常的重写它的标题;

2. 导航

return “redirect:result”

RedirectAttributes 是一个Spring模型,专门用于redirect场景下传值;

使用redirect: 或者是forword: 前缀,这时候返回的字符串都不会解析为视图,而是触发到特定的URL的导航,redirect会发送一个302的信息头,它会在浏览器内部触发导航,而Forword则不会导致URL的变化。

第3章 处理表单和复杂的URL映射

1.基本信息页——表单

th:action=”@{/profile}”

注意:@{} 语法将会为资源构建完成的路径,它会将服务器的上下文路径添加到参数上;

数据传输对象(Data Transfer Object,DTO)

将表单域绑定到DTO上,需要使用:

th:object=”${obj}”

th:field=”${obj.name}”

可以通过继承WebMVCConfigurationAdapter来自定义一个Spring MVC的配置类;

2.校验

可以在DTO中使用

@Size(min=2)

private String nam;

@Email

@NotEmpty

private String email;

@NotNull

private Date birthDate;

@NotEmpty

private List<String> tastes = new ArrayList<>();

这些注解来自于javax.validation.constraints包中的注解以及来自org.hibernate.validator.contraints包中的注解;

在Controller中结合@Valid标注到需要校验的参数上,即可完成响应校验;

BindingResult.hasErrors()

结合使用 th:errors 来显示错误提示信息;

使用th:errorsclass 来指定相关的CSS样式

1.自定义校验信息

可以在src/main/resources/messages.properties中自定义校验信息

在开发期间使用spring.messages.cache-seconds=0

0意味着每次都需要重新加载,而-1则代表着不进行重新加载。

Spring中负责解析错误信息的类是DefalutMessageCodesResolver。在进行输入域校验的时候,这个类将会按照如下的顺序来尝试解析信息:

  1. 编码+“.”+对象名+”.”+输入域
  2. 编码+“.”+输入域
  3. 编码+“.”+输入域类型
  4. 编码

声明错误信息的最后一种错误方式是直接在检验注解中定义错误信息,如下所示:

@Size(min=2,message=”格式错误”)

这种方式的缺点在于它无法与国际化功能兼容;

2.用于校验的自定义注解

3国际化.

国际化通常被称之为il8n,指的是将应用程序设计为可以翻译成为各种语言。

通常会将翻译文本放置到属性bundle中,并且需要以目标地域作为后缀,例如

messages_en.properties、message_en_US.properties和message_fr.properties文件。

Spring 提供了这个接口的多个实现,如FixedLocaleResolver,区域解析器非常简单,可以通过一个属性来配置应用程序的地域,而且一旦定义之后,就不能进行修改了。

要配置我们应用的地域,只需要添加如下的属性到application.properties文件中:

spring.mvc.locale=fr

以下是Spring MVC所提供的不同LocalResolver接口实现:

  1. FixedLocaleResolver:使用配置中固定的地域,一旦确定之后,不能发生改变;
  2. CookieLocaleResolver:允许在Cookie中检索和保存地域信息;
  3. AcceptHeaderLocaleResolver:根据用户浏览器所发送的HTTP头信息来查找地域;
  4. SessionLocaleResolver:在HTTP会话中查找和存储地域信息;

1.修改地域

2.翻译应用文本

3.表单中的列表

4.客户端校验

第4章 文件上传与错误处理

 

4.1 上传文件

在<form>表单中添加enctype=”multipart/form-data”

【Git中的空目录】

Git是基于文件的,不能提交空目录,常见的变通方案就是在目录中提交一个空文件,如“.gitkeep”,从而强制Git对其进行版本控制;

MultipartProperties类中一些属性可以用来自定义文件上传功能:

  1. multipart.maxFileSize:定义上传文件的最大容量
  2. multipart.maxRequestSize:定义了整个multipart请求的最大容量,默认值为10M

1.将图片写入到响应中

response.setHeader(“Content-Type”,URLConnection.guessContentTypeFromName(ClassPathResource.getFileName));

IOUtils.copy(ClassPathResource.getInputStream(),response.getOutputStream());

2.管理上传属性

@ConfigurationProperties(prefix=”upload.properties”)

该注解会告诉Spring Boot以一种类型安全的方式,自动映射类路径下所发现的属性(默认情况下,位于application.properties文件中)

@EnableConfigurationProperties({PictureUploadProperties.class})

3.展现上传的图片

4.处理文件上传的错误

Spring中处理错误的两种方式:

  1. 在控制器本地方法中使用@ExceptionHandler注解;

使用@ExceptionHandler(IOException.class)注解来处理IOException

  1. 在Servlet容器级别定义全局的异常处理器;

每当抛出IOException的时候,使用该注解的方法就会被调用;

EmbeddedServletContainerCustomizer接口有很多其他的特性,可以能够自定义应用程序所运行的Servlet容器;

4.2转换错误信息

使用自定义配置错误信息的方式进行错误信息的转换;

4.3将基本信息放到会话中

问题描述:不建议直接使用会话的另外一个原因在于,对依赖于会话的控制器进行单元测试是非常困难的;

在Spring中,将内容放到会话中的另外一种流行的方式就是为bean添加@Scope(“session”)注解。这样的话,就能够将会话bean注入到控制器中,其他的Spring组件可以为其设置值,或者从中检索值;

HTTP会话可以将任意的对象存储在内存之中,不过,让存储在会话中的对象支持序列化是一种好的实践,比如Redis必须使用Serializable的对象。

为了让bean能够正常的序列化,还需要将它的每个域都变成可序列化的。

4.4 自定义错误页面

Spring Boot允许我们定义自己的错误页面,替换之前的Whitelabel错误页面。它的名称必须为error,其目的是用来处理所有的异常。

4.5 使用矩阵变量进行URL映射

在URL中传递键值对的一种有意思的方式就是矩阵变量(matrix variable)。它非常类似于请求参数。

someUrl/param?var1=value1&var2=value2

someUrl/param;var1=value1;var2=value2

someUrl/param;var1=value1,value2;var2=value3,value4

矩阵变量可以映射为控制器中的不同对象类型

  1. Map<String,List<?>>  :这将会处理多个变量的值
  2. Map<String ,?>  这会处理多个变量的多个值
  3. List<?>  :如果我们只对一个变量感兴趣,并且变量的名称可以配置的话,可以使用这种方式;

注意:Spring MVC 将会移除URL中分号之后的字符,为了在应用程序中启用矩阵变量,需要关闭这种默认行为;

PathMatchConfigurer.setUrlPathHelper(new UrlPathHelper().setRemoveSemicolonContent(false));

 

第5章 创建RESTful应用

1.什么是REST

REST(表述型状态转移,Representational State Transfer)是一种架构风格,它定义了创建可扩展Web服务的最佳实践,这个过程中会充分发挥HTTP协议的功能。

RESTful服务会天然具备如下的属性:

  1. 客户端-服务器:UI是与数据存储分离的;
  2. 无状态:每个请求会包含服务器所需要的足够信息,无需维护状态就能进行操作;
  3. 可缓存:服务器的响应中包含了足够的信息,客户端能够对数据存储做出合理的决策;
  4. 统一接口:URL会唯一识别资源,能够通过超链接发现API
  5. 分层:API的每个资源都提供了合理程度的细节

这种架构的优势在于易于维护以及便于进行服务发现。它的扩展性也很好,因为没有必要在服务器和客户端之间维护持久化的连接,这样就没有必要进行均衡负载或者会话粘性。

最后,因为服务的内容非常简洁并且易于缓存,所以服务会更加的高效;

2 Richardson的成熟度模型

Leonard Richardson 定义了著名的4个等级,从0级到3级,它们描述了Web API的RESTful程度(RESTfulness)。每个等级都需要开展额外的工作,并且在API方面进行投入,但是这也会带来额外的收益;

1. 第0级——HTTP

第0级非常容易实现,我们只需要让资源能够在网络上通过HTTP协议获取即可,可以使用任意合适的数据表述形式(XML、JSON等),只要能够最好的满足使用场景即可;

2. 第1级——资源

资源时模型中某个元素的唯一标识符,借助HTTP,资源会与一个统一的资源标识符URL进行关联。

3. 第2级——HTTP动作

这个级别是使用HTTP动作(verb)来标识资源可能的行为。这种方式能够很好的描述你的API能够完成什么功能;

主要的动作如下:

  1. GET:读取数据
  2. HEAD:它的行为与GET相同,但是不包含响应体。在获取资源的元数据(如缓存信息等等)时候,这种方式是有用的;
  3. DELETE:删除某个资源;
  4. PUT:更新或者创建资源;
  5. POST:更新或者创建资源;
  6. PATCH:部分更新资源;
  7. OPTIONS:这会返回服务端针对特定资源所支持方法列表;

PUT和POST的区别:

         PUT动作被认为是幂等的,这意味着多次发送同一个请求将会导致相同的服务器状态。该规则的含义就是PUT动作要针对给定的URL进行操作,并且其中要包含足够的信息以保证请求能够成功;

         另一方面,如果无法精确地知道该往哪个URL写入数据的话,就应该使用POST。

服务器端可能还允许资源进行部分的修改(客户端不需要发送资源的全部内容),那么在这种情况下,应该对应于PATCH方法;

4.第3级——超媒体控制

超媒体控制(Hypermedia control)也被称为超媒体即应用状态引擎(Hypertext As The Engine Of Application State,HATEOAS)。在这个复杂的缩写词背后,蕴含着RESTful服务最重要的特性:通过使用超文本链接,可以进行服务的发现。这实际上就是服务器端通过响应头或者响应体,告诉客户端其可选的功能;

例如:在通过使用PUT方法创建资源之后,服务端应该返回代码为201 CREATED的响应,并且在响应头信息中使用Location属性中包含新创建资源的URI;

3.API版本化

         如果第三方客户端使用你的API的话,可以考虑对API进行版本化,从而避免更新应用的时候,带来破坏性的变更;

         版本化API通常会在子域下面提供稳定的资源访问功能。

4.有用的HTTP代码

好的RESTful API还有另外一个很重要的方面,那就是合理地使用HTTP编码。

5.客户端为王

我们将会允许第三方客户端通过REST API来获取搜索结果,结果可以使用JSON或者XML的形式来展示;

@RestController注解是一种快捷方式,它所声明的控制器在返回响应的时候,就如同使用了@ResponseBody注解一样。它会告诉Spring将返回类型序列化为合适的格式,默认情况下为JSON格式;

Spring能够使用Jackson自动的将结果进行序列化;

6.调试 RESTful API

在浏览器中,我们只能针对特定的API执行GET操作。使用以下工具可以帮助我们更方便的调试;

1.JSON格式化扩展

         通常我们只是测试GET方法,此时我们的第一反应就是讲地址复制到浏览器中,并检查结果。可以使用Chrome 的JSON Formatter或者火狐的JSONView,这些插件会对结果进行格式化,而不是存文本;

2.浏览器中的RESTful

对于处理HTTP请求来讲,浏览器是最自然的工具,PostMan是针对Chrome的一个插件,RESTClient是实现同样功能的Firefox插件,它们具有类似的特性,例如创建和共享查询、修改头信息以及处理认证(基本认证、摘要认证以及Oauth认证)。

3.httpie

Httpie是一个命令行工具,类似于curl,但是它更加面向REST查询,它允许我们按照如下的方式输入命令:

http PUT httpbin.org/put hello=world

7.自定义JSON输出

         通常使用我们的工具,能够非常便利的查看服务器所产生的响应,缺点是这些工具有些庞大复杂,默认情况下,SpringBoot 所使用的JSON序列化库Jackson会将所有能够通过getter方法访问的内容都进行序列化;

自定义哪些需要进行序列化的最简单的方式就是为相应的bean添加注解。我们可以在类级别使用@JsonIgnoreProperties注解,定义想要忽略的一组属性,也可以在想要忽略的属性所对应的getter方法上,添加@JsonIgnore注解。

8.用户管理API

9.状态码与异常处理

默认情况下,Spring 会自动处理一些状态;

在Spring MVC中,有两种方式来返回状态码:

  1. 在REST控制器中,返回ResponseEntity类;
  2. 所抛出的异常有专门的处理器来捕获;

1.带有状态码的ResponseEntity

Spring MVC中的ResponseEntity类能够将HTTP状态与响应实体关联;

2.使用异常来处理状态码

在API中处理错误的另外一种方法就是抛出异常。使用Spring MVC ,有两种方法来匹配异常。

  1. 在类级别使用@ExceptionHandler;
  2. 使用@ControllerAdvice,捕获所有控制器或者控制器的一个子集所抛出的全局异常;

要将这些处理器与HTTP状态码进行关联,我们可以将response注入到带有注解的方法中并使用HttpServletResponse.sendError()方法,或者为这些方法添加@ResponseStatus注解;

可以自定义异常类来继承Exception

通过为bean添加@ControllerAdvice注解,我们能够为一组控制器添加额外的行为。这些控制器通知可以用来处理异常,也可以通过@ModelAttribute来声明模型属性,或者通过@InitBinder声明校验策略;

10.通过Swagger实现文档化

Swagger是一个非常棒的项目,它能够允许我们在一个HTML5 Web页面中,对API进行文档化和交互。

使用spring-fox库(前身称为swagger-springmvc)可以在spring中使用该库;

11.生成XML

RESTful API有时候会返回不同媒体类型的响应(JSON、XML等)。在Spring中,负责选择正确媒体类型的机制被称为内容协商(content negotiation)。

默认情况下,在Spring  MVC 中,ContentNegotiationManagerFactoryBean类;

内容类型可以通过如下的策略来进行解析:

  1. 按照客户端发送的Accept头信息;
  2. 借助类似于?fromat=json这样的参数;
  3. 借助路径扩展名,如myResource.json或者myresource.xml

默认情况下,Spring会使用Accept头信息和路径扩展名。

要在SpringBoot中启用XML序列化,可以在类路径中添加如下的依赖:

compile ‘com.fasterxml.jackson.dataformat:jackson-dataformat.xml’

12.小结

在使用RESTful架构的风格的API的时候,这种类型的后端能够在性能和可维护性上带来很大的收益,在于像Backbone、AngularJS或者React.js这样的JavaScript MVC框架协作的时候,能够实现超乎想象的效果;

第6章 保护应用

最为简单的认证机制就是基本认证,简而言之,如果没有用户名和密码的话,我们的应用将不允许访问;

6.1基本认证

添加Spring Security依赖;

默认情况下Spring Security将会保护每一项资源,不过,有一些特定的路由会排除在外,如/css/  、 /js/ 、/images/、**、favicon.ico

1.用户授权

自定义类继承WebSecurityConfigurationAdapter,这个代码片段将会搭建一个内存系统,其中包含了应用程序中的用户及其角色;

使用@Configuration和@EnableGlobalMethodSecurity(securedEnabled = true)

这个代码片段将会搭建一个内存系统;

@EnableGlobalMethodSecurity注解将会允许我们为应用中的类和方法添加注解,从而定义它们的安全级别。

例如:如果应用中的管理人员才有权限访问API,则只需要在资源上添加@Secured注解即可,这样的话,只有具备ADMIN角色的用户才能进行访问;

@Secured(“ROLE_ADMIN”)

Spring Security会自动添加一些通用的安全信息头:

  1. Cache-Control:防止用户缓存受保护的资源;
  2. X-XSS-Protection:告知浏览器阻止类似于XSS的攻击;
  3. X-Frame-Options:不允许站点嵌入到Iframe之中;
  4. X-Content-Type-Options:这会禁用浏览器猜测恶意资源的MIME类型,这些资源会用来进行XSS 攻击;

2.URL授权

如果想要完全控制授权功能,移除@Secured注解;

通过重写WebSecurityConfigurerAdapter的configure方法

CSRF(Cross Site Request Forgrey):其含义是跨站请求伪造。指的是一种攻击形式,恶意的Web站点将会在他们的网站上展示一个表单,但是会将表单的数据POST提交到我们的站点上,如果我们站点的用户没有退出的话,那么POST请求能够获取用户的cookie,这样的话,就会被认为是认证过的用户;

使用Spring Security的WebSecurityConfigurationAdapter的configure代码:

http.antMatcher().httpBasic().and().csrf().disable()提供CSRF的防护功能;

针对CSRF的防护会生成短期存活的token,它会随着表单一起进行提交;

3.Thymeleaf安全标签

有时候我们需要展现来自认证层的数据,例如用户的名称和角色,或者根据用户的权限隐藏或者显示Web页面的部分内容。借助于thymeleaf-extras-springsecurity模块,我们就可以实现这些功能;

在build.gradle文件中添加如下的依赖:

compile ‘org.thymeleaf.extras:thymeleaf-extras-springsecurity3’

在html标签中加入:

xmlns:sec=” http://thymeleaf.org/thymeleaf-extras-springsecurity3”

在合适的标签中添加sec:authentication=””

注意:在HTML声明中添加新命名空间以及sec:authentication属性,它允许我们访问org.springframework.security.core.Authentication对象的属性,这个对象代表了当前登陆的用户;

该标签库中有很多其他的标签:sec:authorize=”hasRole(‘’)

6.2登录表单

6.3Twitter认证

如果需要通过Twitter来实现登陆的话,是完全合情合理的,在采取进一步的操作之前,确保已经在Twitter上为我们的应用程序启动了Twitter登陆功能;

6.3.1 搭建社交认证环境

Spring Social 能够借助Twitter这样的Oathprovider实现认证功能,这需要使用登陆/注册的场景来完成;

6.4 分布式会话

将会话能够适应分布式环境,可以采用如下几种方案:

  1. 我们可以使用粘性会话(sticky session),它能够确保特定用户会被转移到同一台服务器上,并保持回话,这种方案需要部署的时候额外进行配置,不是特别优雅的方式:
  2. 重构代码,将数据保存在数据库中,而不是保存在会话中,这样的话,如果需要将其与客户端请求中的cookie或者token相关联,我们可以每次都从数据库中加载数据;
  3. 使用Spring Session项目,从而能够透明的使用像Redis这样的分布式数据库作为底层的会话provider;

Spring Boot中使用Spring Session

添加如下依赖到build.gradle文件中:

  1. compile ‘org.springframework.boot:spring-boot-starter-redis’
  2. compile ‘org.springframework.session:spring-session:1.0.1.RELEASE’

新建一个application-redis.properties的配置文件:

spring.redis.host=localhost

spring.redis.port=6379

Spring Boot提供了一种便利的方式将配置文件与profile关联起来,只有当redis profile激活的时候,application-redis.properties才会被加载;

@Profile(“redis”)

6.5 SSL

安全套接字层(Secure Sockets Layer,SSL)是一个安全协议,根据该协议数据会通过整数加密的方式并发往可信任的参与方

1.生成自签名的证书

正常情况下,X.509证书是由数字证书认证机构(Certificate Authority)来颁发的。一般会收费,作为测试来讲,可以创建自签名的keystore文件;

JDK自带了名为keytool的二进制文件,它是用来管理证书的。借助这个工具,我们可以创建keystore并将证书导入已有的keystore中。

注意:不要将keystore放到仓库中,它可能会被暴力破解,从而使Web站点的安全保护失效,在生成keystore的时候,应该采用随机生成的强密码

2.单一模式

如果只是希望只有安全的HTTPS通道而没有http通道的话,那么非常容易实现:

server.port=8443

server.ssl.key-store=classpath:tomcat.keystore

server.ssl.key-store-password=password

server.ssl.key-password=password2

注意:不要将密码放到仓库中,要使用${}符号来导入环境变量;

3.双通道模式

如果需要在应用中同时使用http和HTTPS通道的话,那么需要在应用中增加如下的配置:

@Configuration

public class SslConfig{

         @Bean

         public  EmbeddedServletContainerFactory servletContainer() throws IOException{

         TomcatEmbeddedServletContainerFactory tomcat = new TomcatEmbeddedServletContainerFactory();

tomcat.addAdditionalTomcatConnectors(createSslConnnector());

return tomcat;

}

}

private Connector createSslConnector() throws IOException{

         Connector connector = new Connector(Http11NioProtocol.class.getName());

         Http11NioProtocol protocol =( Http11NioProtocol) connector.getProtocolHandler();

         connector.setPort(8443);

connector.setSchema(“https”);

protocol.setSSLEnabled(true);

protocol.setKeyAlias(“masterspringmvc”);

protocol.setKeystorePass(“password”);

protocol.setKeyPass(“password2”);

protocol.setKeystoreFile(new ClassPathResource(“tomcat.keystore”).getFile().getAbsolutePath);

protocol.setSslProtocol(“TLS”);

return connector;

}

这样的话,除了8080端口之外,还会加载前文生成的keystore,并在创建8443创建另外一个通道;

我们可以通过如下的配置:使用Spring Security自动将连接从http重定向到https

httpSecurity.requiresChannel().anyRequest().requiresSecure().and()

4.置于安全的服务器之后

通过SSL保护应用的最简便的方式通常是将应用程序部署到启动SSL功能的Web服务器后面,如Apache或者CloudFlare,这样的话,通常会使用头信息表名这个连接最初是通过使用SSL初始化的;

如果在application.properties中指定正确的头信息是什么样子的,那么Spring Boot就能够理解这种协议;

server.tomcat.remote_ip_header=x-forwarded-for

server.tomcat.protocol_header=x-forworded-proto

6.6 检查点

第7章 单元测试和验收测试

1.为什么要测试自己的代码

如果实现编写测试并且能够在几秒的时间就将其运行起来的话,在解决代码中潜在的bug方面,这种方式所消耗的时间肯定会更少;

测试的另外一项好处就是可以作为代码的实时文档。丰富的文档甚至代码注释都可能会失效,因为它们很容易过期,我们需要为极限情况和意外行为编写良好的测试;形成这样的习惯能够为未来编织一到安全网;

2.该如何测试自己的代码

测试分为两大类:

  1. 单元测试:

可以快速执行,并且易于维护;

  1. 验收测试:

金字塔状的测试应该占据的比例:

                   UI测试

                   集成测试

                   单元测试

顶部的UI测试:成本更高并且执行缓慢

集成测试位于二者之间:它们可以视为更大的单元测试,需要单元之间的复杂交互。

这个金字塔的理念是提醒我们需要把焦点放在最有影响力并且能够得到最佳反馈的地方;

3.测试驱动开发

测试驱动开发(Test-driven Development,TDD)这种实践来源于极限编程(Extreme Programming,XP),它会每个开发阶段拆分成很小的步骤,并为每个步骤编写一个会失败的测试,然会对代码进行修改,直到测试通过。

开发人员可以通过非常短的反馈循环最终将特性完成,这样能够确保不出现问题;

TDD的缺点:

编写测试所消耗的时间比编写实际实现的时间还多;

它能够导致设计很差的应用程序;

4.单元测试

单元测试中的单元如何定义取决你:可以是一个类也可以是关系密切的一些类。单元的定义决定了哪些内容需要进行mock处理;

1.流行工具

这些工具可以方便的和Spring集成

  1. Junit

最为广泛采用Java测试运行器,在所有的构建工具中都会自动启用;

  1. AssertJ

一个非常流畅的断言库,使用起来要比Hamcrest更容易

  1. Mockito

很易于使用mock框架

  1. DbUnit

通过XML数据集来mock和断言数据库内容

  1. Spock

一个优雅的Groovy DSL,可以使用行为驱动开发(Behaviour Driven Development,BDD)的风格(Given/When/Then)编写测试;

5.验收测试

在Web应用中,验收测试通常是指浏览器中的端到端测试,在Java领域中,Selenium是最为可靠和成熟的库之一;

而在Javascript领域中,我们可以找到其他的替代方案,如PhantomJS或者Protractor。

借助于PhantomJS可以在一个没有界面的浏览器中,通过Web Driven来运行Selenium测试,这样就提升了启动速度并且无需模拟X服务器或者启动单独的Selenium服务器

 

Selenium2

通过WebDriven探测浏览器,从而进行自动化测试

PhantomJS

无界面的浏览器(没有GUI),可能是最快的浏览器了

FluentLenium

用于执行Selenium测试的一个API很流畅的库

Geb

用于执行Selenium测试的一个Groovy库

6.第一个单元测试

Spring MVC编写测试的关键是添加:

org.springframework.boot:spring-boot-start-test依赖,这将会添加多个非常有用的库:

  1. hamcrest:Junit的断言库
  2. Mockito:一个Mock库
  3. spring-test:Spring的测试库

7.Mock与Stub

1.使用Mockito进行mock

mock的优点:

可以在运行的时候检验与mock的交互和创建预期值

同时这种方式还可以将测试与对象的实际实现进行解耦。

2.在测试的时候Stub bean

@Primary直接会告诉Spring,如果在类路径下还有其他的实现的话,将会优先使用该是实现;

3.该使用Mock还是Stub

这两种方式各有优缺点,可以具体查找资料了解;

8.对REST控制器进行单元测试

9.测试认证

10.编写验收测试

单元测试只能测试应用程序中各组件之间交互的一个子集,为了更进一步的说明,我们需要进行验收测试,这种测试hi启动完整的应用并且允许与界面进行交互;

1.Gradle 配置

2.第一个FluentLenium测试

3.使用FluentLenium创建页面对象

4.用Groovy实现单元测试

Groovy是一个动态的语言,允许操作符重载,在编写POJO的时候,不需要编写getter、setter、equals以及hashCode方法。这些事情已经帮你做好了;

Groovy开发工具集(Groovy Development Kit,GDK)为典型的Java对象添加了很多有意思的方法,还对正则表达式和闭包做了改进;

Groovy插件扩展了Java插件;

5.使用Spock进行单元测试

Spock是最为流行的Groovy测试库;

6.使用Geb进行继承测试

Geb是一个简化Selenium测试的Groovy库

它提供了类似jQuery的选择器API;

7.在Geb中使用页面对象

第8章 优化请求

本章中主要讲述实现优化Web应用的典型技术:缓存控制信息头、Gzip、应用缓存和ETag,还有一些反应型(reactive)相关的技术,如异步方法的调用和WebSocket。

1.生产环境中的profile

应用中的属性配置文件可以在特定的profile激活的情况下才会生效;

对于生产环境来讲:

在src/main/resource中创建application-prod.properties文件,来自prod profile的属性将会重写application.properties文件中所声明的属性;

spring.thymeleaf.cache= true

spring.messages.cache-seconds=-1

启用Thymeleaf缓存;

将缓存时间设置为-1,意味着永远缓存bundle

2.Gzip

Gzip是一种能够被浏览器广泛理解的压缩算法,服务器会提供压缩的响应,这耗费的CPU周期会多一些,但是能够节省带宽;

客户端浏览器负责解压缩并将其展示给用户;

如果想要使用Tomcat的Gzip压缩功能,只需要在application-prod.properties文件中添加如下的几行配置:

         server.tomcat.compression= on

         server.tomcat.compressableMimeTypes=text/html,text/xml,text/css,text/plain,\

         application/json,application/xml,application/javascript

当所请求的文件匹配列表中的MIME类型并且其长度大于2048字节,将会启用Tomcat的Gzip压缩,server.tomcat.compression= force,表示会强制启用压缩功能,如果你想要修改Gzip资源的最小长度的话,也可以将其设置为一个数字值;

如果需要对压缩进行更多的控制,例如将压缩级别或者对某些用户终端不启用压缩功能,那么可以使用Jetty中的GzipFilter类,这需要将org.eclipse.jetty:jetty-servlets依赖项添加到项目中;这将会自动触发GzipFilterAutoConfiguration类,这个类可以通过一些带有spring.http.gzip前缀的属性来进行配置;

3.缓存控制

缓存控制由服务端发送一组HTTP头信息,它会控制用户的浏览器如何缓存资源。

我们看到Spring Securityhi会自动的禁用安全资源的缓存,如果我们想要从缓存控制中受益的话,首先就需关闭Spring Security的这个特性;

security.headers.cache=false

设置缓存时间:

spring.resources.cache-period=259200

 

如果希望对缓存进行更多的控制的话,那么应该在配置中为资源添加自己的处理器:

例如:可以通过ResourceHandlerRegistry.addResourceHandler(“/img/**”).addResourceLocations(“classpath:/stattic/images/”).setCachePeriod(“12”)

我们也可以重写Spring  Security的默认配置

4.应用缓存

通过使用Spring,可以很容易的缓存结果,当使用相同的参数调用搜索功能的时候,都会返回相同的结果;

我们需要做的第一件事情就是使用@EnableCache注解激活Spring的缓存功能;

还需要创建一个CacheManager类来处理缓存。

SimpleCacheManager

EhCacheCacheManager

GuavaCacheManager

现在配置了缓存,接下来就可以在方法上使用@Cacheable注解了,这样使用了之后,Spring会自动缓存方法的结果,将会无法使用Spring缓存功能;

缓存API并不仅限于这些:

如下注解:

  1. @CacheEvict:从缓存中移除一个条目
  2. @CachePut:会将方法的结果放到缓存中,而不会影响到方法调用本身;
  3. @Caching:将缓存注解进行分组;
  4. @CacheConfig:指向不同的缓存配置

1.缓存失效

可以使用GuavaCacheManager设置相应的缓存过期时间;

2.分布式缓存

使用Redis作为缓存提供者,这样就可以跨多台服务器,实现分布式缓存;

5.异步方法

如果需要启用Spring的异步功能,必须要使用@EnableAsync注解。这样将会透明的使用java.util.concurrent.Executor来执行所有带@Async注解的方法;

@EnableAsync

使用@Async注解就是告诉Spring要使用我们的执行器来调度该任务;同样,Spring会还是用代理来完成这个工作;

6.Etag

使用缓存虽然如果相同的条件不会进行额外的搜索,但是即便结果没有发生变化,但是结果本身还是会多次的发送给用户,这样会浪费带宽;

Etag是Web响应数据的一个散列(hash),并且会在头信息中进行发送。客户端可以记住资源的Etag,并且通过IF-None-Match头信息将最新的已经版本发送给服务器。如果这段时间内请求没有发生变化的话,服务器就可以回应304 Not Modified;

Spring 有一个特殊的Servlet来处理Etag,名为:ShallowEtagaheaderFilter

我们只需要将其中一个bean添加到MasterSpringMvc4Application配置类中;

只要响应没有缓存控制头信息的话,系统将会自动为你的响应生成Etag,服务端的响应中会包含etag一起发送到客户端;

如果再次请求相同的资源,并且将已知的最新的Etag放到IF-None-Match头信息中,服务器端将会自动响应304 Not Modified状态;

Etag还有别的用途,例如事务的乐观锁,它能够让你在任意的时间都是知道客户该使用那个版本的对象。在发送数据之前需要对其进行散列操作,这会给服务端带来额外的工作,但是这种方式会节省带宽;

7.WebSocket

其实另外一种优化方式是在服务器端有可用的数据的时候,就立即将其发送到客户端;

Spring 为WebSocket提供了良好的支持,WebScocket协议允许客户端维持与服务器的长连接,数据可以通过WebSocket在这两个端点之间进行双向传输,因此消费数据一方可以实时的获取数据。

可以使用的JavaScript库:SockJS,确保浏览器的兼容性,如果用户使用过时的浏览器,SockJS将会透明的切换为备用设备;

StompJS来连接消息代理(message broker)

构建过程中,需要添加如下的库:

compile ‘org.springframework.boot:spring-boot-starter-websocket’

compile ‘org.springframework:spring-message’

compile ‘org.webjar:sockjs-client:1.0.0’

compile ‘org.webjars:stomp-websocket:2.3.3’

利用WebSocket可以完成的功能:

客户端能够接受应用中的所有的搜索结果——这个过程是实时的:

具体代码中可以在自定义类上使用@EnableWebSocketMassageBroker并且继承AbstractWebSocketMessageBrokerConfigurer

在生产环境中可以进行以下的优化点:

  1. 为客户端创建子通道,私密的进行监听;
  2. 客户端完成使用之后,关闭通道;
  3. 为页面添加CSS效果,让用户感受到是实时的;
  4. 使用像RabbitMQ这样真正的代理,允许后端能够随着连接的增加进行扩展;

WebSocket有很多的内容;

8.检查点

9.小结

提升性能的两种实现:

  1. 方式一:试图减少客户端所使用的带宽,这是通过缓存数据以及使用尽量少的连接来实现的;
  2. 方式二:设计搜索结果的并发执行,通过WebSocket为每个客户端保持一种同步的持久化连接,这样客户端能够实时获取更新,应用的响应性能会更好,但是这样使用的线程会更多;

 将Web应用部署到云中

介绍如何将Web应用部署到Pivotal Web Service和Heroku中;

1.选择主机

云主机中有多种类型,但是对于开发人员来讲,可选的方案主要在平台即服务(Platform As a Service ,PASS)和基础设施即服务(Infrastructure AS a Service,IaaS)之间;

PaaS 使得应用的部署非常的简单,就像使用了推送即部署(push-to-deploy)工作流进行开发一样;

在这个领域中,最知名的提供商为:

  1. Pivotal支持的Cloud Foundry;
  2. Red Hat 的 OpenShift;
  3. Salesforce的Heroku;

这三个提供商各有其优缺点;

1.Cloud Foundry

2.OpenShift

既是PaaS又是IaaS

3.Heroku

是一个知名的PaaS

2.将Web应用部署到Privotal Web Services中

1.安装Cloud Foundry CLI工具

2.装配应用

3.激活Redis

3.将Web应用部署到Heroku中

1.安装工具

2.搭建应用

3.Heroku Profile

4.运行应用

5.激活Redis

4.改善应用的功能

 

超越 Spring Web

1.Spring的生态系统

从Web到数据,Spring是一个综合的生态系统,致力于以模块化的方式解决各种问题;

1.核心

Spring 框架的核心显然是依赖注入机制;

2.执行

Spring XD项目的目标是提供工具来处理、分析以及转换或者导出数据,它的关注点是大数据。

3.数据

在Spring Data下,Spring生态系统提供了很多解决方案;

Spring Data JPA和Spring Data Mongo是Spring Data中最为知名的项目;通过它们,我们能够使用repository来操作实体,利用一些简单的接口,提供了创建查询、持久化对象等功能;

4.其他值得关注的项目

Spring Reactor是由Pivotal实现的反应式流(reactive bean),它的理念是在服务器端提供完全非阻塞IO。

Spring Integration则关注与企业级集成模式(Enterprise Integration Pattern),能够让我们设计通道以加载和转换来自异构系统的数据;

Spring Batch,对于企业级系统中日常操作的大量数据来讲,是一个很有用的抽象;

2.部署

Spring Boot能够以JAR文件的方式运行和分布式部署Spring应用,是很成功的;

  1. Docker容器

其背后的理念就是使用Linux Containers(LXC)以及cgroups来提供完全隔离的环境,让应用程序在这个隔离的环境中运行;

 

学习:spring-boot-docker

在Docker生态系统中,另外值得一提的就是Docker Compose,它允许你通过一个配置文件和连接多个容器;

3.单页面应用

1.参与者

在Java社区,AngularJS很多年来一直很受欢迎,但是最近人们开始转向其他的方案;

  1. BackboneJS:是一个很简单的MVC框架,它构建在Underscore和jQuery之上;
  2. Ember:是一个综合性系统,它提供了与数据和其他内容进行交互的很多基础设施;
  3. React:学习曲线有点高,到那时在设计GUI矿建方面,很受益;

 

2.未来的前景

Typescript提供了Java开发人员经常用到的特性,这样可以让我们接收起来更加简单一些;如接口、类、IDE的支持以及自动补齐功能;

ECMAScript6是一门肯高级和复杂的语言,可以学习;

3.实现无状态

当处理JavaScript客户端的时候,依赖于会话cookie并不是最佳的方案,很多的应用选择使用完全无状态的方案,通过一个token来识别客户端;

4.小结

Spring 生态系统非常庞大,我们能够遇到的所有问题,Spring几乎都有相应的解决项目;

 

猜你喜欢

转载自blog.csdn.net/qq_36807862/article/details/81290041