任务:
我正在尝试搜索springboot应用程序的解决方案,我们希望在调试模式或开发模式下加载CSV文件。这些CSV文件包含测试值,表示格式正确的数据。
解决方案:
根据spring boot documentation我选择yaml配置文件,我可以说,CSV文件将位于某个确切的位置(即:classpath:/)。财产看起来像这样:
spring
profiles: development
csv:
first-csv: classpath:/first.csv
然后在我们阅读资源时有逻辑。该逻辑将决定我们是否将根据模式(开发或任何其他)调用生产数据或模拟数据(csv文件)。在开发模式中,我们将尝试读取csv文件,这些文件应放在应用程序的根文件夹中(如上面的yaml配置中所示。
问题:
当我为类调用构造函数时,我需要知道.csv文件的位置,我不知道如何通过构造函数将这些字符串值设置为本地字符串值。我的电话看起来像这样:
@Configuration
class WhereWeDecideWhichWayToGo() {
private final CSVProperties csvProperties;
//Code for production solution - which works
@Bean
@Profile("development")
public CreateMockData createMockData() {
return new MockData(csvProperties.getMockCSV());
}
}
其中CSVProperties是一个只有yaml配置文件属性的getter / setter的类。这个类有注释:
@Component
@ConfigurationProperties("csv")
它有效。读取配置文件中的值。在调试期间,我可以确认csvProperties.getMockCSV()=" classpath:/first.csv" ;,但它没有分配给MockData类中的正确变量,如下所示:
class MockData {
String CSV;
public MockData(
String mockCSV) {
// Following line is skipped in debug (and also in normal run)
CSV = mockCSV;
}
// Do some stuff with CSV file
}
问题:
为什么MockData的构造函数中的行初始化为CSV String
CSV = mockCSV;
跳过 - 未分配且代码只是继续(跳过分配),即使mockCSV具有正确的值:
classpath:/first.csv
我认为问题是initialisation order,因为我在构造函数之后的方法中使用了CSV的值,并且它为null。
答案 0 :(得分:2)
由于您似乎忽略了我创建MCVE的建议,我尝试使用您问题中的代码尝试这样做,这对我有用。
您发布的代码显然是根据您实际执行的内容进行大量编辑的,所以我不得不猜测一些事情,并且您的示例中也存在一些语法错误已发布,所以我试图推断出它们在您的代码中的真实含义。以下是我所做的工作,以及关于我猜到的地方的说明,希望它能指出你正确的方向。
所以,从一开始,这里就是@SpringBootApplication
的类,大概你在代码库的某个地方有这样的东西:
@SpringBootApplication
public class CSVExampleApplication {
public static void main(String[] args) {
SpringApplication.run(CSVExampleApplication.class, args);
}
}
这是配置属性类。请注意,您不需要它是@Component
。
@ConfigurationProperties("csv")
public class CSVProperties {
private String firstCsv;
public String getFirstCsv() {
return firstCsv;
}
public void setFirstCsv(String firstCsv) {
this.firstCsv = firstCsv;
}
}
我调用了属性firstCsv
以匹配application.yml
文件first-csv
中的值。有趣的是,在您的代码中,您似乎使用csvProperties.getMockCSV()
来引用此属性。我猜你的问题只是一个错字,因为这样做永远不会有效 - 属性名称需要匹配application.yml
文件中的密钥。
这是配置类。你没有在你的例子中的任何地方展示过这个,但可能你在某处有一个等价物。重要的部分是@EnableConfigurationProperties
,它必须指定具有@ConfigurationProperties
注释的类。
@Configuration
@EnableConfigurationProperties(CSVProperties.class)
public class CSVExampleConfiguration {
private final CSVProperties csvProperties;
@Autowired
public CSVExampleConfiguration(CSVProperties csvProperties) {
this.csvProperties = csvProperties;
}
@Bean
@Profile("!development")
public MockData createProductionMockData() {
return new MockData("production");
}
@Bean
@Profile("development")
public MockData createMockData() {
return new MockData(csvProperties.getFirstCsv());
}
}
有趣的是,在您的问题中,您说您使用类似public CreateMockData createMockData() {
的方法创建bean,但随后返回MockData
。同样,我猜测这是你问题中的拼写错误,因为它不会像这样编译(除非MockData
扩展CreateMockData
,但这看起来很奇怪。)
我不确定您是如何设置制作配置文件的,但希望我上面所做的是合理的等效 - @Profile("!development")
说"创建此bean如果'发展'个人资料未设置"
我的application.yml
文件与您在问题中发布的内容略有不同:
spring:
profiles: development
csv:
first-csv: classpath:/first.csv
您的示例根本无法工作,首先是因为您在:
之后错过了spring
,其次是因为您似乎csv
嵌套在spring
之下{1}},这不是你如何设置配置属性 - 它需要在如上所述的根级别。同样,我认为这些只是问题中的拼写错误,因为你说应用程序启动(它不会丢失:
)并且你看到配置属性得到设置(它不会# t csv
嵌套在spring
下。
最后,我用一个简单的控制器测试了所有这些。您还没有提供有关应用程序其余部分的任何详细信息,但这是我已经完成的工作,希望能够模仿您的代码:
@RestController
public class TestController {
private final MockData mockData;
@Autowired
public TestController(MockData mockData) {
this.mockData = mockData;
}
@RequestMapping(value = "/foo", method = RequestMethod.GET)
public String getCsv() {
return mockData.getCSV();
}
}
那么,在应用程序运行且没有配置文件集的情况下,如果我在浏览器中访问http://localhost:8080/foo
,我会得到String" production"在响应中,如果我重新启动应用程序,使用" development"的配置文件,我会收到" classpath的响应:/first.csv"。
我很欣赏这可能不是"只是这样做"您可能希望得到的答案,但我建议您将其与您的代码进行比较,并尝试修改任何不同的内容。如果仍然无法使其工作,那么应用程序中的其他地方必然存在导致问题的其他一些差异。如果您需要更多帮助,请使用我错过的详细信息编辑您的问题,但请尝试发布实际代码(复制和粘贴,而不是重新输入,以避免引入混乱的拼写错误)。