这让我开始尝试弹簧启动@configurationproperties注释工作。所以希望有人可以为我说明我做错了什么。 我有一个spring boot应用程序,它在类路径中包含一个application.properties。它的值为
server.contextPath=/test/v1
server.port=8080
spring.profiles.active=dev
vendors=me
我有一个application.class,它有一个spring boot注释,位于我的包层次结构的顶部
package com.test;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableConfigurationProperties
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
我正在尝试将属性供应商映射到configurationproperties bean,如下所示
package com.test.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
@Component
@PropertySource("classpath:application.properties")
@ConfigurationProperties
public class GlobalProperties {
private String vendors;
public String getVendors() {
return vendors;
}
public void setVendors(String vendors) {
this.vendors = vendors;
}
}
然后从我的rest控制器调用这个bean。我知道它解析了属性,因为当我重命名它时,服务器无法启动。在下面的代码中,props bean没有得到自动装配,并且为null。 //为简洁省略了代码
package com.test.controller;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.test.config.GlobalProperties;
@RestController
@Component
public class MController {
//TODO should be wired in from properties file
@Autowired
GlobalProperties props;
private boolean vendorUnknown(String vendor) {
if(props.getAllowedVendor().equalsIgnoreCase(vendor)) {
return true;
}
return false;
}
@RequestMapping(value = "/test/{id}", method = RequestMethod.GET, produces = { "application/json" })
public ResponseEntity<?> getStatus(
@PathVariable String id) {
//@RequestBody Bookmark input
if(vendorUnknown("me")) {
System.out.println("found");
};
return ResponseEntity.noContent().build();
}
}
有人指出我做错了吗?
更新:
将上面的代码更改为更简单的版本,并使用测试类重新创建问题。请参阅下面的我的pom.xml和测试类
的pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.me.test</groupId>
<artifactId>test-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.3.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- tag::actuator[] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- end::actuator[] -->
<!-- tag::tests[] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- end::tests[] -->
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
测试类:
package com.test.controller;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class MControllerTest {
@Autowired
private MockMvc mockMvc;
@InjectMocks
MController testController;
@Before
public void setup() {
// this must be called for the @Mock annotations above to be processed
// and for the mock service to be injected into the controller under
// test.
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(testController).build();
}
@Test
public void testPropertiesMsg() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/test/1").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk());
}
}
答案 0 :(得分:2)
将@EnableConfigurationProperties添加到Application类以启用扫描ConfigurationProperties bean。
答案 1 :(得分:2)
@PropertySource
。您可以保留@Component
,或者如果您没有,请指定@EnableConfigurationProperties(GlobalProperties.class)
。@Component
上不需要testController
。但我认为您的问题是您从中调用vendorUnknown
方法的地方。它没有显示在您的代码中。如果从构造函数调用,那么bean初始化还没有完成,GlobalProperties props
确实是空的。修改强>:
根据OP的编辑,这是一个完全有效的解决方案。
<强> DemoApplication.java 强>:
@SpringBootApplication
@EnableConfigurationProperties
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
<强> DemoController.java 强>:
@RestController
public class DemoController {
@Autowired
private DemoProperties props;
@GetMapping(value = "/", produces = APPLICATION_JSON_VALUE)
public ResponseEntity<?> getVendor() {
return ResponseEntity.ok(props.getVendors());
}
}
<强> DemoProperties.java 强>:
@ConfigurationProperties
@Component
public class DemoProperties {
private String vendors;
public String getVendors() {
return vendors;
}
public void setVendors(String vendors) {
this.vendors = vendors;
}
}
<强> application.properties 强>:
vendors=me
<强> DemoControllerTest.java 强>:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class DemoControllerTest {
@Autowired
TestRestTemplate restTemplate;
@Test
public void testGenVendor() throws Exception {
String vendor = restTemplate.getForObject("/", String.class);
assertThat(vendor).isEqualTo("me");
}
}
OP代码的问题:
MockMvc
没有使用主类,因此未处理EnableConfigurationProperties
。 MockMvc
或WebMvcTest
旨在测试网络层(呃!),而不是整个应用。使用其中任何一个。属性bean应该由测试设置。
InjectMocks
无声地失败。请参阅Why You Should Not Use InjectMocks Annotation to Autowire Fields。