手写SpringMVC之调度器DispatcherServlet

DispatcherServlet:分发、调度

根据上一节,已经实现了将controller的方法添加到容器中,而DispatcherServlet的作用就是接收来自客户端的请求,然后通过URI的组合,来找到对应的@RequestMapping注解的方法,调用对应的方法,最后返回响应

image-20240627203051007

第一步:获取URI,根据URI来匹配对应的BeanDefinition

String requestURI = req.getRequestURI();Map<String, BeanDefinition<?>> maps = BeanContainer.getMaps();//通过匹配URI来找到对应的BeanDefinition
BeanDefinition<?> beanDefinition = maps.get(requestURI);
if (beanDefinition == null) {throw new FrameWorkException(ResponseCode.REQUEST_MAPPING_PATH_EXCEPTION.getCode(), ResponseCode.REQUEST_MAPPING_PATH_EXCEPTION.getMessage());
}

第二步:获取容器中的BeanDefinition的MethodDefinition和ParameterDefinition

//获取对应的controller类对象
Object t = beanDefinition.getT();
MethodDefinition methodDefinition = beanDefinition.getMethodDefinition();
//获取方法对象
Method method = methodDefinition.getMethod();
method.setAccessible(true);
//获取参数列表
List<ParameterDefinition> parameterDefinitions = methodDefinition.getParameters();

第三步:调用对应的方法

Object[] args;
Model model = new Model();try {args = handlerParameterArgs(parameterDefinitions, req, resp, model);//调用Controller层里某个方法Object returnVal = method.invoke(t, args);if (returnVal != null) {//处理返回值handlerReturnVal(methodDefinition, returnVal, req, resp, model);}
} catch (Exception e) {System.out.println(Arrays.toString(e.getStackTrace()));;
}
handlerParameterArgs:将调用的方法的参数列表与请求数据适配
/*** 集中处理参数的函数,通过判断参数的类型,对不同类型的参数进行处理,包括* 1. 常见参数类型:八大基本数据类型及其包装类 + String* 2. 数组类型* 3. HttpServletRequest 类型* 4. httpServletResponse 类型* 5. List<?> 类型* 6. 自定义类型** @param parameterDefinitions 参数描述对象列表(从controller的方法下抽取出来的)* @param req                  请求对象* @param resp                 响应对象* @param model                数据体(应该是,里面是Map,key为数据名,value为数据体,最后通过装载到request对象转发出去)* @return 参数列表 Object[] args*/
public Object[] handlerParameterArgs(List<ParameterDefinition> parameterDefinitions, HttpServletRequest req, HttpServletResponse resp, Model model) throws ClassNotFoundException {if (parameterDefinitions == null) {return null;}//实际参数的列表Object[] args = new Object[parameterDefinitions.size()];//将请求中的参数添加到args中for (ParameterDefinition parameterDefinition : parameterDefinitions) {String name = parameterDefinition.getParameterName();//参数名Class<?> type = parameterDefinition.getType();//参数类型int index = parameterDefinition.getIndex();//参数下标if (judgeTypeIsJavaOrNot(type)) {//常见数据类型handlerJavaType(req, name, type, args, index);} else if (type == HttpServletRequest.class) {//请求类型args[index] = req;} else if (type == HttpServletResponse.class) {//相应类型args[index] = resp;} else if (type == String[].class) {//数组类型String[] parameterValues = req.getParameterValues(name);args[index] = parameterValues;} else if (type == List.class) {//集合类型handlerListType(parameterDefinition, req, args, index);} else if (type == Model.class) {//Model类型args[index] = model;} else {//自定义类型handlerOtherType(parameterDefinition, req, args, index);}}return args;
}
judgeTypeIsJavaOrNot:判断方法参数是否是常见数据类型

常见参数类型:八大基本数据类型及其包装类 + String

private static final Class<?>[] COMMON_CLASSES = new Class[]{byte.class, short.class, int.class, long.class, float.class, double.class, char.class,Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Character.class,String.class};
/*** 判断参数的类型是不是常见类型 [COMMON_CLASSES]** @param type 参数类型* @return 是否为常见类型*/
public boolean judgeTypeIsJavaOrNot(Class<?> type) {for (Class<?> clazz : COMMON_CLASSES) {if (type == clazz) {return true;}}return false;
}
handlerJavaType:处理常见参数
/*** 处理不同的常见数据类型,将其转化为对应的数据并添加到参数列表对应的位置** @param req   请求对象* @param name  字段名* @param type  字段类型* @param args  参数列表* @param index 参数在方法中的下标*/
public void handlerJavaType(HttpServletRequest req, String name, Class<?> type, Object[] args, int index) {String parameter = req.getParameter(name);if (type == byte.class || type == Byte.class) {args[index] = Byte.parseByte(parameter);} else if (type == short.class || type == Short.class) {args[index] = Short.parseShort(parameter);} else if (type == int.class || type == Integer.class) {args[index] = Integer.parseInt(parameter);} else if (type == long.class || type == Long.class) {args[index] = Long.parseLong(parameter);} else if (type == float.class || type == Float.class) {args[index] = Float.parseFloat(parameter);} else if (type == double.class || type == Double.class) {args[index] = Double.parseDouble(parameter);} else if (type == char.class || type == Character.class) {args[index] = parameter.toCharArray()[0];} else if (type == boolean.class || type == Boolean.class) {args[index] = Boolean.parseBoolean(parameter);}if (type == String.class) {args[index] = parameter;}
}
handlerListType:处理List参数
/*** 处理方法的参数是集合类型的方法,如果参数是List集合,那么要将List中的泛型取出来并设置对应的属性* 最后将泛型对应的对象添加到List中,再将List添加到参数列表中** @param parameterDefinition 参数描述对象(包含泛型的类型)* @param req                 请求对象* @param args                参数列表* @param index               参数对应的下标*/
public void handlerListType(ParameterDefinition parameterDefinition, HttpServletRequest req, Object[] args, int index) throws ClassNotFoundException {Type[] types = parameterDefinition.getTypes();//参数的泛型列表Type genericType = types[0];//泛型列表String typeName = genericType.getTypeName();//泛型的名称 cn.cnmd.pojo.UserList<Object> list = new ArrayList<>();Map<String, String[]> parameterMap = req.getParameterMap();Set<Map.Entry<String, String[]>> entries = parameterMap.entrySet();for (Map.Entry<String, String[]> entry : entries) {String key = entry.getKey();String fieldValue = entry.getValue()[0];int i = Integer.parseInt(key.substring(key.indexOf("[") + 1, key.indexOf("]")));String fieldName = key.substring(key.indexOf(".") + 1);Class<?> aClass = Class.forName(typeName);Object o = null;try {o = list.get(i);} catch (IndexOutOfBoundsException e) {//该集合下标上没有元素try {o = aClass.newInstance();//创建对象list.add(o);} catch (InstantiationException | IllegalAccessException ex) {throw new RuntimeException(ex);}}try {BeanUtils.setProperty(o, fieldName, fieldValue);} catch (IllegalAccessException | InvocationTargetException e) {throw new RuntimeException(e);}}args[index] = list;
}
handlerOtherType:处理自定义参数
/*** 处理自定义类型** @param parameterDefinition 参数描述对象* @param req                 请求对象* @param args                参数列表* @param index               参数下标*/
public void handlerOtherType(ParameterDefinition parameterDefinition, HttpServletRequest req, Object[] args, int index) {try {Object obj;//如果参数上带有@RequestBody注解则会将JSON字符串转化为对象if (parameterDefinition.isRequestBodyHasOrNot()) {BufferedReader reader = req.getReader();StringBuffer sb = new StringBuffer();char[] cs = new char[1024];int len;while ((len = reader.read(cs)) != -1) {sb.append(cs, 0, len);}//String --> Objectobj = objectMapper.readValue(sb.toString(), parameterDefinition.getType());} else { //如果不带@RequestBody注解,则正常当作自定义对象处理obj = parameterDefinition.getType().newInstance();Map<String, String[]> parameterMap = req.getParameterMap();BeanUtils.populate(obj, parameterMap);}args[index] = obj;} catch (InstantiationException | IllegalAccessException | InvocationTargetException | IOException e) {throw new RuntimeException(e);}
}
handlerRequestVal:将Model中的k-v添加到request请求体中
/*** 将model数据对象装载到request对象中** @param request 请求体对象* @param map     model数据对象的map(k-v存储了需要传递给前端的数据)*/
public void handlerRequestVal(HttpServletRequest request, Map<String, Object> map) {Set<Map.Entry<String, Object>> entries = map.entrySet();for (Map.Entry<String, Object> entry : entries) {String key = entry.getKey();Object value = entry.getValue();request.setAttribute(key, value);}
}
handlerReturnVal:返回响应的总调度(按照方法的返回类型)
  1. 如果是String类型,说明返回值是一个URI,ps:‘/user/index.jsp’,就将数据加载到request对象中,跳转到该页面
  2. 如果是ModelAndView类型,说明返回值是一个ModelAndView对象[ Model数据体对象 + URI],再将数据加载到request对象中,通过ModelANdView.getViewName()跳转
  3. 如果是JSON数据[方法上带有@ResponseBody注解],就直接将数据发送到前端
/*** 处理返回值的函数,通过判断URI调用对应的方法的返回值类型,选择不同返回逻辑* 1.如果是String类型,说明返回值是一个URI,ps:'/user/index.jsp',就将数据加载到request对象中,跳转到该页面* 2.如果是ModelAndView类型,说明返回值是一个ModelAndView对象[ Model数据体对象 + URI],再将数据加载到request对象中,通过ModelANdView.getViewName()跳转* 3.如果是JSON数据[方法上带有@ResponseBody注解],就直接将数据发送到前端** @param methodDefinition 方法描述对象* @param returnVal        调用方法的返回值对象* @param request          请求体对象* @param response         响应体对象* @param model            数据体对象*/
public void handlerReturnVal(MethodDefinition methodDefinition, Object returnVal, HttpServletRequest request, HttpServletResponse response, Model model) throws ServletException, IOException {//如果返回的是一个String, 代表直接跳转,ps:'user/login2.action'if (returnVal.getClass() == String.class) {handlerRequestVal(request, model.getMap());jumpPage(returnVal, request, response);//如果返回的是ModelAndView对象,那么代表跳转的地址作为属性被注入到ModelAndView对象中,通过modelAndView.getViewName()跳转} else if (returnVal.getClass() == ModelAndView.class) {ModelAndView modelAndView = (ModelAndView) returnVal;handlerRequestVal(request, modelAndView.getMap());jumpPage(modelAndView.getViewName(), request, response);//如果这个方法上有@REsponseBody注解,则直接将returnVal转化为JSON字符串传出} else if (methodDefinition.isResponseBodyHasOrNot()) {String jsonStr = objectMapper.writeValueAsString(returnVal);sendResponse(jsonStr, response);}}
jumpPage:跳转页面
/*** 页面跳转函数** @param uri      需要跳转的URI* @param request  请求体对象(里面携带了从model装载的数据)* @param response 相应体对象*/
public void jumpPage(Object uri, HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {String view = (String) uri;request.getRequestDispatcher(view).forward(request, response);
}
sendResponse:直接返回响应
/*** 向前端发送JSON数据* @param jsonStr JSON字符串* @param response 相应提对象*/
public void sendResponse( String jsonStr,HttpServletResponse response) throws IOException {response.getWriter().write(jsonStr);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/36486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 剑指 Offer 40

// void help(int[] a,int l,int r,int k){ // if(k0) return; // if(r-l1 < k){ // for(int il;i<r;i){ // ans[cnt] a[i]; // } // return; // } // // 快排的基准值 // int base a[l]; // int i l, j r; // while(i<j){ // while(i<j &&…

极验行为式验证码适配HarmonyOS 鸿蒙SDK下载

现阶段&#xff0c;越来越多的开发者正在积极加入鸿蒙生态系统。随着更多开发者的参与&#xff0c;早在去年9月&#xff0c;极验就成为首批拥有鸿蒙NEXT内测版本和手机系统测试机会的验证码供应商。 为了提高各开发者及企业客户集成鸿蒙版本行为验4.0的效率&#xff0c;方便大家…

Nature推荐的三种ChatGPT论文写作指令(含PDF下载)

1. 润色学术论文 ChatGPT学术润色指令&#xff1a; “I’m writing a paper on [topic]for a leading [discipline] academic journal. WhatItried to say in the following section is [specific point]. Please rephrase itfor clarity, coherence and conciseness, ensuri…

C# 异步编程详解(Task,async/await)

文章目录 1.什么是异步2.Task 产生背景3.Thread(线程) 和 Task(异步)的区别3.1 几个名词3.2 Thread 与 Task 的区别 4.Task API4.1 创建和启动任务4.2 Task 等待、延续和组合4.3 task.Result4.4 Task.Delay() 和 Thread.Sleep() 区别 5.CancellationToken 和 CancellationToken…

最年轻获奖者诞生!一文带你了解历届国家最高科学技术奖获奖人

内容来源&#xff1a;量子前哨&#xff08;ID&#xff1a;Qforepost&#xff09; 文丨浪味仙 排版丨沛贤 深度好文&#xff1a;4000字丨15分钟阅读 作为国家层面面向科学、技术领域的最高级别奖励&#xff0c;国家最高科学技术奖于 2000 年由国务院设立&#xff0c;每年评选…

解锁分布式云多集群统一监控的云上最佳实践

作者&#xff1a;在峰 引言 在当今数字化转型加速的时代&#xff0c;随着混合云、多云多集群环境等技术被众多企业广泛应用&#xff0c;分布式云架构已成为众多企业和组织推动业务创新、实现弹性扩展的首选&#xff0c;分布式云容器平台 ACK One&#xff08;Distributed Clou…

OpenGL3.3_C++_Windows(21)

抗锯齿 遇到模型边缘有锯齿&#xff1a;光栅器将顶点数据转化为片段的方式有关 抗锯齿&#xff1a;产生更平滑的边缘SSAA超采样抗锯齿&#xff1a;使用比正常分辨率更高的分辨率&#xff0c;来渲染场景&#xff0c;它也会带来很大的性能开销。 光栅器&#xff1a; 位于最终处…

vi编辑器的常用方法

一、背景描述 在我们连接操作Linux服务器的时候&#xff0c;需要对其配置文件等内容进行一些增删改的操作&#xff0c;一般情况下我们直接使用Linux系统自带vi编辑器进行相应的操作&#xff0c;熟悉vi的常用功能对于我们编辑一些较大的文件效率能够有所提升&#xff0c;使用起来…

全国公共汽车、出租车拥有情况及客运量、货运量数据

基本信息. 数据名称: 全国公共汽车、出租车拥有情况及客运量、货运量数据 数据格式: Shp、Excel 数据时间: 2020-2022年 数据几何类型: 面 数据坐标系: WGS84 数据来源&#xff1a;中国城市统计年鉴 数据可视化. 2022年全年公共汽车客运总量数据示意图 2022年公路客…

Python 基础:使用 unittest 模块进行代码测试

目录 一、测试函数2.1 通过案例2.2 不通过案例2.3 添加新测试 二、测试类2.1 单个测试案例2.2 多个测试案例 三、总结 遇到看不明白的地方&#xff0c;欢迎在评论中留言呐&#xff0c;一起讨论&#xff0c;一起进步&#xff01; 本文参考&#xff1a;《Python编程&#xff1a;…

第六十八:iview里的table,每行数据如果有满足条件的怎么更改颜色

当然了&#xff0c;肯定又是插槽&#xff0c;话不多说直接贴图 话不多说&#xff0c;直接贴代码 <Table :columns"columns" :data"data" border show-summary height"300" sum-text"汇总" v-else :summary-method"handleSumma…

YOLO目标检测综述(2024.6月最新!)

1 基本概念 目标检测&#xff08;Object Detection&#xff09;是计算机视觉领域的重要任务之一&#xff0c;旨在识别图像或视频中的特定目标并将其位置标记出来。与图像分类任务不同&#xff0c;目标检测要求不仅能够识别目标类别&#xff0c;还需要精确地定位目标的位置。由于…

OpenAI封锁中国?国产大模型开启价格战?收好这份LLM选购指南,带你搞定极致性价比 | ShowMeAI

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; 1. Cloud LLM capability, cost, performance | 一份开发者最实用的大模型「性价比」计算手册 这是 Harlan Lewis 整理的大语言模型 (LLM) 对比清单…

3d合并模型一直加载有哪些原因---模大狮模型网

当在3D软件中合并3d模型时&#xff0c;可能会遇到加载时间过长或持续加载的情况。这可能是由以下原因之一引起的&#xff1a; 一&#xff1a;模型复杂度 合并的模型可能非常复杂&#xff0c;包含大量的面片、顶点或纹理等。这会增加加载和处理的时间。解决方法是优化模型&…

【第二周】基础语法学习

目录 前言初始化项目文件介绍基本介绍JSWXMLWXSS 常见组件基础组件视图容器match-mediamovable-area/viewpage-containerscroll-viewswiper 表单组件自定义组件 模板语法数据绑定单向数据绑定双向数据绑定 列表渲染条件渲染模板引用 事件系统事件类型事件绑定阻止冒泡互斥事件事…

股指期权交割日期是什么时候?在每个月几号?

今天带你了解股指期权交割日期是什么时候&#xff1f;在每个月几号&#xff1f;期权交割日是指合约到期之日&#xff0c;即投资者需要履行买卖合约的义务。 股指期权的交割日期通常是期权合约到期日的第三个星期五。如果这一天是公共假日&#xff0c;则交割日可能会提前到前一…

Transformers 安装及 google-t5/t5-small 机器翻译示例

文章目录 Github文档推荐文章简介安装官方示例google-t5/t5-small使用脚本进行训练Pytorch 机器翻译数据集下载数据集格式转换 Github https://github.com/huggingface/transformers 文档 https://huggingface.co/docs/transformers/indexhttps://github.com/huggingface/tr…

计算机二级Access操作题总结——综合应用

属性表相关 例1&#xff1a; 不允许输入和修改其中的数据→【是否锁定】 例2&#xff1a; 单击“退出”按钮(名为“bt2”)&#xff0c;调用设计好的宏“mEmp”来关闭窗体。 分组和汇总 对“rSell”报表进行适当设置&#xff0c;使每名雇员的姓名显示在该雇员所售书籍信…

三品PDM项目成功上线 垣发集团携手三品软件迈向智能未来

项目背景 随着全球工业化和城市化进程的不断加快&#xff0c;高空作业车的市场需求日益增长。河南垣发专用车辆集团有限公司&#xff08;以下简称“垣发集团”&#xff09;自2014年成立以来&#xff0c;一直专注于高空作业车系列产品的研发与制造。 作为一家科技导向型企业&am…

Java AWT BorderLayout的使用

目录 背景: 代码例子: 代码详解: 效果展示: 总结: 背景: BoderLayout是Java AWT(Abstract Window Toolkit)和Swing图形用户界面(GUI)库中的一个布局管理器。它用于安排组件(如按钮、标签、面板等)在容器(如窗户、面板等)中的位置。BorderLayout容器划分为五个区域:北(NO…