Vaadin Crud 组件不从 JPA 加载数据
Vaadin Crud component doesn't load data from JPA
我正在尝试为我的 Discord Bot 创建一个 Web 界面,它允许用户在他们的服务器上更改 Bot 的一些设置。
我使用 Spring JPA 存储这些设置。问题是存储的信息永远不会出现在 Crud 组件中,但我可以通过它创建新信息。
存储空间Class:
@Table(name = "guild_temp_channel_settings")
@Entity
public class GuildTempChannelSettings {
@GeneratedValue
@Id
@Getter
@Setter
private Long id;
@Getter
@Setter
private long guildId;
@Getter
@Setter
private long channelId;
@Getter
@Setter
private String channelName;
}
存储库:
public interface GuildTempChannelSettingsRepository extends JpaRepository<GuildTempChannelSettings, Long> {
List<GuildTempChannelSettings> findByGuildId(long guildId);
}
数据提供者:
@Slf4j
public class GuildTempChannelSettingsDataProvider extends AbstractBackEndDataProvider<GuildTempChannelSettings, CrudFilter> {
private final GuildTempChannelSettingsRepository tempChannelSettingsRepository;
private final long guildId;
public GuildTempChannelSettingsDataProvider(GuildTempChannelSettingsRepository tempChannelSettingsRepository, long guildId) {
this.tempChannelSettingsRepository = tempChannelSettingsRepository;
this.guildId = guildId;
}
@Override
protected Stream<GuildTempChannelSettings> fetchFromBackEnd(Query<GuildTempChannelSettings, CrudFilter> query) {
int offset = query.getOffset();
int limit = query.getLimit();
Stream<GuildTempChannelSettings> stream = tempChannelSettingsRepository.findByGuildId(this.guildId).stream();
log.info("Found {} entries", stream.count());
if (query.getFilter().isPresent()) {
stream = stream
.filter(predicate(query.getFilter().get()))
.sorted(comparator(query.getFilter().get()));
}
return stream.skip(offset).limit(limit);
}
@Override
protected int sizeInBackEnd(Query<GuildTempChannelSettings, CrudFilter> query) {
return tempChannelSettingsRepository.findByGuildId(this.guildId).size();
}
private static Predicate<GuildTempChannelSettings> predicate(CrudFilter filter) {
// For RDBMS just generate a WHERE clause
return filter.getConstraints().entrySet().stream()
.map(constraint -> (Predicate<GuildTempChannelSettings>) person -> {
try {
Object value = valueOf(constraint.getKey(), person);
return value != null && value.toString().toLowerCase()
.contains(constraint.getValue().toLowerCase());
} catch (Exception e) {
e.printStackTrace();
return false;
}
})
.reduce(Predicate::and)
.orElse(e -> true);
}
private static Comparator<GuildTempChannelSettings> comparator(CrudFilter filter) {
return filter.getSortOrders().entrySet().stream()
.map(sortClause -> {
try {
Comparator<GuildTempChannelSettings> comparator = Comparator.comparing(settings ->
(Comparable) valueOf(sortClause.getKey(), settings)
);
if (sortClause.getValue() == SortDirection.DESCENDING) {
comparator = comparator.reversed();
}
return comparator;
} catch (Exception ex) {
return (Comparator<GuildTempChannelSettings>) (o1, o2) -> 0;
}
})
.reduce(Comparator::thenComparing)
.orElse((o1, o2) -> 0);
}
private static Object valueOf(String fieldName, GuildTempChannelSettings person) {
try {
Field field = GuildTempChannelSettings.class.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(person);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
布局 Crud 用于:
private VerticalLayout createTemporaryChannelSettings() {
VerticalLayout layout = new VerticalLayout();
layout.addClassNames("box l radius", "contrast-5pct");
Span title = new Span("Coming Soon");
title.addClassNames("header-text", "font-size-xxl");
layout.add(title);
Hr titleLine = new Hr();
layout.add(titleLine);
Crud<GuildTempChannelSettings> crud = new Crud<>(GuildTempChannelSettings.class, createGrid(), createCrudEditor());
GuildTempChannelSettingsDataProvider dataProvider = new GuildTempChannelSettingsDataProvider(this.guildTempChannelSettingsRepository, this.guild.getIdLong());
crud.setDataProvider(dataProvider);
crud.addDeleteListener(deleteEvent -> {
//TODO delete channel
this.guildTempChannelSettingsRepository.delete(deleteEvent.getItem());
});
crud.addSaveListener(saveEvent -> {
//TODO create channel
this.guildTempChannelSettingsRepository.save(saveEvent.getItem());
});
layout.add(crud);
Html total = new Html("<span>Total: <b>" + this.guildTempChannelSettingsRepository.findByGuildId(this.guild.getIdLong()).size() + "</b> employees</span>");
Button button = new Button("New", VaadinIcon.PLUS.create());
button.addClickListener(event -> crud.edit(new GuildTempChannelSettings(), Crud.EditMode.NEW_ITEM));
button.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
HorizontalLayout toolbar = new HorizontalLayout(total, button);
toolbar.setAlignItems(FlexComponent.Alignment.CENTER);
toolbar.setFlexGrow(1, toolbar);
toolbar.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
toolbar.setSpacing(false);
crud.setToolbar(toolbar);
return layout;
}
我已经尝试使用 Vaadin Crud component docs 来实现它,但它从不显示组件内部的一些数据。 DataProvider 中的 fetchFromBackEnd
永远不会被调用(不确定这是否重要)。
我是否遗漏了一些信息来加载信息?
编辑:
我可以通过将 crud.addNewListener(newEvent -> newEvent.getItem().setGuildId(this.guild.getIdLong()));
添加到 Crud 组件来解决这个问题。感谢 Simon Martinelli 给我的提示。
可悲的是,当 fetchFromBackEnd
被调用时,我 运行 现在进入 stream has already been operated upon or closed
Exception。
我不知道那里发生了什么:S
第一个问题可以通过在布局中添加 crud.addNewListener(newEvent -> newEvent.getItem().setGuildId(this.guild.getIdLong()));
来解决。
感谢 Simon Martinelli :)
另一个问题可以通过在 DataProvider fetchFromBackEnd
方法中使用 List 而不是 Stream 来解决
我正在尝试为我的 Discord Bot 创建一个 Web 界面,它允许用户在他们的服务器上更改 Bot 的一些设置。
我使用 Spring JPA 存储这些设置。问题是存储的信息永远不会出现在 Crud 组件中,但我可以通过它创建新信息。
存储空间Class:
@Table(name = "guild_temp_channel_settings")
@Entity
public class GuildTempChannelSettings {
@GeneratedValue
@Id
@Getter
@Setter
private Long id;
@Getter
@Setter
private long guildId;
@Getter
@Setter
private long channelId;
@Getter
@Setter
private String channelName;
}
存储库:
public interface GuildTempChannelSettingsRepository extends JpaRepository<GuildTempChannelSettings, Long> {
List<GuildTempChannelSettings> findByGuildId(long guildId);
}
数据提供者:
@Slf4j
public class GuildTempChannelSettingsDataProvider extends AbstractBackEndDataProvider<GuildTempChannelSettings, CrudFilter> {
private final GuildTempChannelSettingsRepository tempChannelSettingsRepository;
private final long guildId;
public GuildTempChannelSettingsDataProvider(GuildTempChannelSettingsRepository tempChannelSettingsRepository, long guildId) {
this.tempChannelSettingsRepository = tempChannelSettingsRepository;
this.guildId = guildId;
}
@Override
protected Stream<GuildTempChannelSettings> fetchFromBackEnd(Query<GuildTempChannelSettings, CrudFilter> query) {
int offset = query.getOffset();
int limit = query.getLimit();
Stream<GuildTempChannelSettings> stream = tempChannelSettingsRepository.findByGuildId(this.guildId).stream();
log.info("Found {} entries", stream.count());
if (query.getFilter().isPresent()) {
stream = stream
.filter(predicate(query.getFilter().get()))
.sorted(comparator(query.getFilter().get()));
}
return stream.skip(offset).limit(limit);
}
@Override
protected int sizeInBackEnd(Query<GuildTempChannelSettings, CrudFilter> query) {
return tempChannelSettingsRepository.findByGuildId(this.guildId).size();
}
private static Predicate<GuildTempChannelSettings> predicate(CrudFilter filter) {
// For RDBMS just generate a WHERE clause
return filter.getConstraints().entrySet().stream()
.map(constraint -> (Predicate<GuildTempChannelSettings>) person -> {
try {
Object value = valueOf(constraint.getKey(), person);
return value != null && value.toString().toLowerCase()
.contains(constraint.getValue().toLowerCase());
} catch (Exception e) {
e.printStackTrace();
return false;
}
})
.reduce(Predicate::and)
.orElse(e -> true);
}
private static Comparator<GuildTempChannelSettings> comparator(CrudFilter filter) {
return filter.getSortOrders().entrySet().stream()
.map(sortClause -> {
try {
Comparator<GuildTempChannelSettings> comparator = Comparator.comparing(settings ->
(Comparable) valueOf(sortClause.getKey(), settings)
);
if (sortClause.getValue() == SortDirection.DESCENDING) {
comparator = comparator.reversed();
}
return comparator;
} catch (Exception ex) {
return (Comparator<GuildTempChannelSettings>) (o1, o2) -> 0;
}
})
.reduce(Comparator::thenComparing)
.orElse((o1, o2) -> 0);
}
private static Object valueOf(String fieldName, GuildTempChannelSettings person) {
try {
Field field = GuildTempChannelSettings.class.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(person);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
布局 Crud 用于:
private VerticalLayout createTemporaryChannelSettings() {
VerticalLayout layout = new VerticalLayout();
layout.addClassNames("box l radius", "contrast-5pct");
Span title = new Span("Coming Soon");
title.addClassNames("header-text", "font-size-xxl");
layout.add(title);
Hr titleLine = new Hr();
layout.add(titleLine);
Crud<GuildTempChannelSettings> crud = new Crud<>(GuildTempChannelSettings.class, createGrid(), createCrudEditor());
GuildTempChannelSettingsDataProvider dataProvider = new GuildTempChannelSettingsDataProvider(this.guildTempChannelSettingsRepository, this.guild.getIdLong());
crud.setDataProvider(dataProvider);
crud.addDeleteListener(deleteEvent -> {
//TODO delete channel
this.guildTempChannelSettingsRepository.delete(deleteEvent.getItem());
});
crud.addSaveListener(saveEvent -> {
//TODO create channel
this.guildTempChannelSettingsRepository.save(saveEvent.getItem());
});
layout.add(crud);
Html total = new Html("<span>Total: <b>" + this.guildTempChannelSettingsRepository.findByGuildId(this.guild.getIdLong()).size() + "</b> employees</span>");
Button button = new Button("New", VaadinIcon.PLUS.create());
button.addClickListener(event -> crud.edit(new GuildTempChannelSettings(), Crud.EditMode.NEW_ITEM));
button.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
HorizontalLayout toolbar = new HorizontalLayout(total, button);
toolbar.setAlignItems(FlexComponent.Alignment.CENTER);
toolbar.setFlexGrow(1, toolbar);
toolbar.setJustifyContentMode(FlexComponent.JustifyContentMode.BETWEEN);
toolbar.setSpacing(false);
crud.setToolbar(toolbar);
return layout;
}
我已经尝试使用 Vaadin Crud component docs 来实现它,但它从不显示组件内部的一些数据。 DataProvider 中的 fetchFromBackEnd
永远不会被调用(不确定这是否重要)。
我是否遗漏了一些信息来加载信息?
编辑:
我可以通过将 crud.addNewListener(newEvent -> newEvent.getItem().setGuildId(this.guild.getIdLong()));
添加到 Crud 组件来解决这个问题。感谢 Simon Martinelli 给我的提示。
可悲的是,当 fetchFromBackEnd
被调用时,我 运行 现在进入 stream has already been operated upon or closed
Exception。
我不知道那里发生了什么:S
第一个问题可以通过在布局中添加 crud.addNewListener(newEvent -> newEvent.getItem().setGuildId(this.guild.getIdLong()));
来解决。
感谢 Simon Martinelli :)
另一个问题可以通过在 DataProvider fetchFromBackEnd
方法中使用 List 而不是 Stream 来解决