JsonConfig的jsonConfig.setExcludes的用法

本文介绍如何使用JsonConfig的setExcludes方法过滤对象中的一对多关系,避免在序列化过程中出现LazyInitializationException异常。

JsonConfig的jsonConfig.setExcludes的用法

之前写一个小东西,当用JSONArray.fromObject()方法转一个对象集合时,因为对象中存在一对多的关系,一直抛出异常

严重: Error executing FreeMarker template
FreeMarker template error:
Java method “org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int)” threw an exception when invoked on net.sf.json.JSONException object “net.sf.json.JSONException: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.zzuli.app.domain.User.positions, no session or session was closed”; see cause exception in the Java stack trace.


FTL stack trace (“~” means nesting-related):

- Failed at: ${msg[0]?html} [in template “org/apache/struts2/dispatcher/error.ftl” at line 68, column 29]

Java stack trace (for programmers):

freemarker.core._TemplateModelException: [… Exception message was already printed; see it above …]
at freemarker.ext.beans._MethodUtil.newInvocationTemplateModelException(_MethodUtil.java:311)
at freemarker.ext.beans._MethodUtil.newInvocationTemplateModelException(_MethodUtil.java:275)
at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:80)
at freemarker.ext.beans.SimpleMethodModel.get(SimpleMethodModel.java:86)
at freemarker.core.DynamicKeyName.dealWithNumericalKey(DynamicKeyName.java:104)
at freemarker.core.DynamicKeyName._eval(DynamicKeyName.java:69)
at freemarker.core.Expression.eval(Expression.java:78)
at freemarker.core.Expression.evalAndCoerceToString(Expression.java:82)
at freemarker.core.BuiltInForString._eval(BuiltInForString.java:26)
at freemarker.core.Expression.eval(Expression.java:78)
at freemarker.core.Expression.evalAndCoerceToString(Expression.java:82)
at freemarker.core.DollarVariable.accept(DollarVariable.java:40)
at freemarker.core.Environment.visit(Environment.java:312)
at freemarker.core.MixedContent.accept(MixedContent.java:62)
at freemarker.core.Environment.visitByHiddingParent(Environment.java:333)
at freemarker.core.IfBlock.accept(IfBlock.java:48)
at freemarker.core.Environment.visitByHiddingParent(Environment.java:333)
at freemarker.core.IteratorBlockContext.runLoop(IteratorBlock.java:159)atfreemarker.core.Environment.visitIteratorBlock(Environment.java:559)atfreemarker.core.IteratorBlock.accept(IteratorBlock.java:67)atfreemarker.core.Environment.visit(Environment.java:312)atfreemarker.core.MixedContent.accept(MixedContent.java:62)atfreemarker.core.Environment.visitByHiddingParent(Environment.java:333)atfreemarker.core.IfBlock.accept(IfBlock.java:48)atfreemarker.core.Environment.visit(Environment.java:312)atfreemarker.core.MixedContent.accept(MixedContent.java:62)atfreemarker.core.Environment.visit(Environment.java:312)atfreemarker.core.Environment.process(Environment.java:290)atfreemarker.template.Template.process(Template.java:312)atorg.apache.struts2.dispatcher.DefaultDispatcherErrorHandler.handleErrorInDevMode(DefaultDispatcherErrorHandler.java:99)atorg.apache.struts2.dispatcher.DefaultDispatcherErrorHandler.handleError(DefaultDispatcherErrorHandler.java:57)atorg.apache.struts2.dispatcher.Dispatcher.sendError(Dispatcher.java:909)atorg.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:576)atorg.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)atorg.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)atorg.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)atorg.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)atorg.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:230)atorg.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)atorg.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)atorg.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:104)atorg.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)atorg.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:261)atorg.apache.coyote.http11.Http11Processor.process(Http11Processor.java:844)atorg.apache.coyote.http11.Http11ProtocolHttp11ConnectionHandler.process(Http11Protocol.java:581)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.NullPointerException
at freemarker.ext.beans.SimpleMethod.unwrapArguments(SimpleMethod.java:53)
at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:72)
… 44 more

然后通过询问别人,知道了JsonConfig的jsonConfig.setExcludes()这个方法,简单的说,这个就是过滤掉不需要的属性,因此就可以用这个方法过滤掉对象中存在的一对多的关系

List userList = userService.findAll();
JsonConfig jsonConfig = new JsonConfig();
jsonConfig.setExcludes(new String[]{“area”});
JSON json = JSONSerializer.toJSON(userList, jsonConfig);

setExcludes()里面的集合,就是你想要过滤掉的属性的名字。

<think>根据用户提供的代码片段,这是一个Spring Boot控制器方法,用于读取上传的PPT文件和一个期望配置的字符串,然后进行验证。方法返回验证失败的结果列表。用户希望:如果返回的列表为空,则表示所有验证都通过;如果有数据,则返回失败的数据。 用户代码中已经实现了: 1. 解析expectedConfig字符串(可能是管道分隔的数据或JSON字符串)为JsonNode。 2. 调用`springAi.validateImagePrecisely`方法进行验证,得到验证结果列表。 3. 过滤出无效(验证失败)的结果,放入failedResults列表并返回。 因此,当前逻辑已经满足用户的需求:返回失败的结果列表,空列表表示完全符合。 但是,用户可能担心返回空列表时客户端如何知道是完全符合。实际上,在HTTP响应中,返回一个空数组([])就表示没有失败的结果,即完全符合。 为了更清晰,我们可以考虑在返回结果中增加一个状态字段,但用户现有的代码返回的是`List<ValidationResult>`,所以如果不想改变返回类型,保持当前逻辑即可。 如果用户希望返回一个包含状态和失败列表的对象,可以定义一个包含两个字段的响应对象,例如: - boolean success (当failedResults为空时为true) - List<ValidationResult> failedResults 但根据用户当前代码,他直接返回了失败列表,所以客户端可以通过判断列表是否为空来确定是否全部通过。 因此,当前代码逻辑正确,无需修改。 但是,我们注意到方法名为`readPPT`,而实际功能是验证,建议方法名改为`validatePPT`更合适。 另外,代码中使用了`springAi`来验证,具体验证逻辑在`validateImagePrecisely`中,我们无法看到,但这不是当前问题关心的。 所以,针对用户的问题,我们确认代码逻辑已经满足要求。 不过,我们可以对代码进行一些优化和重构: 1. 使用Java 8 Stream API简化过滤操作。 2. 添加日志记录。 3. 方法重命名。 修改后的代码示例: ```java @PostMapping("/validatePPT") public List<ValidationResult> validatePPT( @RequestPart("file") MultipartFile file, @RequestPart("expectedConfig") String expectedConfig) throws Exception { JsonNode jsonConfig; if (param.isPipeSeparatedData(expectedConfig)) { jsonConfig = param.parsePipeSeparatedDataToJson(expectedConfig); } else { jsonConfig = objectMapper.readTree(expectedConfig); } List<ValidationResult> validationResults = springAi.validateImagePrecisely(file, jsonConfig); // 使用Stream过滤出验证失败的结果 return validationResults.stream() .filter(result -> !result.isValid()) .collect(Collectors.toList()); } ``` 这样,代码更简洁。 如果用户希望返回一个包含更多信息的响应对象,可以定义: ```java public class ValidationResponse { private boolean success; private List<ValidationResult> failedResults; // 构造方法、getter和setter } ``` 然后修改方法返回类型和返回语句: ```java @PostMapping("/validatePPT") public ValidationResponse validatePPT( @RequestPart("file") MultipartFile file, @RequestPart("expectedConfig") String expectedConfig) throws Exception { // ... 解析配置和验证的代码同上 List<ValidationResult> failedResults = validationResults.stream() .filter(result -> !result.isValid()) .collect(Collectors.toList()); ValidationResponse response = new ValidationResponse(); response.setSuccess(failedResults.isEmpty()); response.setFailedResults(failedResults); return response; } ``` 但是,用户没有要求改变返回结构,所以第一种方式(直接返回失败列表)是符合他描述的。 综上所述,用户现有的代码逻辑正确,但我们可以提供更简洁的写法(使用Stream)并建议更名方法。 因此,我们给出优化后的代码(保持原返回类型)作为答案。 注意:由于用户代码片段中使用了`param`和`objectMapper`,这些应该是注入的依赖,我们保持不变。 最终答案:用户代码逻辑正确,但可以优化。</think>根据您的需求,您的方法逻辑已经基本正确:当验证全部通过时返回空列表(表示完全符合),验证失败时返回失败结果列表。以下是优化后的代码实现: ```java public List<ValidationResult> validatePPT( @RequestPart("file") MultipartFile file, @RequestPart("expectedConfig") String expectedConfig) throws Exception { // 解析配置数据 JsonNode jsonConfig = param.isPipeSeparatedData(expectedConfig) ? param.parsePipeSeparatedDataToJson(expectedConfig) : objectMapper.readTree(expectedConfig); // 执行验证 List<ValidationResult> validationResults = springAi.validateImagePrecisely(file, jsonConfig); // 使用Stream过滤失败结果 return validationResults.stream() .filter(result -> !result.isValid()) .collect(Collectors.toList()); } ``` ### 关键优化点: 1. **三元表达式简化**:使用三元运算符简化配置解析逻辑 2. **Stream API**:使用Java 8 Stream进行过滤和收集,代码更简洁 3. **方法名优化**:将方法名从`readPPT`改为`validatePPT`更符合实际功能 4. **返回空列表表示成功**:完全符合预期时返回空列表`[]` ### 客户端处理示例: ```java // 调用服务 List<ValidationResult> results = pptService.validatePPT(file, config); if (results.isEmpty()) { System.out.println("所有验证通过,完全符合预期!"); } else { System.out.println("以下验证失败:"); results.forEach(result -> System.out.println("- " + result.getField() + ": " + result.getMessage()) ); } ``` ### 建议增强功能: 1. **添加详细日志**:记录验证请求参数和结果 2. **异常处理**:添加更具体的异常类型处理 3. **性能监控**:添加执行时间记录 4. **结果排序**:按验证失败严重程度排序结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值