Loading...

本篇文章对 HandlerMethodReturnValueHandler 接口实现了在控制层返回自定义 JSON 格式。

# 引入需要的依赖

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.2.2</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.2</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.2.6.RELEASE</version>
</dependency>

# 自定义实现过滤器

package com.example.demo.filter;
import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.BeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@SuppressWarnings("deprecation")
@JsonFilter("JacksonFilter")
public class JacksonJsonFilter extends FilterProvider {
    Map<Class<?>, Set<String>> includeMap = new HashMap<>();
    Map<Class<?>, Set<String>> excludeMap = new HashMap<>();
    public void include(Class<?> type, String[] field){
        addToMap(includeMap, type, field);
    }
    public void exclude(Class<?> type, String[] field){
        addToMap(excludeMap, type, field);
    }
    private void addToMap(Map<Class<?>, Set<String>> map, Class<?> type, String[] field) {
        Set<String> fieldSet = map.getOrDefault(type, new HashSet<>());
        fieldSet.addAll(Arrays.asList(field));
        map.put(type, fieldSet);
    }
    @Override
    public BeanPropertyFilter findFilter(Object o) {
        throw new UnsupportedOperationException("Access to deprecated filters not supported");
    }
    @Override
    public PropertyFilter findPropertyFilter(Object filterId, Object valueToFilter) {
        return new SimpleBeanPropertyFilter() {
            @Override
            public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer)
                    throws Exception {
                if (apply(pojo.getClass(), writer.getName())) {
                    writer.serializeAsField(pojo, jgen, prov);
                } else if (!jgen.canOmitFields()) {
                    writer.serializeAsOmittedField(pojo, jgen, prov);
                }
            }
        };
    }
    public boolean apply(Class<?> type, String name) {
        Set<String> includeFields = includeMap.get(type);
        Set<String> filterFields = excludeMap.get(type);
        if (includeFields != null && includeFields.contains(name)) {
            return true;
        } else if (filterFields != null && !filterFields.contains(name)) {
            return true;
        } else if (includeFields == null && filterFields == null) {
            return true;
        }
        return false;
    }
}

# 自定义返回 JSON 注解

JsonReturn

package com.example.demo.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(JsonReturns.class) // 让方法支持多重 @JSON 注解
public @interface JsonReturn {
    Class<?> type();
    String[] include() default {};
    String[] exclude() default {};
}

JsonReturns

package com.example.demo.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface JsonReturns {
    JsonReturn[] value();
}

# 封装 JSON 转换

我们来封装一个类,用作解析注解以及设置过滤器的

JsonReturnValueSerializer

package com.example.demo.serializer;
import com.example.demo.annotations.JsonReturn;
import com.example.demo.filter.JacksonJsonFilter;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class JsonReturnValueSerializer {
    ObjectMapper objectMapper = null;
    JacksonJsonFilter jacksonJsonFilter = new JacksonJsonFilter();
    public JsonReturnValueSerializer(){
        objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
    }
    public void filter(Class<?> clazz, String[] include, String[] exclude){
        if (clazz == null){
            return;
        }
        if (include != null && include.length > 0){
            jacksonJsonFilter.include(clazz, include);
        }
        if (exclude != null && exclude.length > 0){
            jacksonJsonFilter.exclude(clazz, exclude);
        }
        objectMapper.addMixIn(clazz, jacksonJsonFilter.getClass());
    }
    public void filter(JsonReturn json) {
        this.filter(json.type(), json.include(), json.exclude());
    }
    public String toJson(Object object) throws JsonProcessingException {
        objectMapper.setFilterProvider(jacksonJsonFilter);
        return objectMapper.writeValueAsString(object);
    }
}

# 实现 HandlerMethodReturnValueHandler

HandlerMethodReturnValueHandler 接口 Spring MVC 用于处理请求返回值 。 看一下这个接口的定义和描述,接口有两个方法 supportsReturnType 用来判断 处理类 是否支持当前请求, handleReturnValue 就是具体返回逻辑的实现。

package com.example.demo.handle;
import com.example.demo.annotations.JsonReturn;
import com.example.demo.annotations.JsonReturns;
import com.example.demo.serializer.JsonReturnValueSerializer;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.util.Arrays;
public class JsonReturnValueHandler implements HandlerMethodReturnValueHandler {
    private HandlerMethodReturnValueHandler target;
    public JsonReturnValueHandler(HandlerMethodReturnValueHandler target) {
        this.target = target;
    }
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        return target.supportsReturnType(returnType);
    }
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest) throws Exception {
        // 设置这个就是最终的处理类了,处理完不再去找下一个类进行处理
        modelAndViewContainer.setRequestHandled(true);
        // 获得注解并执行 filter 方法 最后返回
        HttpServletResponse response = nativeWebRequest.getNativeResponse(HttpServletResponse.class);
        Annotation[] annotations = methodParameter.getMethodAnnotations();
        JsonReturnValueSerializer jsonReturnValueSerializer = new JsonReturnValueSerializer();
        Arrays.asList(annotations).forEach(annotation -> {
            if (annotation instanceof JsonReturn){
                JsonReturn jsonReturn = (JsonReturn) annotation;
                jsonReturnValueSerializer.filter(jsonReturn);
            }else if (annotation instanceof JsonReturns){
                JsonReturns jsonReturns = (JsonReturns) annotation;
                Arrays.asList(jsonReturns.value()).forEach(jsonReturnValueSerializer::filter);
            }
        });
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        String json = jsonReturnValueSerializer.toJson(returnValue);
        target.handleReturnValue(json, methodParameter, modelAndViewContainer, nativeWebRequest);
    }
}

# 初始化 Bean

InitializingReturnValueHandler

package com.example.demo.init;
import com.example.demo.handle.JsonReturnValueHandler;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor;
import java.util.ArrayList;
import java.util.List;
public class InitializingReturnValueHandler implements InitializingBean {
    @Autowired
    private RequestMappingHandlerAdapter adapter;
    @Override
    public void afterPropertiesSet() throws Exception {
        List<HandlerMethodReturnValueHandler> returnValueHandlers = adapter.getReturnValueHandlers();
        List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(returnValueHandlers);
        this.decorateHandles(handlers);
        adapter.setReturnValueHandlers(handlers);
    }
    private void decorateHandles(List<HandlerMethodReturnValueHandler> handlers) {
        for (HandlerMethodReturnValueHandler handler : handlers){
            if (handler instanceof RequestResponseBodyMethodProcessor){
                JsonReturnValueHandler jsonReturnValueHandler = new JsonReturnValueHandler((RequestResponseBodyMethodProcessor) handler);
                int index = handlers.indexOf(handler);
                handlers.set(index, jsonReturnValueHandler);
                break;
            }
        }
    }
}

# 配置

JsonReturnConfig

package com.example.demo.config;
import com.example.demo.init.InitializingReturnValueHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JsonReturnConfig {
    @Bean
    public InitializingReturnValueHandler init(){
        return new InitializingReturnValueHandler();
    }
}

# 测试

# 定义实体

DemoEntity

package com.example.demo.entity;
import java.io.Serializable;
import java.math.BigDecimal;
public class DemoEntity implements Serializable {
    private Refer refer;
    private BigDecimal price;
    private String categories;
    public BigDecimal getPrice() {
        return price;
    }
    public void setPrice(BigDecimal price) {
        this.price = price;
    }
    public String getCategories() {
        return categories;
    }
    public void setCategories(String categories) {
        this.categories = categories;
    }
    public Refer getRefer() {
        return refer;
    }
    public void setRefer(Refer refer) {
        this.refer = refer;
    }
    @Override
    public String toString() {
        return "DemoEntity{" +
                "refer=" + refer +
                ", price=" + price +
                ", categories='" + categories + '\'' +
                '}';
    }
}

Refer

package com.example.demo.entity;
public class Refer {
    private String id;
    private String code;
    private String name;
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Refer{" +
                "id='" + id + '\'' +
                ", code='" + code + '\'' +
                ", name='" + name + '\'' +
                '}';
    }
}

# 定义控制层

DemoController

package com.example.demo.controller;
import com.example.demo.annotations.JsonReturn;
import com.example.demo.entity.DemoEntity;
import com.example.demo.entity.Refer;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.math.BigDecimal;
import java.util.UUID;
@RestController
public class DemoController {
    @GetMapping("/queryAll")
    public DemoEntity queryAll(){
        return initDemoEntity();
    }
    @JsonReturn(type = DemoEntity.class, include = {"categories", "refer", "price"})
    @JsonReturn(type = Refer.class, exclude = {"id"})
    @GetMapping("/demo")
    public DemoEntity demo(){
        return initDemoEntity();
    }
    private DemoEntity initDemoEntity(){
        DemoEntity demoEntity = new DemoEntity();
        Refer refer = new Refer();
        refer.setId(UUID.randomUUID().toString());
        refer.setCode("DEMO");
        refer.setName("测试");
        demoEntity.setRefer(refer);
        demoEntity.setPrice(new BigDecimal("10.00"));
        demoEntity.setCategories("demo分类");
        return demoEntity;
    }
}

# 请求

localhost:8080/queryAll

页面返回结果

{"refer":{"id":"f3ca1a6a-b5e3-49b9-94aa-38a0e2160e6e","code":"DEMO","name":"测试"},"price":10.00,"categories":"demo分类"}

localhost:8080/demo

页面返回结果

{"refer":{"code":"DEMO","name":"测试"},"price":10.00,"categories":"demo分类"}
更新于

请我喝[茶]~( ̄▽ ̄)~*

七音 微信支付

微信支付

七音 支付宝

支付宝