当前位置: 代码网 > it编程>编程语言>Java > 《学会 SpringMVC 系列 · 返回值处理器》

《学会 SpringMVC 系列 · 返回值处理器》

2024年08月03日 Java 我要评论
前几篇博文,大致了解了SpringMVC请求流程中的入参和出参处理环节,后续的几篇博文,会将流程中涉及的若干关键环节单独拿出来讲解,并结合实战中的运用,帮助领略SpringMVC带来的定制和扩展能力。本篇文章先介绍一下返回值处理器相关内容。代码:study-up#MyHandlerMethodReturnValueHandler逻辑:对添加了自定义注解的接口,包装上一层实体返回。实现步骤:Step1、添加自定义返回值处理器@Override@Override= null) {

csdn.gif

写在前面的话

前几篇博文,大致了解了springmvc请求流程中的入参和出参处理环节,后续的几篇博文,会将流程中涉及的若干关键环节单独拿出来讲解,并结合实战中的运用,帮助领略springmvc带来的定制和扩展能力。
本篇文章先介绍一下返回值处理器相关内容。

学前准备与回顾

本篇为 springmvc 源码分析系列文章,正片开始前,先总结回顾一下全流程。

【一次请求的主链路节点】
dispatcherservlet#dodispatch(入口方法)
dispatcherservlet#gethandler(根据path找到对应的handlerexecutionchain
dispatcherservlet#gethandleradapter(根据handle找到对应的handleradapter
handlerexecutionchain#applyprehandle(触发拦截器的前置逻辑)
abstracthandlermethodadapter#handle(核心逻辑)
handlerexecutionchain#applyposthandle(触发拦截器的后置逻辑)

【核心handle方法的主链路节点】
requestmappinghandleradapter#handleinternal(入口方法)
requestmappinghandleradapter#invokehandlermethod(入口方法2)
servletinvocablehandlermethod#invokeandhandle(入口方法3)
invocablehandlermethod#invokeforrequest(参数和实际执行的所在,3.1)
invocablehandlermethod#getmethodargumentvalues(参数处理,3.1.1)
invocablehandlermethod#doinvoke(实际执行,3.1.2)
handlermethodreturnvaluehandlercomposite#handlereturnvalue(返回处理,3.2)
image.png

【针对 @requestbody 和 @responsebody 场景】
image.png

相关博文
《学会 springmvc 系列 · 基础篇》
《学会 springmvc 系列 · 剖析篇(上)》
《学会 springmvc 系列 · 剖析入参处理》
《学会 springmvc 系列 · 剖析出参处理》
《程序猿入职必会(1) · 搭建拥有数据交互的 springboot 》


springmvc 返回值处理器

技术说明

handlermethodreturnvaluehandler 是 spring mvc 中的一个接口,用于处理控制器方法的返回值。它是处理返回值与 http 响应之间关系的核心机制。通过自定义 handlermethodreturnvaluehandler,可以实现特定返回值类型的处理逻辑,例如格式化输出、包装响应数据等。

接口信息

handlermethodreturnvaluehandler 接口定义了两个主要方法:
boolean supportsreturntype(methodparameter returntype):支持处理给定返回值类型的处理器方法。
void handlereturnvalue(object returnvalue, methodparameter returntype, modelandviewcontainer mavcontainer, nativewebrequest webrequest):处理实际的返回值。
methodparameter:封装方法参数或方法返回值的元数据,包括类型、注解等信息。
modelandviewcontainer:用于存储处理器方法的返回值以及视图名称或 view 对象。
nativewebrequest:封装当前 http 请求和响应。

常见列表

requestresponsebodymethodprocessor – 处理 @responsebody
viewnamemethodreturnvaluehandler – 处理返回 string(视图)
自定义 handlermethodreturnvaluehandler – 包装返回值输出

应用场景

统一响应格式:可以用于统一返回格式,将所有返回值封装为特定的响应对象。
数据包装:在返回数据之前,进行某些特定的包装操作,如添加元数据、状态码等。
权限过滤:在返回之前,检查并过滤掉用户无权限访问的数据。
日志记录:对返回的数据进行记录,用于审计或分析。

自定义示例

代码:study-up#myhandlermethodreturnvaluehandler
逻辑:对添加了自定义注解的接口,包装上一层实体返回。
实现步骤:
step1、添加自定义返回值处理器

public class myhandlermethodreturnvaluehandler implements handlermethodreturnvaluehandler {

    @override
    public boolean supportsreturntype(methodparameter returntype) {
        return (annotatedelementutils.hasannotation(returntype.getcontainingclass(), resultmodelannotation.class) || returntype.hasmethodannotation(resultmodelannotation.class));
    }

    @override
    public void handlereturnvalue(object returnvalue, methodparameter returntype, modelandviewcontainer mavcontainer, nativewebrequest webrequest) throws ioexception, httpmediatypenotacceptableexception, httpmessagenotwritableexception {
        resultmodel<object> resultmodel;

        string message = "";
        operation methodannotation = returntype.getmethodannotation(operation.class);
        if (methodannotation != null) {
            message = methodannotation.summary() + "成功";
        }

        if (returnvalue instanceof resultmodel) {
            resultmodel = (resultmodel<object>) returnvalue;
            if (!resultmodel.issuccess()) {
                resultmodel.setmessage(message + "失败");
            }
        } else {
            resultmodel = resultmodel.success(returnvalue, message);
        }

        mavcontainer.setrequesthandled(true);
        httpservletresponse response = webrequest.getnativeresponse(httpservletresponse.class);
        if (response != null) {
            response.setstatus(httpstatus.ok.value());
            response.setheader("result-model", "true");
            response.setcontenttype(mediatype.application_json_value);
            response.setcharacterencoding("utf-8");
            try (printwriter writer = response.getwriter()) {
                writer.write(json.tojsonstring(resultmodel, serializerfeature.writemapnullvalue));
                writer.flush();

                // 设置请求处理已完成,防止spring继续处理返回值
                mavcontainer.setrequesthandled(true);
            } catch (ioexception ex) {
                ex.printstacktrace();
            }
        }
    }
}

step2、配置返回值处理器

通过自定义 requestmappinghandleradapter 的方式实现效果。

public class customresultmappinghandleradapter extends requestmappinghandleradapter {

    @override
    public void afterpropertiesset() {
        super.afterpropertiesset();
        list<handlermethodreturnvaluehandler> returnvaluehandlers = super.getreturnvaluehandlers();
        myhandlermethodreturnvaluehandler handler = new myhandlermethodreturnvaluehandler();
        list<handlermethodreturnvaluehandler> list = new arraylist<>();
        list.add(handler);
        list.addall(returnvaluehandlers);
        super.setreturnvaluehandlers(list);
    }
}
@configuration
public class webconfig implements webmvcconfigurer {

    @bean
    public webmvcregistrations feignwebregistrations() {
        return new webmvcregistrations() {
            @override
            public requestmappinghandleradapter getrequestmappinghandleradapter() {
                return new customresultmappinghandleradapter();
            }
        };
    }

}

step3、测试效果
正常书写controller,该处理器会包裹resultmodel返回。

@restcontroller
@resultmodelannotation
@tag(name = "教师信息控制层", description = "教师信息")
@requestmapping(value = "/zyteacherinfo")
public class zyteacherinfocontroller extends basecontroller {

    @autowired
    private zyteacherinfoservice zyteacherinfoservice;

    @getmapping("/{id}")
    public zyteacherinfo get(@pathvariable string id) {
        return zyteacherinfoservice.getbyid(id);
    }
}

返回结果如下:

{
  "code": "00000",
  "data": {
    "createdtime": "2024-05-16 20:07:21",
    "modifiedtime": "2024-07-29 14",
    "sortno": null,
    "stuitem": null,
    "teacode": "1",
    "teaconfig": null,
    "teaimg": null,
    "teaname": "张老师",
    "teaphone": null,
    "teatype": null,
    "validflag": "1"
  },
  "error": "",
  "message": "获取教师信息表详细信息成功",
  "success": true
}

观察源码可以看到,这里走的是自定义的返回值处理器,细节就不展开了。
image.png

requestresponsebodymethodprocessor

前面源码分析章节,可以看到,参数解析和返回值解析中,都用到了 requestresponsebodymethodprocessor,那它为何可以如此呢?其实看一下类图就明白了。
既实现了handlermethodreturnvaluehandler接口,也实现了handlermethodargumentresolver,看它的匹配方法也可以看出来,就是针对 @requestbody 和 @responsebody 的处理器。
image.png


总结陈词

💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。

csdn_end.gif

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com