在SpringMVC的上下文中,如何让Web服务提供同一类的不同JSON表示?



我有一个数据类,像这样:

public class Person {
private String name;
private Long code;
// corresponding getters and setters
}

我想编写两个 Web 服务,提供两种不同的 JSON 表示形式。例如,其中一个提供{"name":"foo"}但另一个{"name":"foo", "code":"123"}

作为更复杂的方案,假设 Person 具有引用属性,例如地址。地址也有它自己的属性,我希望我的两个 Web 服务都考虑这个属性,但每个服务都以自己的方式执行此操作。

我的 SpringMVC 视图应该是什么样子的?

请注意,我是SpringMVC的新手。因此,请在您的答案旁边给我一个示例代码。

更新1:几天后,所有答案都促使我在控制器中或通过注释数据类来解决问题。但是我想在视图中执行此操作,而无需更多的Java代码。我可以在 JSP 文件或百里香叶模板甚至 .properties 文件中执行此操作吗?

更新2:我找到了json-taglib。但不知何故,它被排除在新升级之外。有没有类似的解决方案?

你正在使用Spring-MVC所以杰克逊负责JSON序列化和反序列化。

在这种情况下,可以使用@JsonInclude(Include.NON_NULL)在序列化期间忽略 null 字段。

public class Person {
@JsonInclude(Include.NON_NULL)
private String name;
@JsonInclude(Include.NON_NULL)
private Long code;
// corresponding getters and setters
}

如果您的namecodenull则将其排除在输出JSON

因此,如果您将code作为null传递,则输出的JSON将如下所示{"name":"foo"}

当使用Spring MVC创建JSon时,默认情况下,"视图渲染器"是Jackson。没有必要使用JSP或其他视图技术之类的东西。你想做的是告诉杰克逊如何针对给定的情况渲染对象。有多种选择可用,但我建议使用投影。 举个例子:

@RestController
@RequestMapping(value = "person")
public class PersonController {
private final ProjectionFactory projectionFactory;
public PersonController(ProjectionFactory projectionFactory) {
this.projectionFactory = projectionFactory;
}
@GetMapping("...")
public PersonBase getPerson(..., @RequestParam(value = "view", required = false, defaultValue = "base") String view) {
...
if(view.equals("extended")) {
return projectionFactory.createProjection(PersonExtended.class, person);
} else {
return projectionFactory.createProjection(PersonBase.class, person);
}
}
}

public interface PersonBase {
String getName();
}
public interface PersonExtended extends PersonBase {
Long getCode;
}

应用程序的视图层是投影类(然后放在一个包中,如果您愿意,可以放入视图包中(。 控制器可以选择要呈现的视图,也可以使结果动态化,如示例中所示。

您关于如何呈现地址的问题可以通过这样的另一个投影来解决:

public interface PersonWithAddress extends PersonExtended {
AddressProjection getAddress();
}
public interface AddressProjection {
String getStreetName();
String getZipcode();
...
}

您可以使用MappingJacksonValue查找字段的动态过滤。

筛选器允许您序列化满足自定义条件的字段。

你可以在这里查看我的示例代码:

package com.github.tddiaz.jsonresponsefiltering;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import jdk.nashorn.internal.objects.annotations.Getter;
import lombok.Data;
import lombok.NonNull;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@RestController
class Controller {
@GetMapping("/filter")
public ResponseEntity filter() {
final Response response = new Response("value1", "value2", "value3");
//ignore field3; will only return values of field1 and field2
final SimpleBeanPropertyFilter beanPropertyFilter = SimpleBeanPropertyFilter.filterOutAllExcept("field1", "field2");
final FilterProvider filterProvider = new SimpleFilterProvider().addFilter("responseFilter", beanPropertyFilter);
final MappingJacksonValue mappingJacksonValue = new MappingJacksonValue(response);
mappingJacksonValue.setFilters(filterProvider);
return ResponseEntity.ok(mappingJacksonValue);
}
}
@JsonFilter("responseFilter")
@Data
class Response {
@NonNull
private String field1, field2, field3;
}
}

使用投影以不同的方式公开您的 json,如果您需要通过投影向此模型添加更多信息,例如另一个数据库表,请使用资源处理器。

根据您的用例,只需从 jsp/js 页面调用您选择的控制器......例如,假设管理员是用户,然后调用管理员控制器,否则调用用户控制器...这可以使用简单的 if/else 条件来完成...您也可以查看代理设计模式,但这取决于用例

我建议你在前端使用JSON.stringify(value[, replacer[, space]](函数。我在下面举了一个例子。您可以根据特定视图的要求编写自定义函数。

例如。下面的示例忽略空值。在这里,我编写了删除空值的编辑者函数。

该函数有两个输入参数,即键和值。根据要删除或更改的键和值编写逻辑。

var springperson = { "name":"foo","code":null }
console.log(springperson); // person recieved from  spring
function editjson(key, value){
if (value !== null) return value
}
var editperson = JSON.stringify(springperson, editjson); // String representation of person
var personjson=JSON.parse(editperson);  // JSON object representation of person
console.log(personjson); // person as required by the view

如果您有任何问题,请发表评论。

最新更新