Spring框架(Spring Boot)的技巧
总的来说
这是关于Spring框架(Spring Boot)的技巧。我们将随时进行更新。
一些较长的内容将作为单独的文章发布,并在此处提供链接。
另外,请注意,最初发布的技巧是在2015年使用的旧版本,可能不再适用,敬请留意。
建议
将属性文件的值设置为字段的默认值。
- 環境: Spring Boot 1.3.0.M5, Java 1.8.0_60
价值注解
您可以使用Value注解将属性文件的值作为字段的默认值。
- Annotation Type Value
myapp:
string:
property: Some text
propertyDefault:
# propertyUnresolvable:
int:
property: 123
boolean:
property: true
@Value("${myapp.string.property}")
private String stringProperty;
@Value("${myapp.int.property}")
private int intProperty;
@Value("${myapp.boolean.property}")
private boolean boolProperty;
logger.info("String:{} int:{} bool:{}", stringProperty, intProperty, boolProperty);
// ⇒ String:Some text int:123 bool:true
未被定义的属性
当引用未定义的属性时会引发异常。
@Value("${myapp.string.propertyUnresolvable}")
private String stringPropertyUnresolvable;
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'myapp.string.propertyUnresolvable' in string value "${myapp.string.propertyUnresolvable}"
为了解决这个问题,我们将自定义PropertySourcesPlaceholderConfigurer。我们将使用setIgnoreUnresolvablePlaceholders方法来忽略无法解决的属性。
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer config = new PropertySourcesPlaceholderConfigurer();
config.setIgnoreUnresolvablePlaceholders(true);
return config;
}
接下来,我们将设置默认值。通过使用冒号进行分隔来指定默认值。
@Value("${myapp.string.propertyUnresolvable:defaultValue}")
private String stringPropertyUnresolvable;
结果如下所示。
logger.info("String Unresolvable:{}", stringPropertyUnresolvable);
// ⇒ String Unresolvable:defaultValue
默认值
如果属性的值未被定义,那么将不会反映Value注解指定的默认值。
myapp:
string:
propertyDefault:
@Value("${myapp.string.propertyDefault:defaultValue}")
private String stringPropertyDefault;
在字段中,未反映默认值的Value注释将输出为空字符串。
logger.info("String Default:{}", stringPropertyDefault);
// ⇒ String Default:
为了解决这个问题,我们可以定制PropertySourcesPlaceholderConfigurer。我们可以使用setNullValue方法将空字符串转换为null。
@Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
PropertySourcesPlaceholderConfigurer config = new PropertySourcesPlaceholderConfigurer();
config.setIgnoreUnresolvablePlaceholders(true);
config.setNullValue("");
return config;
}
然而,默认值未被设置,将变为null。
logger.info("String Default:{}", stringPropertyDefault);
// ⇒ String Default:null
因此,在此处用Value注释不指定默认值,而是使用Optional。
@Value("${myapp.string.propertyDefault}")
private Optional<String> stringPropertyDefault;
结果如下所示。
logger.info("String Default:{}", stringPropertyDefault.orElse("defaultValue"));
// ⇒ String Default:defaultValue
收集
- Class DefaultFormattingConversionService
用yaml定义数组的方式如下,但是spring似乎不支持这种形式的数组定义。(这个问题已经被列为@Value注解应该能够从YAML属性中注入List的问题。)
myapp:
intList:
property:
- 1
- 2
- 3
- 4
- 5
目前,我们使用逗号来分隔并列举数值,以表示数组。
myapp:
intList:
property: 1,2,3,4,5
stringArray:
property: a,b,c,d,e
@Value("${myapp.intList.property}")
private List<Integer> intList;
@Value("${myapp.stringArray.property}")
private List<String> stringArray;
然而,继续这样下去将会导致异常产生。
Caused by: java.lang.NumberFormatException: For input string: "1,2,3,4,5"
为了解决这个问题,使用ConversionService将DefaultFormattingConversionService进行转换。
@Bean
public static ConversionService conversionService() {
ConversionService conversionService = new DefaultFormattingConversionService();
return conversionService;
}
结果如下。
logger.info("intList:{}", intList.toString());
// ⇒ intList:[1, 2, 3, 4, 5]
logger.info("stringArray:{}", stringArray.toString());
// ⇒ stringArray:[a, b, c, d, e]
本地日期
要将日期时间设为字段的默认值,除了使用Value注释外,还需使用DateTimeFormat注释。
myapp:
localDate:
property: 2015-09-28
localDateTime:
property: 2015-09-28 10:05:00
使用DateTimeFormat注解声明模式。
@Value("${myapp.localDate.property}")
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate localDate;
@Value("${myapp.localDateTime.property}")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime localDateTime;
结果如下所示。
logger.info("localDate:{}", localDate.toString());
// ⇒ localDate:2015-09-28
logger.info("localDateTime:{}", localDateTime.toString());
// ⇒ localDateTime:2015-09-28T10:05
thymeleaf 是一个用于在 Java 网页应用中创建动态模板的开源模板引擎。
您可以从Thymeleaf模板中引用属性文件的值。
myapp:
version: 1.0.1
<p th:text="${@environment.getProperty('myapp.version')}"></p>
结果如下。
<p>1.0.1</p>
对ConversionService进行自定义操作
- 環境: Spring Boot 1.3.0.M5, Java 1.8.0_60
定制化型轉換服務,將日期字串轉換為Date或LocalDate類別。
-
- Interface ConversionService
- Class FormattingConversionServiceFactoryBean
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
@Configuration
public class ConversionConfig {
@Bean
public static ConversionService conversionService() {
FormattingConversionServiceFactoryBean factoryBean = new FormattingConversionServiceFactoryBean();
factoryBean.setConverters(getConverters());
factoryBean.afterPropertiesSet();
ConversionService conversionService = factoryBean.getObject();
return conversionService;
}
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
private static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
private static Set<Converter<String, ?>> getConverters() {
Set<Converter<String, ?>> converters = new HashSet<Converter<String, ?>>();
converters.add(
new Converter<String, Date>() {
@Override
public Date convert(String str) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
return sdf.parse(str);
} catch (ParseException e) {
return null;
}
}
});
converters.add(
new Converter<String, LocalDate>() {
@Override
public LocalDate convert(String str) {
return LocalDate.parse(str, DATE_FORMATTER);
}
});
converters.add(
new Converter<String, LocalDateTime>() {
@Override
public LocalDateTime convert(String str) {
return LocalDateTime.parse(str, DATETIME_FORMATTER);
}
});
return converters;
}
}
确认动作代码
@Autowired
ConversionService conversionService;
public void confirm() {
Integer i = conversionService.convert("2015", Integer.class);
Long l = conversionService.convert("2015", Long.class);
BigDecimal b = conversionService.convert("124.45", BigDecimal.class);
logger.info("Integer:{} Long:{} BigDecimal:{}", i, l, b);
// ⇒ Integer:2015 Long:2015 BigDecimal:124.45
Date d = conversionService.convert("2015-10-03", Date.class);
logger.info("Date:{}", d.toString());
// ⇒ Date:Sat Oct 03 00:00:00 JST 2015
LocalDate ld = conversionService.convert("2015-10-03", LocalDate.class);
logger.info("localDate:{}", ld.toString());
// ⇒ localDate:2015-10-03
}
3. 使用EventListener注解来实现应用程序事件。
- 環境: Spring Boot 1.3.0.M5, Java 1.8.0_60
从Spring 4.2开始,您可以使用EventListener注解来实现应用程序事件的实现。
-
- Annotation Type EventListener
-
- Class ApplicationEvent
-
- Interface ApplicationListener
- Interface ApplicationEventPublisher
不使用注释的实现方法
import java.io.Serializable;
import java.util.Date;
public class Blog implements Serializable {
private static final long serialVersionUID = -5011335950988850583L;
private Long id;
private String title;
private Date published;
public Blog(Long id, String title) {
this.id = id;
this.title = title;
this.published = null;
}
... getter/setter省略 ...
@Override
public String toString() {
return "Blog [id=" + id + ", title=" + title + ", published=" + published
+ "]";
}
}
事件类
import org.springframework.context.ApplicationEvent;
public class BlogEvent extends ApplicationEvent {
private static final long serialVersionUID = 6029200135885343599L;
private Blog blog;
public BlogEvent(Object source, Blog blog) {
super(source);
this.blog = blog;
}
public Blog getBlog() {
return blog;
}
public void setBlog(Blog blog) {
this.blog = blog;
}
}
听众类
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class BlogListener implements ApplicationListener<BlogEvent> {
final static Logger logger = LoggerFactory.getLogger(BlogListener.class);
@Override
public void onApplicationEvent(BlogEvent event) {
logger.info("Blog Event is occured!!");
logger.info(event.getBlog().toString());
event.getBlog().setPublished(new Date());
}
}
实现ApplicationEventPublisherAware
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
@Service
public class BlogService implements ApplicationEventPublisherAware {
final static Logger logger = LoggerFactory.getLogger(BlogService.class);
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
public void createBlog(Blog blog) {
logger.info("Publishing Blog Create Event");
BlogEvent event = new BlogEvent(this, blog);
publisher.publishEvent(event);
}
}
动作确认代码
@Autowired
BlogService blogService;
public void confirm() {
Blog blog = new Blog(1L, "浜省だらけの野球対決を観賞する");
logger.info(blog.toString());
// ⇒ Blog [id=1, title=浜省だらけの野球対決を観賞する, published=null]
blogService.createBlog(blog);
logger.info(blog.toString());
// ⇒ Blog [id=1, title=浜省だらけの野球対決を観賞する, published=Sun Oct 04 20:25:33 JST 2015]
}
使用EventListener注解的实现方法
import java.io.Serializable;
import java.util.Date;
public class Product implements Serializable {
private static final long serialVersionUID = 886343041195980987L;
private Long id;
private String productName;
private Date createdAt;
private Date completedAt;
public Product(Long id, String productName) {
this.id = id;
this.productName = productName;
this.createdAt = null;
this.completedAt = null;
}
... getter/setter省略 ...
@Override
public String toString() {
return "Product [id=" + id + ", productName=" + productName
+ ", createdAt=" + createdAt + ", completedAt=" + completedAt + "]";
}
}
事件类
不需要继承ApplicationEvent。
public class ProductEvent {
private Product product;
private String status;
public ProductEvent(Product product) {
this.product = product;
this.status = "CREATE";
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}
听众类
不需要实现ApplicationListener。 相反,可以在方法上添加EventListener注解来注册事件侦听器。
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
@Component
public class ProductListener {
final static Logger logger = LoggerFactory.getLogger(ProductListener.class);
@EventListener(condition = "#event.status == 'CREATE'")
public void createEvent(ProductEvent event) {
logger.info("Product Create Event is occured!!");
try {
TimeUnit.SECONDS.sleep(3L);
} catch (InterruptedException e) {
e.printStackTrace();
}
event.getProduct().setCreatedAt(new Date());
}
@EventListener(condition = "#event.status == 'COMPLETE'")
public void closeEvent(ProductEvent event) {
logger.info("Product Complete Event is occured!!");
try {
TimeUnit.SECONDS.sleep(3L);
} catch (InterruptedException e) {
e.printStackTrace();
}
event.getProduct().setCompletedAt(new Date());
}
}
发布事件的类
不需要实现ApplicationEventPublisherAware。
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
@Service
public class ProductService {
final static Logger logger = LoggerFactory.getLogger(ProductService.class);
@Autowired
ApplicationEventPublisher publisher;
public void createProduct(Product product) {
logger.info("Publishing Product Create Event");
ProductEvent event = new ProductEvent(product);
publisher.publishEvent(event);
}
public void completeProduct(Product product) {
logger.info("Publishing Product Complete Event");
ProductEvent event = new ProductEvent(product);
event.setStatus("COMPLETE");
publisher.publishEvent(event);
}
}
运动确认代码
@Autowired
ProductService productService;
public void confirm() {
Product product = new Product(1L, "Mazda RX-7");
logger.info(product.toString());
// ⇒ Product [id=1, productName=Mazda RX-7, createdAt=null, completedAt=null]
productService.createProduct(product);
logger.info(product.toString());
// ⇒ Product [id=1, productName=Mazda RX-7, createdAt=Sun Oct 04 20:25:36 JST 2015, completedAt=null]
try {
TimeUnit.SECONDS.sleep(3L);
} catch (InterruptedException e) {
e.printStackTrace();
}
productService.completeProduct(product);
logger.info(product.toString());
// ⇒ Product [id=1, productName=Mazda RX-7, createdAt=Sun Oct 04 20:25:36 JST 2015, completedAt=Sun Oct 04 20:25:42
}
4. 使用ResourceLoader从资源文件中获取资源
- 環境: Spring Boot 1.3.0.M5, Java 1.8.0_60
如果无法使用ApplicationContext的实例来获取资源文件,可以使用ResourceLoader代替来获取资源文件。
- Interface ResourceLoader
资源文件
在/src/main/resources中创建用于动作确认的资源文件。
/src/main/resources/resource1.txt 的以下内容,用汉语进行本地化的释义。
123
456
789
/src/main/resources/resource2.txt 的中文本地化版本
ABC
DEF
GHI
/主/资源3.txt
あいうえお
かきくけこ
さしすせそ
动作确认代码
-
- 使用ApplicationContext的方式
-
- 使用ResourceLoader的方式
- 使用DefaultResourceLoader的方式
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Service;
@Service
public class ResourceLoaderService {
final static Logger logger = LoggerFactory.getLogger(ResourceLoaderService.class);
@Autowired
ResourceLoader resourceLoader;
@Autowired
ApplicationContext context;
// (1)
public void execute1() {
try {
Resource resource = context.getResource("classpath:resource1.txt");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
reader.lines().forEach(line -> {
logger.info(line);
// ⇒ 123
// ⇒ 456
// ⇒ 789
});
}
} catch (IOException e) {
logger.error(e.getMessage());
}
}
// (2)
public void execute2() {
try {
Resource resource = resourceLoader.getResource("classpath:resource2.txt");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
reader.lines().forEach(line -> {
logger.info(line);
// ⇒ ABC
// ⇒ DEF
// ⇒ GHI
});
}
} catch (IOException e) {
logger.error(e.getMessage());
}
}
// (3)
public void execute3() {
try {
Resource resource = new DefaultResourceLoader().getResource("classpath:resource3.txt");
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
reader.lines().forEach(line -> {
logger.info(line);
// ⇒ あいうえお
// ⇒ かきくけこ
// ⇒ さしすせそ
});
}
} catch (IOException e) {
logger.error(e.getMessage());
}
}
}
当尝试通过Resource.getFile来读取资源文件时,如果将应用程序打包成jar文件并执行,则会出现FileNotFoundException。
try (BufferedReader reader = new BufferedReader(new FileReader(resource.getFile()))) {
reader.lines().forEach(line -> {
//...処理
});
}
java.io.FileNotFoundException: class path resource [resource3.txt] cannot be resolved to absolute file path because it does not reside in the file system: jar:file: 省略...
5. 通过MessageSource获取消息源。
-
- 投稿: 2015/10/08
- 環境: Spring Boot 1.3.0.M5, Java 1.8.0_60
在中国的母语中,以下是一个选项的释义:配置消息资源是通过spring.messages.*属性进行的。
# INTERNATIONALIZATION (MessageSourceAutoConfiguration)
spring:
messages:
basename: messages,views
cache-seconds: -1
encoding: utf-8
-
- basename
メッセージソースファイルのベース名を指定します。複数指定する場合はカンマで区切ります。デフォルトはmessagesです。
cache-seconds
メッセージソースをキャッシュする秒数を指定します。デフォルトは-1でキャッシュの期限は無期限です。 0を指定するとキャッシュされません。
encoding
メッセージソースのエンコードを指定します。デフォルトはutf-8です。
可以通过向消息源文件的基本名称中添加像_ja或_en这样的区域设置来实现国际化。如果只需要支持一种语言,则不需要区域设置。
message.text1 = abc
message.text2 = 123
message.text3 = hello {0}.
layout.header = \u30D8\u30C3\u30C0\u30FC
layout.footer = Copyright {0} - {1}.
控制器
如果想在Controller类内引用消息源,可以使用MessageSource的实例。
@Autowired
MessageSource messageSource;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index(Model model, Locale locale) {
String text1 = messageSource.getMessage("message.text1", null, locale);
String text2 = messageSource.getMessage("message.text2", null, locale);
String text3 = messageSource.getMessage("message.text3", new Object[]{"world!"}, locale);
logger.info("message: text1:{} text2:{} text3:{}", text1, text2, text3);
// ⇒ message: text1:abc text2:123 text3:hello world!.
return "Index/index";
}
thymeleaf (百叶窗)
在thymeleaf模板中引用消息资源,可以使用#{资源键}的语法。
<h1 th:text="#{layout.header}">header</h1>
<h3 th:text="#{layout.footer('2014','2015')}">footer</h3>
以下是结果。
<h1>ヘッダー</h1>
<h3>Copyright 2014 - 2015.</h3>
使用SPRING INITIALIZR生成应用程序的模板。
- 投稿: 2015/10/08
您可以使用SPRING INITIALIZR生成pom.xml和build.gradle的模板。
请指定项目类型(Maven或Gradle)和Spring-Boot的版本,并输入项目元数据。
然后点击”切换到完整版本”的链接文本。

勾选必要的组件,最后点击“生成项目”按钮即可开始下载项目模板的zip文件。
下载:提示示例.zip

以下是解压缩zip文件后的目录结构。
tips-example
├─.mvn
│ └─wrapper
└─src
├─main
│ ├─java
│ │ └─com
│ │ └─example
│ │ └─sbtip
│ └─resources
│ ├─static
│ └─templates
└─test
└─java
└─com
└─example
└─sbtip
要将此应用程序导入到eclipse中,请进入解压后的目录并执行以下命令。
> mvn eclipse:eclipse
7. 关机挂钩
-
- 投稿: 2015/10/20
- 環境: Spring Boot 1.3.0.M5, Java 1.8.0_60
在应用程序结束时执行任意方法,可以使用PreDestro注解。
@PreDestroy
public static void exit() {
System.out.println("appliation exit");
}
8. 将属性文件的值设定为其他键的值。
-
- 投稿: 2016/02/07
- 環境: Spring Boot 1.3.0, Java 1.8.0_65
属性文件的值可以使用SpEL表达式进行定义。
myapp:
configA:
var1: ABC
var2: DEF
configB:
var1: 123
var2: ${myapp.configA.var1}
使用Thymeleaf直接输出并确认。
<div class="row">
<p th:text="${@environment.getProperty('myapp.configA.var1')}"></p>
<p th:text="${@environment.getProperty('myapp.configA.var2')}"></p>
<p th:text="${@environment.getProperty('myapp.configB.var1')}"></p>
<p th:text="${@environment.getProperty('myapp.configB.var2')}"></p>
</div>
<div class="row">
<p>ABC</p>
<p>DEF</p>
<p>123</p>
<p>ABC</p>
</div>
9. 在 Spring Boot 中,编写 Handler 方法的参数来接收任意类的实例作为参数。
-
- 投稿: 2016/10/09
- 環境: Spring Boot 1.3.0, Java 1.8.0_65
10. 使用Spring Boot来构建重定向目标URL
-
- 投稿: 2016/10/09
- 環境: Spring Boot 1.4.1, Java 1.8.0_101
11. 关于Spring Boot devtools的自动重启功能
-
- 投稿: 2016/10/13
- 環境: Spring Boot 1.4.1, Java 1.8.0_101
12. Spring Framework中方便的类,位于“org.springframework.web.util”包。
-
- 投稿: 2016/10/27
- 環境: Spring Boot 1.4.1, Java 1.8.0_101
13. 使用拦截器来设置响应头信息
-
- 投稿: 2016/11/09
- 環境: Spring Boot 1.4.1, Java 1.8.0_101
14. 关于Spring AOP的切点选择器写法
-
- 投稿: 2017/05/02
- 環境: Spring Boot 1.5.3, Java 1.8.0_131
15. 展示如何在Spring Boot 1.5版本中处理多个数据库的网络应用程序示例。
-
- 投稿: 2017/05/04
- 環境: Spring Boot 1.5.3, Java 1.8.0_131
16. 示例代码将属性文件的值分配给期望的字段类型
-
- 投稿: 2017/08/20
- 環境: Spring Boot 1.5.4, Java 1.8.0_144
17. 用maven的多模块构建Spring Boot应用程序
-
- 投稿: 2017/09/25
- 環境: Spring Boot 1.5.6, Java 1.8.0_144
在编辑应用程序的自定义属性时,使代码补全功能可用。
-
- 投稿: 2018/02/25
- 環境: Spring Boot 2.0.0.RC2, Java 1.8.0_162
19. 用Spring Boot开发的应用程序的GitHub存储库
- 投稿: 2018/03/15
这是一个列出了迄今为止为了学习和验证而开发的Spring Boot 应用程序的GitHub仓库列表。
20. 学习掌握Spring Boot
- 投稿: add 2018/04/03
以下是有效的信息来源的总结,适用于追赶时机。
Spring Data Jpa的技巧
在JPQL中查询具有JSON类型列的表
-
- 投稿: 2017/09/15
- 環境: Spring Boot 1.5.6, Java 1.8.0_144
2. 使用Spring Data JPA的QBE(Query by Example)进行搜索的示例代码。
-
- 投稿: 2017/09/13
- 環境: Spring Boot 1.5.6, Java 1.8.0_144
3. 使用JPQL调用数据库的用户自定义函数
-
- 投稿: 2017/09/12
- 環境: Spring Boot 1.5.6, Java 1.8.0_144
使用仓库进行搜索,并将特定列映射到POJO中。
-
- 投稿: 2017/09/12
- 環境: Spring Boot 1.5.6, Java 1.8.0_144
5. 我调查了在Spring Boot 1.5.9中进行异步查询的方式。
-
- 投稿: 2017/12/23
- 環境: Spring Boot 1.5.9, Java 1.8.0_144
6. Java持久化API 2.1的复习笔记
-
- 投稿: 2018/03/11
- 環境: Spring Boot 2.0.0, Spring Data JPA 2.0.5, Java 9.0.4
7. 如何在JPA中执行存储过程
-
- 投稿: 2018/03/25
- 環境: Spring Boot 2.0.0, Spring Data JPA 2.0.5, Java 1.8.0_162
测试技巧
1. 关于Spring Boot和单元测试环境的设计
-
- 投稿: 2018/3/20
- 環境: Spring Boot 2.0.0, Java 1.8.0_162
2. 接受Pageable作为参数的控制器处理方法的单元测试失败。
-
- 投稿: 2018/06/30
- 環境: Spring Boot 2.0.3, Java 10.0.1
当运行一个接受类似Pageable参数的处理程序方法的单元测试时,将输出以下错误消息并失败。
No primary or default constructor found for interface org.springframework.data.domain.Pageable
控制器的处理方法 de
@GetMapping(path = "list", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public ResponseEntity<List<Memo>> list(Pageable page) {
//...省略
}
测试代码
@RunWith(SpringRunner.class)
@WebMvcTest(MemoController.class)
public class MemoControllerTests {
@Autowired
private MockMvc mvc;
@Test
public void getList() throws Exception {
RequestBuilder builder = MockMvcRequestBuilders.get("/memo/list")
.param("page", "0")
.param("size", "5")
.accept(MediaType.APPLICATION_JSON_UTF8);
MvcResult result = mvc.perform(builder)
.andExpect(status().isOk())
.andExpect(content().contentType(contentType))
.andDo(print())
.andReturn();
}
}
失败的原因是,在使用WebMvcTest注解进行测试时,PageableHandlerMethodArgumentResolver无法有效地设置Pageable实例,因此为解决此问题而创建了一个问题。
@WebMvcTest 还应该自动配置Spring Data的Web集成功能
您可以通过在测试类中添加以下代码行来暂时解决此问题。
@Import(SpringDataWebAutoConfiguration.class)
開發環境的小貼士
1. 使用Spring Boot 2.0.0的谷歌云平台
-
- 投稿: 2018/03/29
- 環境: Spring Boot 2.0.0, Java 1.8.0_162
这是一个关于如何在Google Cloud Platform上使用Spring Boot运行web应用程序的总结文章。
在使用Java 10开发Spring Boot 2.0应用程序时需要注意的基本事项
-
- 投稿: 2018/06/04
- 環境: Spring Boot 2.0.2, Java 10.0.1
这是关于在Java 10上开发和运行环境的注意事项备忘。
使用Eclipse Photon (4.8)和Java 10来搭建Spring Boot应用程序的开发环境。
-
- 投稿: 2018/6/30
- 環境: Spring Boot 2.0.3, OpenJDK 10.0.1