文 by / 林本托

Tips

做一个终身学习的人。

源代码:github下的/code01/ch2。

配置 Web 应用程序

在上一章中,我们学习了如何创建一个基本的应用程序模板,并添加了一些基本功能,并建立与数据库的连接。 在本章中,我们将继续增强BookPub应用程序,并提供 Web 支持。

在本章,主要包括以下内容:

  • 创建一个基本的 RESTful 风格的应用程序;
  • 创建一个 Spring Data REST 服务;
  • 配置一个自定义的 Servlet 的过滤器;
  • 配置一个自定义的拦截器;
  • 配置一个HttpMessageConverters的转换器;
  • 配置一个自定义的PropertyEditors编辑器;
  • 配置一个自定义的类型格式化类。

一. 创建一个基本的 RESTful 风格的应用程序

虽然命令行应用程序确实有其用途,但今天的大多数应用程序开发都围绕着 Web,REST 和数据服务。 我们开始增强 BookPub 应用程序,提供一个基于Web 的 API,以便访问图书目录。

我们继续使用前一章创建的应用程序框架,其中定义了实体对象和存储库服务,并配置了与数据库的连接。

首先,第一件事情是我们需要在build.gradle 文件中添加新的依赖模块spring-boot-starter-web,以便获取基于 web 服务的所需的类库。具体的代码片段如下:

dependencies {
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-jdbc")
compile("org.springframework.boot:spring-boot-starter-web")
runtime("com.h2database:h2")
testCompile("org.springframework.boot:spring-boot-
starter-test")
}

接下来,创建一个 Spring 控制器,用于处理我们应用程序中获取目录数据的 Web 请求。 新建一个包目录来存放控制器相关的 Java 程序,以便我们的代码按照适当的目的分组。 在 src/main/java/org/test/bookpub 目录下创建一个名为 controllers的包目录。

因为需要暴露图书的数据,所以,在新建的包下,创建一个控制器类BookController

package org.test.bookpub.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.propertyeditors.StringTrimmerEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.test.bookpub.entity.Book;
import org.test.bookpub.entity.Reviewer;
import org.test.bookpub.repository.BookRepository; import java.util.Collections;
import java.util.List; @RestController
@RequestMapping("/books")
public class BookController {
@Autowired
private BookRepository bookRepository; @RequestMapping(value = "", method = RequestMethod.GET)
public Iterable<Book> getAllBooks() {
return bookRepository.findAll();
} @RequestMapping(value = "/{isbn}", method =
RequestMethod.GET)
public Book getBook(@PathVariable String isbn) {
return bookRepository.findBookByIsbn(isbn);
}
}

然后, 使用 ./gradlew clean bootRun.命令启动应用程序。

最后,当应用程序程序启动以后,在浏览器中输入:http://localhost:8080/books, 然后会在页面上显示“[]”,表示目前没有图书的数据。

获取暴露于Web请求的服务的关键是@RestController注解。这是一个元注解使用的例子,正如Spring文档指出的那样,我们在以前的代码看到过。 在@RestController中,定义了两个注解:@Controller和@ResponseBody。 所以我们可以轻松给BookController类添加注解,如下所示:

@Controller
@ResponseBody
@RequestMapping("/books")
public class BookController {...}

@Controller是一个类似于@Bean 和@Repository的Spring的元注解,并将已经添加注解的类声明为 MVC 控制器。

@ResponseBody是一个Spring MVC的注解,指示来自Web请求映射方法的响应,构成HTTP响应主体有效负载的整个内容,这是RESTful应用程序比较典型的使用场景。

二. 创建一个 Spring Data REST 服务

在上一个例子中,我们使用REST控制器来展示我们的BookRepository,通过Web RESTful API访问后台的数据。 虽然这是数据访问的一种快捷方便的方式,但它要求我们手动创建一个控制器并定义所有所需操作的映射。 为了最小化代码,Spring为我们提供了一种更方便的方法:spring-boot-starter-data-rest模块。 这允许我们简单地向存储库接口添加一个注解,而Spring将做剩下的事情用以将数据暴露给Web。

首先,我们需要在build.gradle文件中添加spring-boot-starter-data-rest模块。

dependencies {
...
compile("org.springframework.boot:spring-boot-starter-data-rest")
...
}

第二步,在src/main/java/org/test/bookpub/repository目录下新建AuthorRepository接口,代码如下:

package org.test.bookpub.repository;

import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.springframework.stereotype.Repository;
import org.test.bookpub.entity.Author; @RepositoryRestResource
public interface AuthorRepository extends PagingAndSortingRepository<Author, Long> {
}

接下来为剩下的实体模型创建对应的接口,

package org.test.bookpub.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.test.bookpub.entity.Publisher; @RepositoryRestResource
public interface PublisherRepository extends PagingAndSortingRepository<Publisher, Long> {
}
package org.test.bookpub.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
import org.test.bookpub.entity.Reviewer; @RepositoryRestResource
public interface ReviewerRepository extends PagingAndSortingRepository<Reviewer, Long> {
}

代码完成后,执行./gradlew clean bootRun。当启动成功以后,访问http://localhost:8080/profile/authors,在 Chrome 浏览器下,显示如下内容:

{
"_embedded" : {
"authors" : [ ]
},
"_links" : {
"self" : {
"href" : "http://localhost:8080/authors{?page,size,sort}",
"templated" : true
},
"profile" : {
"href" : "http://localhost:8080/profile/authors"
}
},
"page" : {
"size" : 20,
"totalElements" : 0,
"totalPages" : 0,
"number" : 0
}
}

从浏览器里显示的内容可以看出,我们将获得比我们编写BookController控制器更多的信息。 之所以显示了更多的信息,由于我们没有扩展CrudRepository接口,而是扩展了PagingAndSortingRepository,而它又是CrudRepository的扩展。 这样做的原因是获得PagingAndSortingRepository提供的额外好处。 这将添加额外的功能,使用分页检索实体,并能够对它们进行排序。

@RepositoryRestResource注解是可选项,但可以让我们更好地控制作为Web数据服务的存储库的暴露。 例如,如果我们要将URL路径由“authers”改成“rel”,则可以此注解调整,如下所示:

@RepositoryRestResource(collectionResourceRel = "writers", path = "writers")

修改以后,之前的 url 现在改完“http://localhost:8080/reviewers”。

由于我们在构建依赖项中包含spring-boot-starter-data-rest模块,我们还获得spring-hateoas类库的支持,此库给我们提供了很好的ALPS元数据,比如_links对象。 这在构建API驱动的UI时可能非常有用,这可以从元数据推导出导航功能并以适合的方式呈现它们。

Tips

关于更多 ALPS 元数据的信息,请参考https://spring.io/blog/2014/07/14/spring-data-rest-now-comes-with-alps-metadata。

三. 配置一个自定义的 Servlet 的过滤器

在一个真实的Web应用程序中,我们几乎总是需要为服务请求添加装饰器或包装器,用来记录它们,过滤XSS(跨站脚本攻击)的非法字符,执行认证等。Spring Boot自动添加OrderedCharacterEncodingFilter和HiddenHttpMethodFilter 两个过滤器,除此之外,还有其他的过滤器。 让我们看看Spring Boot如何帮助我们实现这个任务。

在Spring Boot,Spring Web,Spring MVC等的各种框架中,已经有各种不同的servlet过滤器可用,我们所要做的就是将它们作为一个bea定义到配置中。 假设应用程序将在负载平衡器代理之后运行,并且当我们的应用程序实例收到请求时,我们希望将用户使用的实际请求IP转换为代理的IP。 幸运的是,Tomcat 8已经为我们提供了一个实现:RemoteIpFilter。 我们需要做的就是将其添加到我们的过滤器链中。

根据功能的不同,便于管理和职责清晰,我们需要把不同的类放在不同的包下,我们创建一个WebConfiguration.java 的文件,放在src/main/java/org/test/bookpub 目录下。

package org.test.bookpub;

import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; @Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Bean
public RemoteIpFilter remoteIpFilter() {
return new RemoteIpFilter();
}
}

第二步,执行./gradlew clean bootRun命令,在启动中,查看 log,会出现以下信息,表示过滤器已经添加:

o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'remoteIpFilter' to: [/*]

这个功能背后的功能其实很简单。 我们从单独的配置类开始,并且将我们的方法用于过滤器bean的检测。

我们看看主类BookPubApplication,这个类添加了@SpringBootApplication注解,此注解是是一个元注解,它声明了@ComponentScan等其他注解。@ComponentScan的存在指示Spring Boot将WebConfiguration类检测为@Configuration注解的标记类,并将其定义添加到应用程序上下文中。所以,我们将在WebConfiguration类中声明的任何事情就好像我们将它放在BookPubApplication类中是一样的。

@Bean public RemoteIpFilter remoteIpFilter(){...}声明为RemoteIpFilter类创建一个Spring bean。当Spring Boot 检测到javax.servlet.Filter的所有bean时,它将自动将它们添加到过滤器链中。所以我们要做的就是,如果要添加更多的过滤器,那就是将它们声明为@Bean配置。例如,对于更高级的过滤器配置,如果希望特定的过滤器仅适用于特定的URL模式,可以创建一个FilterBistrationBean类型的@Bean配置,并用来配置精确的设置。

四. 配置一个自定义的拦截器

Servlet过滤器是Servlet API的一部分,与Spring完全没有任何关系,除了自动添加到过滤器链中,Spring MVC为我们提供了另一种方式来包装Web请求:HandlerInterceptor拦截器。根据文档,HandlerInterceptor就像一个Filter,但是,拦截器不是在嵌套链中包含请求,而是在处理请求、处理视图或在页面渲染之前,在不同的阶段向我们提供了拦截点,对请求进行拦截。到最后,请求已经完成。它不改变有关请求的任何内容,但是如果拦截器逻辑返回false,它允许我们通过抛出异常来停止执行。

与过滤器的情况类似,Spring MVC附带了一些预定义的HandlerInterceptor。常用的是LocaleChangeInterceptor和ThemeChangeInterceptor。接下来在应用程序中添加LocaleChangeInterceptor,看看它是如何完成的。

添加一个拦截器并不像刚才声明一个bean那么简单。 实际上需要通过实现WebMvcConfigurer接口或重写WebMvcConfigurationSupport来实现。

第一步,WebConfiguration类继承WebMvcConfigurerAdapter类。

public class WebConfiguration extends
WebMvcConfigurerAdapter {…}

接下来,为LocaleChangeInterceptor拦截器增加@Bean注解,

@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
return new LocaleChangeInterceptor();
}

这实际上只会创建拦截 Spring bean,但不会将其添加到请求处理链中。 为了实现这一点,我们需要重写addInterceptors方法,注册拦截器。

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}

整个代码如下:

package org.test.bookpub;

import org.apache.catalina.filters.RemoteIpFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; @Configuration
public class WebConfiguration extends WebMvcConfigurerAdapter {
@Bean
public RemoteIpFilter remoteIpFilter() {
return new RemoteIpFilter();
} @Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
return new LocaleChangeInterceptor();
} @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}

执行 ./gradlew clean bootRun

应用程序启动以后,在浏览器中输入http://localhost:8080/books?locale=foo。

这时,浏览器报错:

后台的错误 log 如下:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.UnsupportedOperationException: Cannot change HTTP accept header - use a different locale resolution strategy

Tips

上面的错误不是因为我们输入了无效的区域设置,而是因为默认语言环境解析策略不允许重置浏览器请求的语言环境。出现一个错误,实际上是证明了拦截器已经生效了。

当涉及到配置Spring MVC内部组件时,它并不像只是定义一堆bean那样简单—— 至少不总是这样。 这是因为需要向请求提供更精细的MVC组件映射。 为了简化难度,Spring为我们提供了WebMvcConfigurerAdapter适配器,它是WebMvcConfigurer接口实现,我们可以扩展和覆盖我们需要的设置。

在配置拦截器的特定情况下,我们可以重写addInterceptors(InterceptorRegistry registry)方法。 这是一个典型的回调方法,我们给予一个注册类,以便根据需要注册多个附加拦截器。 在MVC自动配置阶段,Spring Boot就像过滤器一样检测到WebMvcConfigurer的实例,并依次调用所有这些回调方法。 这意味着如果需要其他逻辑分离,可以有多个WebMvcConfigurer类的实现。

五. 配置一个HttpMessageConverters转换器

在构建RESTful Web服务时,我们定义了控制器,资源库,并在其上面添加了注解,但是从Java实体bean到HTTP数据流输出没有任何类型的对象转换。 实际上,Spring Boot自动配置了HttpMessageConverters转换器将实体bean对象转换为使用了Jackson类库的JSON的格式,将生成的JSON数据写入HTTP响应输出流。 当多个转换器可用时,根据消息对象类和请求的内容类型选择最适用的转换器。

HttpMessageConverters的目的是将各种对象类型转换为相应的HTTP输出格式。 转换器可以支持一系列多种数据类型或多种输出格式,或两者的组合。 例如,MappingJackson2HttpMessageConverter类可以将任何Java对象转换为application/json的格式,而ProtobufHttpMessageConverter类只能对com.google.protobuf.Message的实例进行操作,但可以将其作为application/json,application/xml,text/plain或application/xprotobuf格式。 HttpMessageConverters不仅支持写入HTTP流,还支持将HTTP请求转换为适当的Java对象。

我们可以通过多种方式配置转换器。 这一切都取决于你喜欢哪一个,或者想要实现多少控制。

首先,我们在WebConfiguration类中增加ByteArrayHttpMessageConverter,并加上@Bean注解。

@Bean
public
ByteArrayHttpMessageConverter byteArrayHttpMessageConverter() {
return new ByteArrayHttpMessageConverter();
}

另一种实现方式是重写WebConfiguration类中的configureMessageConverters方法,首先需要继承WebMvcConfigurerAdapter类,具体的代码如下:

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new ByteArrayHttpMessageConverter());
}

如果想获取更多的控制,还可以重写extendMessageConverters方法。

@Override
public void
extendMessageConverters(List<HttpMessageConverter<?>>
converters) {
converters.clear();
converters.add(new ByteArrayHttpMessageConverter());
}

如上所示,Spring给了我们多种方式来实现同样的事情,这一切都取决于我们的偏好或具体的实现细节。

我们介绍了将HttpMessageConverter添加到应用程序中的三种不同的方法。 那有什么区别呢?

将HttpMessageConverter声明为@Bean是向应用程序添加自定义转换器的最快捷,最简单的方法。 它类似于我们在前面的例子中添加了Servlet过滤器。 如果Spring检测到一个HttpMessageConverter类型的bean,它将自动将其添加到列表中。 如果WebConfiguration类没有继承WebMvcConfigurerAdapter父类,那么这是首选方法。

当应用程序需要指定WebMvcConfigurerAdapter的扩展以配置其他的东西,如拦截器,那么重写configureMessageConverters方法并将我们的转换器添加到列表将更为协调一致。可以从Spring Boot 的模块中添加多个WebMvcConfigurers实例并自动配置,但是不能保证我们的方法可以以任何特定的顺序被调用。

如果我们需要做一些更加具体的事情,比如从列表中删除所有其他转换器或清除重复的转换器,这需要重写extendMessageConverters方法的地方。 所有WebMvcConfigurer被调用到configureMessageConverter方法并且转换器列表被完全填充后调用此方法。 当然,WebMvcConfigurer的其他一些实例完全可以重写extendMessageConverters, 但是这样做的机会并不多。

六. 配置一个自定义的PropertyEditors编辑器

在前面的例子中,我们学习了如何为HTTP请求和响应数据配置转换器。 还有其他类型的转换,特别是在将参数动态转换为各种对象时,例如String类型转换为Date或Integer。

当我们在控制器中声明一个映射方法时,Spring使用确切的对象类型来自由定义方法签名。 这个方式是通过使用PropertyEditor实现的。 PropertyEditor是一个默认概念,定义为JDK的一部分,旨在允许将文本值转换为给定类型。 它最初用于构建Java Swing / AWT GUI,后来被证明是适合Spring需要将Web参数转换为方法参数类型的需要。

Spring MVC已经为很多常见类型(如布尔型,货币型和类)提供了大量的PropertyEditor实现。 假设我们要创建一个Isbn类对象,并在我们的控制器中使用它,而不是一个纯粹的String类型。

首先,我们需要在WebConfiguration类中移除extendMessageConverters方法,因为调用converters.clear()这段代码会中断渲染,因为删除了所有支持的类型转换器。

然后,定义Isbn类,和对应的IsbnEditor属性编辑器,以及重写initBinde方法给我们的BookController类,使用以下内容配置IsbnEditor

public class Isbn {
private String isbn; public Isbn(String isbn) {
this.isbn = isbn;
} public String getIsbn() {
return isbn;
}
}
public class IsbnEditor extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
if (StringUtils.hasText(text)) {
setValue(new Isbn(text.trim()));
}
else {
setValue(null);
}
} @Override
public String getAsText() {
Isbn isbn = (Isbn) getValue();
if (isbn != null) {
return isbn.getIsbn();
}
else {
return "";
}
}
} @InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Isbn.class, new IsbnEditor());
}

第三步,在BookController类中修改getBook方法,以便可以接受 Isbn类型的对象,

@RequestMapping(value = "/{isbn}", method = RequestMethod.GET)
public Book getBook(@PathVariable Isbn isbn) {
return bookRepository.findBookByIsbn(isbn.getIsbn());
}

第四步,启动./gradlew clean bootRun,启动成功以后,在浏览器中输入http://localhost:8080/books/978-1-78528-415-1。

虽然我们不会观察到任何可见的更改,但IsbnEditor确实在工作,从{isbn}参数中创建Isbn类对象实例。我们打印了传递过来的Isbn实例,重写了toString()方法。

Spring自动配置大量的默认编辑器,但是对于自定义类型,我们必须明确地为每个Web请求实例化新的编辑器。 这是在控制器中使用@InitBinder注解的方法完成的。 扫描此注解,所有检测到的方法应具有接受WebDataBinder作为参数的签名。 除此之外,WebDataBinder还为我们提供了注册尽可能多的自定义编辑器的能力,要求控制器的方法被正确绑定。

Tips

PropertyEditor不是线程安全的!

因此,我们必须为每个Web请求创建一个新的自定义编辑器实例,并将其注册到WebDataBinder。

如果需要新的PropertyEditor,最好通过扩展PropertyEditorSupport类并自定义重写所需的方法来创建。

七. 配置一个自定义的类型格式化类

PropertyEditor因为它的状态和非线程安全,从版本3起,Spring添加了一个Formatter接口作为PropertyEditor的替代。 格式化类旨在提供类似的功能,但是以完全线程安全的方式,并专注于解析对象类型中的String并将对象转换为其字符串表示形式的非常具体的任务。

对于我们的应用程序,希望有一个格式化程序可以使用一个字符串形式的书籍的ISBN号码并将其转换为一个Book实体对象。 这样,当请求URL签名仅包含ISBN号码或数据库ID时,就可以使用Book类型的参数定义控制器请求的方法。

首先,在src/main/java/org/test/bookpub目录下创建一个新的包formatters,在此包下,创建BookFormatter类并实现Formatter接口,代码示例如下:

public class BookFormatter implements Formatter<Book> {
private BookRepository repository;
public BookFormatter(BookRepository repository) {
this.repository = repository;
}
@Override
public Book parse(String bookIdentifier, Locale locale) throws ParseException {
Book book = repository.findBookByIsbn(bookIdentifier);
return book != null ? book : repository.findOne(Long.valueOf(bookIdentifier));
}
@Override
public String print(Book book, Locale locale) {
return book.getIsbn();
}
}

然后,在WebConfiguration类中,重写addFormatters(FormatterRegistry registry)方法,并把BookFormatter类注册进去。

@RequestMapping(value = "/{isbn}/reviewers", method = RequestMethod.GET)
public List<Reviewer> getReviewers(@PathVariable("isbn") Book book) {
return book.getReviewers();
}

接下来,在BookController类中,新增一个请求方法,用来根据给定的图书的 isbn来显示评论者,

@RequestMapping(value = "/{isbn}/reviewers", method = RequestMethod.GET)
public List<Reviewer> getReviewers(@PathVariable("isbn") Book book) {
return book.getReviewers();
}

为了一些数据,现在手动添加一些测试数据填充数据库,通过向StartupRunner类添加两个自动装配的资源库:

@Autowired private AuthorRepository authorRepository;
@Autowired private PublisherRepository publisherRepository;

下面这些代码添加到StartupRunner类的run(...)方法中:

Author author = new Author("Alex", "Antonov");
author = authorRepository.save(author);
Publisher publisher = new Publisher("Packt");
publisher = publisherRepository.save(publisher);
Book book = new Book("978-1-78528-415-1", "Spring Boot Recipes", author, publisher);
bookRepository.save(book);

输入./gradlew clean bootRun,在控制台,启动应用程序。

访问http://localhost:8080/books/978-1-78528-415-1/reviewers,在浏览器中可以看到如下结果:

格式化功能旨在提供与PropertyEditors类似的功能。 通过将FormatterRegistry注册在重写的addFormatter方法中,告诉Spring使用Formatter将Book的文本表示转换为实体对象并返回。 由于格式化是无状态的,因此我们无需在控制器中每次都要注册; 我们只做一次就好,这确保Spring为每个Web请求使用它。

Tips

如果要定义一个常用类型的转换(例如String或Boolean),就像我们在IsbnEditor示例中所做的那样,最好是通过Controller的InitBinder方法中的PropertyEditors初始化来做,因为这样的改变可能不是全局所期望的,只是针对特定的控制器的功能。

你可能已经注意到,我们还将BookRepository自动装配到WebConfiguration类,因为这是创建BookFormatter所需的。 这是Spring的一个很酷的东西,它让我们可以组合配置类,并使它们同时依赖于其他bean。 正如我们指出,为了创建一个WebConfiguration类,我们需要一个BookRepository,Spring确保在创建WebConfiguration类时首先创建BookRepository,然后自动注入作为依赖。 实例化WebConfiguration之后,将对其进行处理以进行配置说明。

Spring Boot 学习(2)的更多相关文章

  1. Spring Boot学习大全(入门)

    Spring Boot学习(入门) 1.了解Spring boot Spring boot的官网(https://spring.io),我们需要的一些jar包,配置文件都可以在下载.添置书签后,我自己 ...

  2. Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客

    ==他的博客应该不错,没有细看 Spring Boot学习记录(二)--thymeleaf模板 - CSDN博客 http://blog.csdn.net/u012706811/article/det ...

  3. Spring boot学习1 构建微服务:Spring boot 入门篇

    Spring boot学习1 构建微服务:Spring boot 入门篇 Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框 ...

  4. spring boot 学习资料

    spring boot 学习资料: 学习资料 网址 Spring Boot Cookbook-极客学院 http://wiki.jikexueyuan.com/project/spring-boot- ...

  5. Spring Boot学习笔记2——基本使用之最佳实践[z]

    前言 在上一篇文章Spring Boot 学习笔记1——初体验之3分钟启动你的Web应用已经对Spring Boot的基本体系与基本使用进行了学习,本文主要目的是更加进一步的来说明对于Spring B ...

  6. spring boot 学习(十四)SpringBoot+Redis+SpringSession缓存之实战

    SpringBoot + Redis +SpringSession 缓存之实战 前言 前几天,从师兄那儿了解到EhCache是进程内的缓存框架,虽然它已经提供了集群环境下的缓存同步策略,这种同步仍然需 ...

  7. 转载:spring boot学习

    Spring Boot学习 Spring Boot是为了简化Spring应用的创建.运行.调试.部署等而出现的,使用它可以做到专注于Spring应用的开发,而无需过多关注XML的配置. 简单来说,它提 ...

  8. Spring Boot学习路线

    Spring Boot 学习路线,本文计划根据作者近几年的工作.学习经验,来分析和制定一个学习使用 Spring Boot技术的步骤路线图. SpringBoot是伴随着Spring4.0诞生的: S ...

  9. 我的Spring Boot学习记录(二):Tomcat Server以及Spring MVC的上下文问题

    Spring Boot版本: 2.0.0.RELEASE 这里需要引入依赖 spring-boot-starter-web 这里有可能有个人的误解,请抱着怀疑态度看. 建议: 感觉自己也会被绕晕,所以 ...

  10. 15 个优秀开源的 Spring Boot 学习项目,一网打尽!

    Spring Boot 算是目前 Java 领域最火的技术栈了,松哥年初出版的 <Spring Boot + Vue 全栈开发实战>迄今为止已经加印了 8 次,Spring Boot 的受 ...

随机推荐

  1. windows下修改eclipse的默认编码 转

    windows下一般系统编码为 GB2312(中文版的windows), 由于我比较喜欢utf8格式的编码,现将修改方式和大家分享 如果要使新建立工程.java文件直接使UTF-8则需要做以下工作: ...

  2. grep的用法笔记

    1.grep搜索不保护字符串的命令格式如下: #带-v参数 jevan@df ~ grep "agc" -vRn ./

  3. html/css/javascript的含义、作用及理解

    HTML(HyperText Markup Language/超文本标记语言) 含义:HTML是一种用于创建网页的标准标记语言. 作用:页面内可以包含图片.链接,甚至音乐.程序等非文字元素. 理解:主 ...

  4. iOS开发 - 啰嗦讲解 Runloop

    写在前面的 为什么要了解 RunLoop?如果你想成为一个高级iOS开发工程师,那这是你必须了解的东西,他能帮助你更好的理解底层实现的原理,可以利用它的特性做出一些高效又神奇的功能.RunLoop这个 ...

  5. 深入理解css中vertical-align属性

    一.为什么要写这篇文章 今天看到一个问题: 两个div 都设置 display:inline-block,正常显示:但是在第二个div中加一个块级元素或者内联元素,显示就变了个样,为什么? <m ...

  6. 类似智能购票的demo--进入页面后默认焦点在第一个输入框,输入内容、回车、right时焦点自动跳到下一个,当跳到select时,下拉选项自动弹出,并且可以按上下键选择,选择完成后再跳到下一个。

    要实现的效果:进入页面后默认焦点在第一个输入框,输入内容.回车.right时焦点自动跳到下一个,当跳到select时,下拉选项自动弹出,并且可以按上下键选择,选择完成后再跳到下一个. PS:自己模拟的 ...

  7. Maven(二)之Maven项目构建演练

    从上一篇的讲解中我们知道了什么是Maven,然后它的安装配置,到修改本地仓库,这篇我们用一个实际的例子,带领大家走进我们的Maven之旅.让我们一起来体验一下Maven的高度自动化构建项目的过程. 一 ...

  8. ajax发送异步请求

    一:得到XMLHttpRequest对象 ajax其实只需要学习XMLHttpRequest一个对象 大多数浏览器都支持: var xmlHttp = new XMLHttprequest(); IE ...

  9. css3常用方法以及css3选择器

    最重要的 CSS3 模块包括: 选择器 框模型 背景和边框 文本效果 2D/3D 转换 动画 多列布局 用户界面   CSS3 边框   CSS3 边框 通过 CSS3,您能够创建圆角边框,向矩形添加 ...

  10. (知识点)JavaScript闭包

    下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函数定义时创建时自己的环境即作用域 作用域链:函数内可访问自 ...