自己动手写一个spring之MVC_4

发布时间:2026/7/16 8:41:03
自己动手写一个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 。