自己动手写一个spring之MVC_4 写在前面源码 。本文看下如何返回对象以及页面到前端。当前生成页面的方式有两种一种是前后端分离的方式也就是后端返回对象到前端第二种方式是后端将生成好的html页面直接返回到浏览器本文就看下这两种情况。1返回对象我们不能真的就返回一个对象而是要将对象转换为某种格式后返回为了标识方法需要转换后返回定义注解ResponseBody/** * 对象-》string返回 的标记注解 */Target({ElementType.METHOD})Retention(RetentionPolicy.RUNTIME)publicinterfaceResponseBody{}为了完成转换定义接口HttpMessageConverter// com.hc.minispring.web.v6_modelview.converter.HttpMessageConverter/** * 负责将object转换为某种数据格式如jsonxml等并写回客户端的接口类 */publicinterfaceHttpMessageConverter{voidwrite(Objectobj,HttpServletResponseresponse)throwsIOException;}提供实现类DefaultHttpMessageConverterpublicclassDefaultHttpMessageConverterimplementsHttpMessageConverter{StringdefaultContentTypetext/json;charsetUTF-8;StringdefaultCharacterEncodingUTF-8;ObjectMapperobjectMapper;publicObjectMappergetObjectMapper(){returnobjectMapper;}publicvoidsetObjectMapper(ObjectMapperobjectMapper){this.objectMapperobjectMapper;}publicDefaultHttpMessageConverter(){}Overridepublicvoidwrite(Objectobj,HttpServletResponseresponse)throwsIOException{response.setContentType(defaultContentType);response.setCharacterEncoding(defaultCharacterEncoding);writeInternal(obj,response);response.flushBuffer();}privatevoidwriteInternal(Objectobj,HttpServletResponseresponse)throwsIOException{StringsJsonStrthis.objectMapper.writeValuesAsString(obj);PrintWriterpwresponse.getWriter();pw.write(sJsonStr);}}ObjectMapper是一个接口负责将对象转换为特定数据类型定义如下/** * 将object转换为特定数据格式的接口 */publicinterfaceObjectMapper{// 专门为日期格式定义的接口voidsetDateFormat(StringdateFormat);// 专门为数字格式定义的接口voidsetDecimalFormat(StringdecimalFormat);StringwriteValuesAsString(Objectobj);}转json实现类/** * 默认实现类 */publicclassDefaultObjectMapperimplementsObjectMapper{StringdateFormatyyyy-MM-dd;DateTimeFormatterdatetimeFormatterDateTimeFormatter.ofPattern(dateFormat);StringdecimalFormat#,##0.00;DecimalFormatdecimalFormatternewDecimalFormat(decimalFormat);// ...OverridepublicStringwriteValuesAsString(Objectobj){StringsJsonStr{;Class?clzobj.getClass();Field[]fieldsclz.getDeclaredFields();for(Fieldfield:fields){// ...if(sJsonStr.equals({)){sField\name\:\strValue\;}else{sField,\name\:\strValue\;}sJsonStrsField;}sJsonStr};returnsJsonStr;}}2返回页面因为返回页面是需要用户进行定制的为了方便用户的使用定义类ModelAndView来维护页面信息以及页面需要的数据信息// com.hc.minispring.web.v6_modelview.ModelAndView/** * 页面以及页面需要的数据通过该类设置页面信息以及页面需要的数据信息 */publicclassModelAndView{// 页面的逻辑名称privateObjectview;privateMapString,ObjectmodelnewHashMap();publicModelAndView(){}// ...}有了页面的逻辑名称还不够还要能够解析出实际的页面htmljsppdf 等等因此定义接口/** * 负责根据用户指定的viewname解析实际页面地址的接口 */publicinterfaceViewResolver{ViewresolveViewName(StringviewName)throwsException;}实现类publicclassInternalResourceViewResolverimplementsViewResolver{privateClass?viewClassnull;privateStringviewClassName;privateStringprefix;privateStringsuffix;privateStringcontentType;// ...protectedViewbuildView(StringviewName)throwsException{Class?viewClassgetViewClass();Viewview(View)viewClass.newInstance();view.setUrl(getPrefix()viewNamegetSuffix());StringcontentTypegetContentType();view.setContentType(contentType);returnview;}}我们还需要视图渲染的组件负责渲染页面到前端也就是这里的View如下/** * 负责渲染页面 */publicinterfaceView{voidrender(MapString,?model,HttpServletRequestrequest,HttpServletResponseresponse)throwsException;// ...}实现类:/** * jsp视图渲染 */publicclassJstlViewimplementsView{publicstaticfinalStringDEFAULT_CONTENT_TYPEtext/html;charsetISO-8859-1;// ...Overridepublicvoidrender(MapString,?model,HttpServletRequestrequest,HttpServletResponseresponse)throwsException{for(EntryString,?e:model.entrySet()){request.setAttribute(e.getKey(),e.getValue());}request.getRequestDispatcher(getUrl()).forward(request,response);}}接着来修改RequestMappingHandlerAdapter执行方法返回ModelView// com.hc.minispring.web.v4_split_dispatcher.RequestMappingHandlerAdapterpublicclassRequestMappingHandlerAdapterimplementsHandlerAdapter{Override// public void handle(HttpServletRequest request, HttpServletResponse response, Object handler)publicModelAndViewhandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler)throwsException{// handleInternal(request, response, (HandlerMethod) handler);returnhandleInternal(request,response,(HandlerMethod)handler);}// private void handleInternal(HttpServletRequest request, HttpServletResponse response,privateModelAndViewhandleInternal(HttpServletRequestrequest,HttpServletResponseresponse,HandlerMethodhandlerMethod)throwsException{try{returninvokeHandlerMethod(request,response,handlerMethod);}catch(Exceptione){e.printStackTrace();}returnnull;}// private void invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {privateModelAndViewinvokeHandlerMethod(HttpServletRequestrequest,HttpServletResponseresponse,HandlerMethodhandlerMethod)throwsException{// ...ObjectreturnObjinvocableMethod.invoke(handlerMethod.getBean(),methodParamObjs);ModelAndViewmavnull;// 如果是设置responsebody注解则返回json格式if(invocableMethod.isAnnotationPresent(ResponseBody.class)){System.out.println(convert to json and return!);this.messageConverter.write(returnObj,response);// return;}elseif(returnObjinstanceofModelAndView){// 在controller方法中直接返回了modelandview说明用户希望展示某个页面mav(ModelAndView)returnObj;returnmav;}elseif(returnObjinstanceofString){//在controller 中直接返回了string说明用户希望按照某种规则返回某个页面mavnewModelAndView();mav.setViewName((String)returnObj);returnmav;}returnmav;// response.getWriter().append(returnObj.toString());}}修改dispatcherservlet支持渲染页面packagecom.hc.minispring.web.v6_modelview;// ...publicclassDispatcherServletextendsHttpServlet{privatestaticfinallongserialVersionUID1L;publicstaticfinalStringWEB_APPLICATION_CONTEXT_ATTRIBUTEDispatcherServlet.class.getName().CONTEXT;privatestaticfinalStringVIEW_RESOLVER_BEAN_NAMEviewResolver;// ...privateViewResolverviewResolver;Overridepublicvoidinit(ServletConfigconfig)throwsServletException{// ...}protectedvoidRefresh(){// ...initViewResolvers(this.webApplicationContext);}// ...protectedvoidinitViewResolvers(WebApplicationContextwac){try{this.viewResolver(ViewResolver)wac.getBean(VIEW_RESOLVER_BEAN_NAME);}catch(BeansExceptione){e.printStackTrace();}}Overrideprotectedvoidservice(HttpServletRequestrequest,HttpServletResponseresponse){request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.webApplicationContext);try{doDispatch(request,response);}catch(Exceptione){// ...}protectedvoiddoDispatch(HttpServletRequestrequest,HttpServletResponseresponse)throwsException{// ...ModelAndViewmavha.handle(processedRequest,response,handlerMethod);this.render(request,response,mav);}protectedvoidrender(HttpServletRequestrequest,HttpServletResponseresponse,ModelAndViewmv)throwsException{if(mvnull){response.getWriter().flush();response.getWriter().close();return;}// 获取逻辑上的目标视图StringsTargetmv.getViewName();// 获取视图需要的数据MapString,ObjectmodelMapmv.getModel();// 通过逻辑的目标视图获取目标视图的渲染器ViewviewresolveViewName(sTarget,modelMap,request);// 执行真正的渲染view.render(modelMap,request,response);}protectedViewresolveViewName(StringviewName,MapString,Objectmodel,HttpServletRequestrequest)throwsException{if(this.viewResolver!null){ViewviewviewResolver.resolveViewName(viewName);if(view!null){returnview;}}returnnull;}}3测试在applicationContext.xml中定义bean?xml version1.0 encodingUTF-8?beansbeanidaserviceclasscom.hc.minispring.web.v5_databind.test.AServiceImpl/beanidwebBindingInitializerclasscom.hc.minispring.web.v5_databind.DateInitializer/beanbeanidmessageConverterclasscom.hc.minispring.web.v6_modelview.converter.DefaultHttpMessageConverterpropertytypecom.hc.minispring.web.v6_modelview.util.ObjectMappernameobjectMapperrefobjectMapper//beanbeanidobjectMapperclasscom.hc.minispring.web.v6_modelview.util.DefaultObjectMapperpropertytypeStringnamedateFormatvalueyyyy/MM/dd/propertytypeStringnamedecimalFormatvalue###.##//beanbeanidhandlerAdapterclasscom.hc.minispring.web.v4_split_dispatcher.RequestMappingHandlerAdapterpropertytypecom.hc.minispring.web.v6_modelview.converter.HttpMessageConverternamemessageConverterrefmessageConverter/!-- property typecom.minis.web.WebBindingInitializer namewebBindingInitializer refwebBindingInitializer/--/beanbeanidviewResolverclasscom.hc.minispring.web.v6_modelview.InternalResourceViewResolverpropertytypeStringnameviewClassNamevaluecom.hc.minispring.web.v6_modelview.JstlView/propertytypeStringnameprefixvalue/jsp//propertytypeStringnamesuffixvalue.jsp//bean/beans定义测试controllerpackagecom.hc.minispring.web.v6_modelview.controller;// ...publicclassHelloController{AutowiredprivateAServiceaservice;RequestMapping(/hello1658)ResponseBody// public String doTest(String name) {publicUserdoTest(/*User user*/){UserusernewUser();user.setAge(45);user.setName(里斯);user.setBirthday(newDate());returnuser;// return aservice.sayHello() -- user;}RequestMapping(/hellojsp)// ResponseBody// public String doTest(String name) {publicStringhellojsp(/*User user*/){returnindex;// return aservice.sayHello() -- user;}}一个返回对象一个返回页面index.jsp,index.jsp如下% page contentTypetext/html;charsetUTF-8 languagejava % html head titleTitle/title /head body index jsp!!!!!!!!!! /body /html启动测试返回对象和页面C:\Users\dell9020curl http://localhost:8080/minispring_Web_exploded/hello1658 {name:里斯,age:45,birthday:2026/07/14} C:\Users\dell9020curl http://localhost:8080/minispring_Web_exploded/hellojsp html head titleTitle/title /head body index jsp!!!!!!!!!! /body /html C:\Users\dell9020写在后面参考文章列表手把手带你写一个 MiniSpring 。

相关新闻

最新新闻

SerenityOS 命令行选项解析指南:getopt 与 getopt_long 用法、返回值与底层实现

SerenityOS 命令行选项解析指南:getopt 与 getopt_long 用法、返回值与底层实现

SerenityOS 命令行选项解析指南:getopt 与 getopt_long 用法、返回值与底层实现 【免费下载链接】serenity The Serenity Operating System 🐞 项目地址: https://gitcode.com/GitHub_Trending/se/serenity 导读 本文以 getopt(3) 手册 为核心&a…

2026/9/23 4:54:42
轻量服务器还是ECS?大促云服务器选购与避坑实战指南

轻量服务器还是ECS?大促云服务器选购与避坑实战指南

每年大促节点,群里永远有人在问同一个问题:“38元的轻量服务器到底怎么抢?为什么我每次点进去都是已售罄?68元直购和99元的ECS我到底选哪个?”作为一个常年帮团队和自己采购云服务器的老用户,我太清楚这种纠…

2026/9/23 8:01:55
为 AI 代理的 Review 动作编写 Cedar 审批门控策略:review-agent-governance 策略编写实战指南

为 AI 代理的 Review 动作编写 Cedar 审批门控策略:review-agent-governance 策略编写实战指南

为 AI 代理的 Review 动作编写 Cedar 审批门控策略:review-agent-governance 策略编写实战指南 【免费下载链接】agents Multi-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity 项目地址:…

2026/9/23 8:02:11
PaddleOCR 手写数学公式识别算法 CAN 实战指南:Counting-Aware Network 训练、评估与推理部署

PaddleOCR 手写数学公式识别算法 CAN 实战指南:Counting-Aware Network 训练、评估与推理部署

PaddleOCR 手写数学公式识别算法 CAN 实战指南:Counting-Aware Network 训练、评估与推理部署 【免费下载链接】PaddleOCR Turn any PDF or image document into structured data for your AI. A powerful, lightweight OCR toolkit that bridges the gap between i…

2026/9/23 8:01:38
Spring源码解析:构造器注入的类型转换与候选匹配机制

Spring源码解析:构造器注入的类型转换与候选匹配机制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/23 8:01:21
openai-agents-python 多模型接入指南:深入解析 AnyLLMModel 适配层与 any-llm 路由

openai-agents-python 多模型接入指南:深入解析 AnyLLMModel 适配层与 any-llm 路由

openai-agents-python 多模型接入指南:深入解析 AnyLLMModel 适配层与 any-llm 路由 【免费下载链接】openai-agents-python A lightweight, powerful framework for multi-agent workflows 项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-pyth…

2026/9/23 8:02:28

日新闻

周新闻