我正在使用 Spring Boot 开发 Vaadin 应用程序,并且在 MenuLayout 类中的 @PostConstruct 方法期间遇到了 ApplicationProperties 为 null 的问题。这会导致菜单项无法正确设置,并且我在日志中看到以下警告:
2024-09-03T13:09:08.059+03:00 WARN 6988 --- [io-8080-exec-10] c.r.application.layouts.MenuLayout : ApplicationProperties is null. Menu items will not be set up.
2024-09-03T13:09:08.067+03:00 INFO 6988 --- [io-8080-exec-10] c.r.a.config.ApplicationProperties : Unique Categories with Folders: {Transactions=[ObjectTransfers], Organizations=[Organization, Department], Metadata=[ResearcherComment, InfoText], Occurrences=[Event], Sources=[BookSource, OralHistorySource, ArchivalSources, WebSources, SourcePassageCollection, NewspaperPeriodical, Bibliography, SourcePassage], Entities=[Material, Persons, Objects, Collection, Route, DigitalObject, Objects]}
这是我的 MenuLayout 类的相关代码:
@Lazy
@Component
@DependsOn("applicationProperties")
public class MenuLayout extends HybridMenu implements RouterLayout {
private static final long serialVersionUID = 1L;
private static final Logger logger = Logger.getLogger(MenuLayout.class.getName());
private final ApplicationProperties appProperties;
@Autowired
public MenuLayout(@Qualifier("applicationProperties") ApplicationProperties appProperties) {
this.appProperties = appProperties;
}
@PostConstruct
public void postConstruct() {
// Check if ApplicationProperties is null
if (this.appProperties == null) {
logger.log(Level.SEVERE, "ApplicationProperties is null in postConstruct of MenuLayout.");
throw new IllegalStateException("ApplicationProperties is null in postConstruct of MenuLayout.");
}
// Ensure VaadinSession is available
VaadinSession vaadinSession = VaadinSession.getCurrent();
if (vaadinSession == null) {
throw new IllegalStateException("VaadinSession is not available.");
}
// Initialize the menu
init(vaadinSession, UI.getCurrent());
}
@Override
public boolean init(VaadinSession vaadinSession, UI ui) {
initMenu();
return true;
}
private void initMenu() {
withConfig(new MenuConfig());
getConfig().setTheme(ETheme.Lumo);
if (appProperties != null) {
setupMenuItems();
} else {
logger.log(Level.WARNING, "ApplicationProperties is null. Menu items will not be set up.");
}
}
private void setupMenuItems() {
// Menu setup code...
}
}
这是应用程序属性:
package com.ricontrans.application.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
@Primary
@Component
@ConfigurationProperties(prefix = "application")
public class ApplicationProperties {
private final Map<String, Category> acceptedCategories = new HashMap<>();
private final List<Description> descriptions = new ArrayList<>();
private static final Logger logger = Logger.getLogger(ApplicationProperties.class.getName());
public ApplicationProperties() {
logger.log(Level.INFO, "ApplicationProperties constructor called.");
loadProperties();
}
private void loadProperties() {
logger.log(Level.INFO, "Loading properties from configuration.properties.");
Properties properties = new Properties();
try (InputStream input = getClass().getClassLoader().getResourceAsStream("configuration.properties")) {
if (input == null) {
logger.log(Level.WARNING, "configuration.properties not found.");
return;
}
properties.load(input);
// Load accepted categories (existing functionality)
properties.forEach((key, value) -> {
String keyString = (String) key;
String valueString = (String) value;
String[] keyParts = keyString.split("\\.");
if (keyParts.length == 4 && "acceptedCategories".equals(keyParts[1])) {
String categoryName = keyParts[2];
String property = keyParts[3];
// Ensure that the category exists
Category category = acceptedCategories.computeIfAbsent(categoryName, k -> new Category());
// Update the category based on the property
switch (property) {
case "folder":
category.setFolder(valueString);
break;
case "schema":
category.setSchema(valueString);
break;
case "label":
category.setLabel(valueString);
break;
case "icon":
category.setIcon(valueString);
break;
case "tableProperties":
category.setTableProperties(valueString);
break;
case "Pie":
category.setPie(valueString);
break;
case "PieCategories":
category.setPieCategories(valueString);
break;
case "Map":
category.setMap(valueString);
break;
case "Time":
category.setTime(valueString);
break;
case "chartTypes":
category.setChartTypes(valueString);
break;
case "category":
category.setCategory(valueString);
break;
default:
break;
}
}
});
logger.log(Level.INFO, "Accepted Categories: {0}", acceptedCategories);
// Load descriptions for texts and images (new functionality)
int index = 1;
while (true) {
String textPath = properties.getProperty("application.description." + index + ".text");
String imagePath = properties.getProperty("application.description." + index + ".image");
if (textPath == null && imagePath == null) {
break; // No more descriptions to load
}
Description description = new Description();
if (textPath != null) {
description.setTextPath(textPath);
description.setLeft(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".text.left", "false")));
description.setCenter(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".text.center", "false")));
description.setRight(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".text.right", "false")));
}
if (imagePath != null) {
description.setImagePath(imagePath);
description.setLeft(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".image.left", "false")));
description.setCenter(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".image.center", "false")));
description.setRight(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".image.right", "false")));
}
description.setAlignWithLast(Boolean.parseBoolean(properties.getProperty("application.description." + index + ".alignWithLast", "false")));
descriptions.add(description);
index++;
}
logger.log(Level.INFO, "Descriptions loaded: {0}", descriptions);
} catch (IOException ex) {
logger.log(Level.SEVERE, "IOException occurred while loading properties", ex);
}
}
public Map<String, Category> getAcceptedCategories() {
return acceptedCategories;
}
public List<Description> getDescriptions() {
return descriptions;
}
public String getCategoryFolder(String categoryName) {
Category category = acceptedCategories.get(categoryName);
return category != null ? category.getFolder() : null;
}
public Map<String, List<String>> getUniqueCategoriesWithFolders() {
Map<String, List<String>> categoryFoldersMap = new HashMap<>();
acceptedCategories.values().forEach(category -> {
String categoryName = category.getCategory();
String folder = category.getFolder();
if (categoryName != null && folder != null) {
// Get the list of folders for this category, or create a new one if it doesn't exist
List<String> folders = categoryFoldersMap.computeIfAbsent(categoryName, k -> new ArrayList<>());
// Add the folder to the list
folders.add(folder);
}
});
logger.log(Level.INFO, "Unique Categories with Folders: {0}", categoryFoldersMap);
return categoryFoldersMap;
}
public static class Category {
private String folder;
private String schema;
private String label;
private String icon;
private String tableProperties;
private String Pie;
private String PieCategories;
private String Time;
private String Map;
private String chartTypes;
private String category;
private Properties properties = new Properties();
// Getters and setters
public String getFolder() {
return folder;
}
public void setFolder(String folder) {
this.folder = folder;
}
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
public String getLabel() {
return label;
}
public void setLabel(String label) {
this.label = label;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getTableProperties() {
return tableProperties;
}
public void setTableProperties(String tableProperties) {
this.tableProperties = tableProperties;
}
public String getPie() {
return Pie;
}
public void setPie(String pie) {
Pie = pie;
}
public String getPieCategories() {
return PieCategories;
}
public void setPieCategories(String pieCategories) {
PieCategories = pieCategories;
}
public String getTime() {
return Time;
}
public void setTime(String time) {
Time = time;
}
public String getMap() {
return Map;
}
public void setMap(String map) {
Map = map;
}
public String getChartTypes() {
return chartTypes;
}
public void setChartTypes(String chartTypes) {
this.chartTypes = chartTypes;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
@Override
public String toString() {
return "Category{" +
"folder='" + folder + '\'' +
", schema='" + schema + '\'' +
", label='" + label + '\'' +
", icon='" + icon + '\'' +
", tableProperties='" + tableProperties + '\'' +
", Pie='" + Pie + '\'' +
", PieCategories='" + PieCategories + '\'' +
", Time='" + Time + '\'' +
", Map='" + Map + '\'' +
", chartTypes='" + chartTypes + '\'' +
", category='" + category + '\'' +
'}';
}
}
public static class Description {
private String textPath;
private String imagePath;
private boolean left;
private boolean center;
private boolean right;
private boolean alignWithLast;
private String image;
private String text;
// Getters and setters
public String getTextPath() {
return textPath;
}
public void setTextPath(String textPath) {
this.textPath = textPath;
}
public String getImagePath() {
return imagePath;
}
public void setImagePath(String imagePath) {
this.imagePath = imagePath;
}
public boolean isLeft() {
return left;
}
public void setLeft(boolean left) {
this.left = left;
}
public boolean isCenter() {
return center;
}
public void setCenter(boolean center) {
this.center = center;
}
public boolean isRight() {
return right;
}
public void setRight(boolean right) {
this.right = right;
}
public boolean isAlignWithLast() {
return alignWithLast;
}
public void setAlignWithLast(boolean alignWithLast) {
this.alignWithLast = alignWithLast;
}
@Override
public String toString() {
return "Description{" +
"textPath='" + textPath + '\'' +
", imagePath='" + imagePath + '\'' +
", left=" + left +
", center=" + center +
", right=" + right +
", alignWithLast=" + alignWithLast +
'}';
}
public String getImage() {
return image;
}
public void setImage(String image) {
this.image = image;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}
我在这里试图实现的主要功能是我可以为我的所有视图设置一个动态布局混合菜单,并且有关菜单选项的信息在configuration.properties文件中设置,其中加载这些属性都完成到ApplicationProperties.java中! 所以我猜测这里的问题是,由于某种原因,menulayout 总是首先从 applicationProperties 初始化,因为它们都是组件,也许它需要先完成一些工作。
我尝试了很多事情,如你所见:
延迟加载
取决于应用程序属性
构建后。
另外,如果我删除 post 构造方法,我会遇到一个有关 VaadinSession 为空的问题,因为菜单布局被标记为组件,并且会话目前不可用!
让我们来剖析一下这个问题:
postconstruct
运行它应该抛出,如果 appProperties
是
空init
,它再次调用
initMenu
initMenu
appProperties
现在为空,但它是最终的并且
除了c'tor应该能够改变它之外什么都没有任何一件事都必须为真:
对于后者,有一个解释:
RouterLayout
由 Spring 间接管理,但直接通过 Vaadin 管理
-- 访问该站点将为该站点创建视图及其布局
通过 Instantiator
设施查看。 如果 Spring 正在发挥作用,则相反
DefaultInstantiator
SpringInstantiator
最终会做
工作。
但是没有必要/需要为 Spring-DI 配置
RouterLayout
和
在这里它只会造成伤害。
@Lazy
会将实例延迟到需要时;瓦丁需要
照顾这个@Component
使其成为单例,必须删除@DependsOn("applicationProperties")
充其量是没用的
最坏的情况是出现问题,因为布局是由于使用而实现的
在 @Route
注释中所以除非这里有其他东西在起作用,否则我希望这能起作用一次 所有注释均从
RouterLayout
中删除。