所以,我遇到了这种情况
我有一个Restful控制器方法,它返回对象list
的{{1}}
Match
对象@RequestMapping(value = "/fetchFootballMatchesToday", method = RequestMethod.GET)
public @ResponseBody List<Match> fetchMatchesScheduledToday() throws ParseException {
return matchesToday;
}
具有15个属性,而我在UI上仅需要3个属性。我不希望用户看到该对象的其他属性。
有两种方法可以做到:
运行一个for循环,并为每个Match
对象显式地将属性设置为null,这并不意味着将其发送到UI。像这样
Match
此方法的问题在于,将来会增加属性的数量。此代码也需要更新。同样,如果对象的属性数量很大。我需要在这里多次设置为空。
第二种方法是在循环内创建一个新的Match对象,并为其设置3个必需的值。
List<Match> matchesToday = matchInvService.fetchMatchByDate(today);
for (Match stats : matchesToday) {
if (stats != null) {
/* user should not know these details, so they are being set to null */
stats.setMatchSuccessIndex(null);
stats.setTeamRanking(null);
stats.setStadiumInfrastructureLevel(null);
..... & so on
}
}
此方法每次循环运行时都会创建其他Match对象。同样,如果调用该特定方法的次数过多,则对象的创建会激增。 尽管对象将被垃圾回收,但我不确定这是否是最佳方法。
需要您的建议。在编写更多代码与节省内存之间进行权衡吗?解决这个问题的最佳方法是什么?
答案 0 :(得分:3)
对象Match具有15个属性,而我只需要3个属性 用户界面。我不希望用户看到其他属性 宾语。
将所有字段设置为null
确实很麻烦且容易出错。
所以我会避免第一种方式。
第二种方法似乎朝着更好的方向发展。
但是您不必担心将对象映射到其他对象,因为客户端需要查看它们的特定视图。
用于“合理”列表大小的简单映射操作很便宜。而且我想您不会在UI中显示数百万行,因此大小应该合理。
否则,您应该考虑分页概念,重新考虑整个UI设计。
我将使用第三个选项:创建一个类,声明客户端需要了解的3个属性,并将Match
映射到该类。它使事情变得更加清晰。
List<Match> matchesToday = matchInvService.fetchMatchByDate(today);
List<MatchDTO> responseList = new ArrayList<Match>();
for (Match stats : matchesToday) {
if (stats != null) {
MatchDTO match = new MatchDTO(stats);
responseList.add(match);
}
}
return responseList;
MatchDTO(Match)
是从Match
实例复制三个必填字段的构造函数:
public MatchDTO(Match match){
this.foo = match.getFoo();
this.bar = match.getBar();
this.fooBar = match.getFooBar();
}
或在Java 8中:
List<MatchDTO> responseList =
matchInvService.fetchMatchByDate(today)
.stream()
.filter(Objects::nonNull)
.map(MatchDTO::new)
.collect(Collectors.toList);
答案 1 :(得分:1)
您可以创建一个新的传输对象(一个简单的POJO),在其中可以定义要发送到UI的字段。
这样,您将使响应与实际的数据库实体脱钩。因此,从这种意义上讲,您的服务层将根据您所遇到的各种条件检索匹配项并将其存储在列表中。
然后,您可以继续使用Function
或Spring Converter
接口的实现流式传输将它们映射到新的传输对象(前面提到的POJO)的列表。
因此,完成后,您的响应将包含传输对象列表以及要发送到UI的字段。
答案 2 :(得分:1)
服务应仅回答要求的详细信息。 Java's GC
非常适合删除不再需要的小对象。因此,我将继续创建代表所需状态的小对象并将其作为响应传递。例如
return matchesToday.stream().map(MatchInfoResponse::new).collect(Collectors.toList());
答案 3 :(得分:1)
将查询约束为仅要求您需要的属性始终是一个好习惯。
因此,而不是matchInvService.fetchMatchByDate(today);
返回整个Match
例如,您可以实施本机查询。同样,这是一个好主意,而不是返回实体以返回DTO。
使用SqlResultSetMapping批注的一个小示例如下:
MatchDTO match = (MatchDTO) em.createNativeQuery("select m.property1, m.property2, m.property3 from match where m.date=aDate", "MatchDTOMapping").getSingleResult();
拥有
class MatchDTO {
private String property1
private String property2;
private String property3;
//omit other attributes
public MatchDTO(String property1, String property2, String property3) {
this.property1 = property1;
this.property2 = property2;
this.property3 = property3;
}
}
用
注释@SqlResultSetMapping(name="MatchDTOMapping",
classes="@ConstructorResult(
targetClass= MatchDTO.class,
columns = {@ColumnResult(name="property1"),
@ColumnResult(name="property2"),
@ColumnResult(name="property3")}))
Here,您还可以使用本机查询和JPQL查询找到解决方案。
答案 4 :(得分:1)
如果不再使用原始列表。您可以将其设置为null,并且迟早会被回收。我认为考虑内存是没有意义的。