我有这个问题,我不知道如何解决。我使用Spring Boot创建了Restful API,我正在实现DTO-Domain-Entity模式,所以在这种特殊情况下我有这个控制器的方法
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<UserResponseDTO> createUser(@RequestBody UserRequestDTO data) {
UserDomain user = this.mapper.map(data, UserDomain.class);
UserDomain createdUser = this.service.createUser(user);
UserResponseDTO createdUserDTO = this.mapper.map(createdUser, UserResponseDTO.class);
return new ResponseEntity<UserResponseDTO>(createdUserDTO, HttpStatus.CREATED);
}
public class UserDomain {
private Long id;
private Date createdDate;
private Date updatedDate;
private String username;
private String password;
@Value("${default.user.enabled:true}") // I have default-values.properties being loaded in another configuration file
private Boolean enabled;
}
我正在将UserRequestDTO对象转换为UserDomain。据我所知,UserRequestDTO是一个正在注入的bean。然后我将其转换为UserDomain,这里的问题是UserDomain对象不是组件,因此enabled属性不会采用默认值。
如果我不想将UserDomain作为bean处理,我怎么能让spring加载默认值(在这种情况下只启用属性)?
这不是相同的答案,因为我的目标是使用@Value注释完成它。
无论如何,康斯坦丁建议,做这样的事情会更好吗?
public class UserDomain {
@Autowired
private Environment environment;
private Boolean enabled;
UserDomain(){
this.enabled = environment.getProperty("default.user.enabled");
// and all the other ones
}
}
答案 0 :(得分:6)
如果你的mapper有一个方法接受已经准备好的实例而不是Class
,那么你可以添加原型范围的UserDomain
bean并从控制器方法中调用context.getBean()
。
控制器的
...
@Autowired
private WebApplicationContext context;
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
public ResponseEntity<UserResponseDTO> createUser(@RequestBody UserRequestDTO data) {
UserDomain user = this.mapper.map(data, getUserDomain());
UserDomain createdUser = this.service.createUser(user);
UserResponseDTO createdUserDTO = this.mapper.map(createdUser, UserResponseDTO.class);
return new ResponseEntity<UserResponseDTO>(createdUserDTO, HttpStatus.CREATED);
}
private UserDomain getUserDomain() {
return context.getBean(UserDomain.class);
}
...
Spring配置
@Configuration
public class Config {
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propConfigurer = new PropertySourcesPlaceholderConfigurer();
propConfigurer.setLocation(new ClassPathResource("application.properties"));
return propConfigurer;
}
@Bean
@Scope("prototype")
public UserDomain userDomain() {
return new UserDomain();
}
...
}
否则,您可以使用@Configurable
和AspectJ编译时编织。但是你必须决定是否值得在你的项目中引入编织,因为你有其他方法来处理这种情况。
的pom.xml
...
<!-- additional dependencies -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.2.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.6</version>
</dependency>
...
<!-- enable compile-time weaving with aspectj-maven-plugin -->
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.7</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<encoding>UTF-8</encoding>
<aspectLibraries>
<aspectLibrary>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</aspectLibrary>
</aspectLibraries>
<Xlint>warning</Xlint>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
UserDomain.java
@Configurable
public class UserDomain {
private Long id;
private Date createdDate;
private Date updatedDate;
private String username;
private String password;
@Value("${default.user.enabled:true}")
private Boolean enabled;
...
}
Spring配置
@EnableSpringConfigured与<context:spring-configured>
相同。
@Configuration
@EnableSpringConfigured
public class Config {
@Bean
public static PropertySourcesPlaceholderConfigurer properties() {
PropertySourcesPlaceholderConfigurer propConfigurer = new PropertySourcesPlaceholderConfigurer();
propConfigurer.setLocation(new ClassPathResource("application.properties"));
return propConfigurer;
}
...
}
有关AspectJ and @Configurable的更多信息,请参阅Spring文档。
关于你的编辑。
请注意,您在那里使用@Autowired
。这意味着UserDomain
实例必须由Spring容器管理。容器不知道在其外部创建的实例,因此对于此类实例,@Autowired
(完全为@Value
)将无法解析,例如UserDomain userDomain = new UserDomain()
或UserDomain.class.newInstance()
。因此,您仍然需要将一个原型范围的UserDomain
bean添加到您的上下文中。实际上,这意味着提议的方法类似于@Value
相关的方法,除了它将您的UserDomain
与Spring Environment
联系起来。因此,这很糟糕。
仍然可以使用Environment
和ApplicationContextAware
制作更好的解决方案,而无需将域对象绑定到Spring。
ApplicationContextProvider.java
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getEnvironmentProperty(String key, Class<T> targetClass, T defaultValue) {
if (key == null || targetClass == null) {
throw new NullPointerException();
}
T value = null;
if (applicationContext != null) {
System.out.println(applicationContext.getEnvironment().getProperty(key));
value = applicationContext.getEnvironment().getProperty(key, targetClass, defaultValue);
}
return value;
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
}
UserDomain.java
public class UserDomain {
private Boolean enabled;
public UserDomain() {
this.enabled = ApplicationContextProvider.getEnvironmentProperty("default.user.enabled", Boolean.class, false);
}
...
}
Spring配置
@Configuration
@PropertySource("classpath:application.properties")
public class Config {
@Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
...
}
但是,我不喜欢这种方法的额外复杂性和邋iness性。我认为这根本没有道理。
答案 1 :(得分:1)
你没有服务层吗?首选项,参数,默认值等应该注入服务类,这些服务类是集中业务逻辑的服务类,它们应该由Spring管理。
如果您没有UserService
,请将默认值加载到控制器中。
我只是注意到从DTO到域类的转换正在控制器中进行。
定义
@Value("${default.user.enabled:true}")
private Boolean defaultUserEnabled;
在控制器内,然后
if (user.isEnabled() == null)
user.setEnabled(defaultUserEnabled);
但是,正如我已经说过的,声明和默认值的设置都属于Spring管理的服务类。