栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

将Spring MVC中仅提及的字段序列化为JSON响应

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

将Spring MVC中仅提及的字段序列化为JSON响应

恕我直言,最简单的方法是使用自省功能动态生成包含选定字段的哈希,然后使用Json序列化该哈希。您只需确定什么是可用字段列表(请参见下文)。

这是两个能够做到这一点的示例函数,第一个获取所有公共字段和公共获取器,第二个获取当前类及其所有父类中的所有已声明字段(包括私有字段):

public Map<String, Object> getPublicMap(Object obj, List<String> names)        throws IllegalAccessException, IllegalArgumentException, InvocationTargetException  {    List<String> gettedFields = new ArrayList<String>();    Map<String, Object> values = new HashMap<String, Object>();    for (Method getter: obj.getClass().getMethods()) {        if (getter.getName().startsWith("get") && (getter.getName().length > 3)) { String name0 = getter.getName().substring(3); String name = name0.substring(0, 1).toLowerCase().concat(name0.substring(1)); gettedFields.add(name); if ((names == null) || names.isEmpty() || names.contains(name)) {     values.put(name, getter.invoke(obj)); }        }    }    for (Field field: obj.getClass().getFields()) {        String name = field.getName();        if ((! gettedFields.contains(name)) && ((names == null) || names.isEmpty() || names.contains(name))) { values.put(name, field.get(obj));        }    }    return values;}public Map<String, Object> getFieldMap(Object obj, List<String> names)        throws IllegalArgumentException, IllegalAccessException  {    Map<String, Object> values = new HashMap<String, Object>();    for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) {        for (Field field : clazz.getDeclaredFields()) { String name = field.getName(); if ((names == null) || names.isEmpty() || names.contains(name)) {     field.setAccessible(true);     values.put(name, field.get(obj)); }        }    }    return values;}

然后,您只需要获取此函数之一的结果(或可以根据需要进行调整的结果),然后使用Jackson对其进行序列化即可。

如果您对域对象进行了自定义编码,则必须在两个不同的地方维护序列化规则:哈希生成和Jackson序列化。在这种情况下,您可以简单地使用Jackson生成完整的类序列化,然后过滤生成的字符串。这是此类过滤器功能的示例:

public String jsonSub(String json, List<String> names) throws IOException {    if ((names == null) || names.isEmpty()) {        return json;    }    ObjectMapper mapper = new ObjectMapper();    Map<String, Object> map = mapper.readValue(json, HashMap.class);    for (String name: map.keySet()) {        if (! names.contains(name)) { map.remove(name);        }    }    return mapper.writevalueAsString(map);}

编辑:集成在Spring MVC

在谈到Web服务和Jackson时,我假设您使用Spring

RestController
ResponseBody
批注以及(在幕后)a
MappingJackson2HttpMessageConverter
。如果您改用Jackson
1,则应为
MappingJacksonHttpMessageConverter


我建议的只是添加一个

HttpMessageConverter
可以利用上述过滤功能之一的新功能,并将实际工作(以及辅助方法)委托给true
MappingJackson2HttpMessageConverter
。在该
write
新转换器的方法中,
fields
由于Spring的帮助,不需要显式的ThreadLocal变量就可以访问最终的请求参数
RequestContextHolder
。那样

  • 您可以清楚地分离角色,而无需在现有控制器上进行任何修改
  • 您没有在Jackson2配置中进行任何修改
  • 您不需要新的ThreadLocal变量,只需在已经绑定到Spring的类中使用Spring类即可,因为它实现了
    HttpMessageConverter

这是这样的消息转换器的示例:

public class JsonConverter implements HttpMessageConverter<Object> {    private static final Logger logger = LoggerFactory.getLogger(JsonConverter.class);    // a real message converter that will respond to ancilliary methods and do the actual work    private HttpMessageConverter<Object> delegate = new MappingJackson2HttpMessageConverter();    // allow configuration of the fields name    private String fieldsParam = "fields";    public void setFieldsParam(String fieldsParam) {        this.fieldsParam = fieldsParam;    }    @Override    public boolean canRead(Class<?> clazz, MediaType mediaType) {        return delegate.canRead(clazz, mediaType);    }    @Override    public boolean canWrite(Class<?> clazz, MediaType mediaType) {        return delegate.canWrite(clazz, mediaType);    }    @Override    public List<MediaType> getSupportedMediaTypes() {        return delegate.getSupportedMediaTypes();    }    @Override    public Object read(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {        return delegate.read(clazz, inputMessage);    }    @Override    public void write(Object t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {        // is there a fields parameter in request        String[] fields = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes())     .getRequest().getParameterValues(fieldsParam);        if (fields != null && fields.length != 0) { // get required field names List<String> names = new ArrayList<String>(); for (String field : fields) {     String[] f_names = field.split("\s*,\s*");     names.addAll(Arrays.asList(f_names)); } // special management for Map ... if (t instanceof Map) {     Map<?, ?> tmap = (Map<?, ?>) t;     Map<String, Object> map = new linkedHashMap<String, Object>();     for (Entry entry : tmap.entrySet()) {         String name = entry.getKey().toString();         if (names.contains(name)) {  map.put(name, entry.getValue());         }     }     t = map; } else {     try {         Map<String, Object> map = getMap(t, names);         t = map;     } catch (Exception ex) {         throw new HttpMessageNotWritableException("Error in field extraction", ex);     } }        }        delegate.write(t, contentType, outputMessage);    }        public static Map<String, Object> getMap(Object obj, List<String> names) throws IllegalArgumentException, IllegalAccessException  {        Map<String, Object> values = new HashMap<String, Object>();        for (Class<?> clazz = obj.getClass(); clazz != Object.class; clazz = clazz.getSuperclass()) { for (Field field : clazz.getDeclaredFields()) {     String name = field.getName();     if (names.contains(name)) {         field.setAccessible(true);         values.put(name, field.get(obj));     } }        }        return values;    }    }

如果您希望转换器具有更多用途,则可以定义一个接口

public interface FieldsFilter {    Map<String, Object> getMap(Object obj, List<String> names) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;}

并为其注入实现。

现在,您必须要求Spring MVC使用该自定义消息控制器。

如果使用XML config,则只需在

<mvc:annotation-driven>
元素中声明它:

<mvc:annotation-driven  >    <mvc:message-converters>        <bean id="jsonConverter" />    </mvc:message-converters></mvc:annotation-driven>

而且,如果您使用Java配置,它几乎就很简单:

@EnableWebMvc@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter {  @Autowired JsonConverter jsonConv;  @Override  public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {    converters.add(jsonConv);    StringHttpMessageConverter stringConverter = new StringHttpMessageConverter();    stringConverter.setWriteAcceptCharset(false);    converters.add(new ByteArrayHttpMessageConverter());    converters.add(stringConverter);    converters.add(new ResourceHttpMessageConverter());    converters.add(new SourceHttpMessageConverter<Source>());    converters.add(new AllEncompassingFormHttpMessageConverter());    converters.add(new MappingJackson2HttpMessageConverter());  }}

但是在这里您必须明确地添加所需的所有默认消息转换器。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/568762.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号