Springboot 对返回结果ReturnValueHandler 处理实现原理与实现说明

420 阅读7分钟

若您想要自定义处理 Spring MVC 中方法的返回结果,您可以使用 HandlerMethodReturnValueHandler 接口进行实现。以下是一个示例:

首先,创建一个实现 HandlerMethodReturnValueHandler 接口的自定义返回结果处理器 CustomReturnValueHandler

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.io.IOException;
import java.lang.reflect.Method;

public class CustomReturnValueHandler implements HandlerMethodReturnValueHandler {

    private final HandlerMethodReturnValueHandler delegate;

    public CustomReturnValueHandler(HandlerMethodReturnValueHandler delegate) {
        this.delegate = delegate;
    }

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        // 在这里定义您要处理的返回类型条件
        // 此示例中,我们仅处理返回类型为 long 的方法
        return returnType.getParameterType().equals(long.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
                                  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException {
        // 在这里进行返回结果的自定义处理逻辑
        // 此示例中,我们将 long 类型的返回结果转换为字符串,并进行输出

        // 转换为字符串
        String convertedValue = String.valueOf(returnValue);

        // 获取 HttpServletResponse
        ServletServerHttpResponse response = new ServletServerHttpResponse(webRequest.getNativeResponse(HttpServletResponse.class));

        // 设置响应内容类型和编码
        response.getHeaders().setContentType(MediaType.TEXT_PLAIN);
        response.getHeaders().setCharacterEncoding("UTF-8");

        // 将转换后的结果写入响应
        response.getBody().write(convertedValue.getBytes("UTF-8"));
    }
}

在上述示例中,我们创建了一个 CustomReturnValueHandler 类,实现了 HandlerMethodReturnValueHandler 接口。在 supportsReturnType() 方法中,我们定义了要处理的返回类型条件,此示例中仅处理返回类型为 long 的方法。

handleReturnValue() 方法中,我们进行了自定义的返回结果处理逻辑。这里的示例是将返回结果转换为字符串,并将其写入响应。

接下来,您需要在 Spring MVC 的配置中注册自定义的返回结果处理器。可以通过实现 WebMvcConfigurer 接口来完成:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;

import java.util.ArrayList;
import java.util.List;

@Configuration
@EnableWebMvc
public class CustomWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 查找并替换默认的 RequestMappingHandlerAdapter
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof RequestMappingHandlerAdapter) {
                RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) converter;
                List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(adapter.getReturnValueHandlers());
                replaceReturnValueHandler(handlers);
                adapter.setReturnValueHandlers(handlers);
                break;
            }
        }
    }

    private void replaceReturnValueHandler(List<HandlerMethodReturnValueHandler> handlers) {
        for (int i = 0; i < handlers.size(); i++) {
            HandlerMethodReturnValueHandler handler = handlers.get(i);
            if (handler.getClass().getSimpleName().equals("RequestResponseBodyMethodProcessor")) {
                handlers.set(i, new CustomReturnValueHandler(handler));
                break;
            }
        }
    }
}

在上述示例中,我们创建了一个 CustomWebMvcConfigurer 类,实现了 WebMvcConfigurer 接口,并重写了 extendMessageConverters() 方法。在该方法中,我们查找并替换默认的 RequestMappingHandlerAdapter,将其中的 RequestResponseBodyMethodProcessor 替换为自定义的 CustomReturnValueHandler

请确保将上述类正确配置到您的 Spring MVC 应用程序中,以便自定义处理方法的返回结果。在示例中,我们仅处理返回类型为 long 的方法,并将返回结果转换为字符串进行输出。您可以根据需要修改和扩展自定义的返回结果处理逻辑。

当您想要通过 WebMvcConfigureraddReturnValueHandlers 方法添加自定义的返回对象处理时,可以按照以下示例进行实现:

首先,创建一个实现 HandlerMethodReturnValueHandler 接口的自定义返回对象处理器 CustomReturnValueHandler,并在其中定义您的自定义处理逻辑:

import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;

import java.io.IOException;

public class CustomReturnValueHandler implements HandlerMethodReturnValueHandler {

    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        // 在这里定义您要处理的返回类型条件
        // 例如,处理返回类型为 YourCustomObject 的方法
        return returnType.getParameterType().equals(YourCustomObject.class);
    }

    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType,
                                  ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
            throws IOException {
        // 在这里进行返回对象的自定义处理逻辑
        // 例如,将返回对象转换为 JSON,并写入响应

        // 将返回对象转换为 JSON 字符串
        String jsonString = convertToJson(returnValue);

        // 获取 HttpServletResponse
        ServletServerHttpResponse response = new ServletServerHttpResponse(webRequest.getNativeResponse(HttpServletResponse.class));

        // 设置响应内容类型和编码
        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
        response.getHeaders().setCharacterEncoding("UTF-8");

        // 将 JSON 字符串写入响应
        response.getBody().write(jsonString.getBytes("UTF-8"));
    }

    private String convertToJson(Object object) {
        // 自定义将对象转换为 JSON 的逻辑
        // 例如,使用 Jackson ObjectMapper 进行转换
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Failed to convert object to JSON", e);
        }
    }
}

在上述示例中,我们创建了一个 CustomReturnValueHandler 类,实现了 HandlerMethodReturnValueHandler 接口。在 supportsReturnType() 方法中,我们定义了要处理的返回类型条件,例如 YourCustomObject 类型。在 handleReturnValue() 方法中,我们进行了自定义的返回对象处理逻辑,这里的示例是将返回对象转换为 JSON 字符串,并写入响应。

接下来,在您的 WebMvcConfigurer 配置类中,通过 addReturnValueHandlers() 方法添加自定义的返回对象处理器:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.util.List;

@Configuration
@EnableWebMvc
public class CustomWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
        // 添加自定义的返回对象处理器
        returnValueHandlers.add(new CustomReturnValueHandler());
    }
}

在上述示例中,我们创建了一个 CustomWebMvcConfigurer 类,实现了 WebMvcConfigurer 接口,并重写了 addReturnValueHandlers() 方法。在该方法中,我们通过调用 returnValueHandlers.add(new CustomReturnValueHandler()) 将自定义的返回对象处理器 CustomReturnValueHandler 添加到返回对象处理器列表中。

请确保将上述类正确配置到您的 Spring MVC 应用程序中,以便添加自定义的返回对象处理器。在示例中,我们处理返回类型为 YourCustomObject 的方法,并将返回对象转换为 JSON 字符串进行输出。您可以根据需要修改和扩展自定义的返回对象处理逻辑。

如果您只想添加一个特定的返回结果处理器而不改变整个架构或替换其他默认的处理器,您可以使用WebMvcConfigurerconfigureMessageConverters方法,并添加自定义的HttpMessageConverter来处理返回结果。

以下是一个示例:

import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.io.IOException;
import java.util.List;

@Configuration
@EnableWebMvc
public class CustomWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 创建自定义的 HttpMessageConverter
        CustomHttpMessageConverter customConverter = new CustomHttpMessageConverter();

        // 添加到 converters 列表中
        converters.add(customConverter);
    }

    private static class CustomHttpMessageConverter implements HttpMessageConverter<Object> {

        @Override
        public boolean canRead(Class<?> clazz, MediaType mediaType) {
            // 在这里定义是否支持读取指定类型的对象
            return false; // 例如,不支持读取操作
        }

        @Override
        public boolean canWrite(Class<?> clazz, MediaType mediaType) {
            // 在这里定义是否支持写入指定类型的对象
            // 该示例假设只处理返回类型为 YourCustomObject 的对象
            return YourCustomObject.class.isAssignableFrom(clazz);
        }

        @Override
        public List<MediaType> getSupportedMediaTypes() {
            // 在这里定义支持的媒体类型
            return List.of(MediaType.TEXT_PLAIN);
        }

        @Override
        public Object read(Class<?> clazz, HttpInputMessage inputMessage)
                throws IOException {
            // 在这里实现读取操作的逻辑
            throw new UnsupportedOperationException("Read operation not supported");
        }

        @Override
        public void write(Object object, MediaType contentType, HttpOutputMessage outputMessage)
                throws IOException {
            // 在这里实现写入操作的逻辑
            // 该示例假设将 YourCustomObject 写入为文本
            String text = object.toString();

            ServletServerHttpResponse response = (ServletServerHttpResponse) outputMessage;
            response.getServletResponse().setContentType(contentType.toString());
            response.getServletResponse().getWriter().write(text);
        }
    }
}

在上述示例中,我们创建了一个内部类 CustomHttpMessageConverter,实现了 HttpMessageConverter 接口。在该类中,我们定义了处理返回类型为 YourCustomObject 的对象,并将其写入响应的逻辑。此示例中,我们将其写入为纯文本格式。

然后,我们在 CustomWebMvcConfigurer 类的 configureMessageConverters 方法中添加了自定义的 CustomHttpMessageConverter 实例到 converters 列表中。

请确保将上述类正确配置到您的 Spring MVC 应用程序中,以便添加自定义的返回结果处理器。在示例中,我们处理返回类型为 YourCustomObject 的对象,并将其写入为文本。您可以根据需要修改和扩展自定义的返回结果处理逻辑。

确实,您可以使用拦截器来处理返回结果。通过实现HandlerInterceptor接口并重写postHandle方法,您可以在请求处理完成后对返回结果进行自定义处理。以下是一个示例:

import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CustomInterceptor implements HandlerInterceptor {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 在这里对返回结果进行自定义处理
        // 例如,将返回对象转换为 JSON 并写入响应

        // 获取返回结果
        Object returnValue = modelAndView.getModel().get("returnValue");

        // 将返回对象转换为 JSON 字符串
        String jsonString = convertToJson(returnValue);

        // 设置响应内容类型和编码
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        // 将 JSON 字符串写入响应
        response.getWriter().write(jsonString);
    }

    private String convertToJson(Object object) {
        // 自定义将对象转换为 JSON 的逻辑
        // 例如,使用 Jackson ObjectMapper 进行转换
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            return objectMapper.writeValueAsString(object);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Failed to convert object to JSON", e);
        }
    }
}

在上述示例中,我们创建了一个名为CustomInterceptor的拦截器,并实现了HandlerInterceptor接口。在postHandle方法中,我们可以获取到返回结果,并对其进行自定义处理。在示例中,我们将返回对象转换为JSON字符串,并将其写入响应。

然后,您可以将该拦截器配置到Spring MVC应用程序中。这可以通过添加以下配置类完成:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CustomWebMvcConfigurer implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册自定义拦截器
        registry.addInterceptor(new CustomInterceptor());
    }
}

在上述示例中,我们创建了一个名为CustomWebMvcConfigurer的配置类,并实现了WebMvcConfigurer接口。在addInterceptors方法中,我们将自定义的拦截器CustomInterceptor添加到拦截器注册表中。

请确保将上述类正确配置到您的Spring MVC应用程序中,以便添加自定义的返回结果处理逻辑。在示例中,我们在拦截器中处理返回结果,并将其转换为JSON字符串进行输出。您可以根据需要修改和扩展自定义的返回结果处理逻辑。