写在前面的话
前几篇博文,大致了解了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)
【针对 @requestbody 和 @responsebody 场景】
相关博文
《学会 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
}
观察源码可以看到,这里走的是自定义的返回值处理器,细节就不展开了。
requestresponsebodymethodprocessor
前面源码分析章节,可以看到,参数解析和返回值解析中,都用到了 requestresponsebodymethodprocessor,那它为何可以如此呢?其实看一下类图就明白了。
既实现了handlermethodreturnvaluehandler接口,也实现了handlermethodargumentresolver,看它的匹配方法也可以看出来,就是针对 @requestbody 和 @responsebody 的处理器。
总结陈词
💗 后续会逐步分享企业实际开发中的实战经验,有需要交流的可以联系博主。
发表评论