伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

手写spring+springmvc+mybatis框架篇【springmvc】

来源:本站原创 浏览:164次 时间:2021-08-04

知音专栏

程序员的出路

写程序时该追求什么,什么是次要的?

如何准备Java初级和高级的技术面试

上一篇:手写spring+springmvc+mybatis框架篇【springIOC容器】

题外话:技术交流,欢迎加入QQ群:696209224 。广告勿扰!

先放一张网上的很好的一张原理图

图片出自,这篇博客原理也写的很清晰明了。我的实现也是借鉴了这张图

https://www.cnblogs.com/xiaoxi/p/6164383.html

先说一下我的实���ʼ���,��װ����现思路:

1 在MyDispatcherServlet中的servlet初始化的时候,绑定标有@MyController注解类下面的@MyRequestMappign的value值和对应的方法。绑定的方式是放在map集合中。这个map集合就是上图说的handlerMapping,返回的handler也就是一组键值对。

2 找到对应的方法后,反射执行方法,在方法中创建一个modelandview对象,model也就是我们说的数据域,view返回的是一个视图名称,也就是我们说的视图域,当然,我这里只有jsp,spring做的很复杂。支持多种类型。最后所谓的渲染,也就是将这个数据域中的数据会添加到request请求中,然后转发。返回客户端。

3 绑定参数模型这一部分略为复杂。在下面讲解

下面是MyDispatcherServlet

这个servlet的作用就是接收用户请求,然后派发注意标红处bingdingMethodParamters方法,这个方法实现了参数的绑定。

package spring.servlet;import lombok.extern.slf4j.Slf4j;import spring.factory.InitBean;import spring.springmvc.Binding;import spring.springmvc.Handler;import spring.springmvc.MyModelAndView;import spring.springmvc.ViewResolver;import javax.servlet.ServletContext;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.List;import java.util.Map;import java.util.Set;import static spring.springmvc.BindingRequestAndModel.bindingRequestAndModel;/*** Created by Xiao Liang on 2018/6/27.*/@WebServlet(name = "MyDispatcherServlet")@Slf4jpublic class MyDispatcherServlet extends HttpServlet {   /**    * 初始化servlet,将bean容器和HandlerMapping放到servlet的全局变量中    */   @Override   public void init() {       InitBean initBean = new InitBean();       initBean.initBeans();       //根据bean容器中注册的bean获得HandlerMapping       Map<String, Method> bindingRequestMapping = Handler.bindingRequestMapping(initBean.beanContainerMap);       ServletContext servletContext = this.getServletContext();       servletContext.setAttribute("beanContainerMap", initBean.beanContainerMap);       servletContext.setAttribute("bindingRequestMapping", bindingRequestMapping);   }   protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {       try {           doDispatch(request, response);       } catch (Exception e) {           log.error("控制器处理异常");           e.printStackTrace();       }   }   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {       doPost(request, response);   }   //接收到请求后转发到相应的方法上   private void doDispatch(HttpServletRequest request, HttpServletResponse response) throws IOException, InvocationTargetException, IllegalAccessException, InstantiationException {       ServletContext servletContext = this.getServletContext();       //获取扫描controller注解后url和方法绑定的mapping,也就是handlerMapping       Map<String, Method> bindingRequestMapping =               (Map<String, Method>) servletContext.getAttribute("bindingRequestMapping");       //获取实例化的bean容器       Map<String, Object> beanContainerMap = (Map<String, Object>) servletContext.getAttribute("beanContainerMap");       String url = request.getServletPath();       Set<Map.Entry<String, Method>> entries = bindingRequestMapping.entrySet();       List<Object> resultParameters = Binding.bingdingMethodParamters(bindingRequestMapping, request);       for (Map.Entry<String, Method> entry :               entries) {           if (url.equals(entry.getKey())) {               Method method = entry.getValue();               Class<?> returnType = method.getReturnType();                   //如果返回值是MyModelAndView,开始绑定               if ("MyModelAndView".equals(returnType.getSimpleName())){                   Object object = beanContainerMap.get(method.getDeclaringClass().getName());                   //获取springmvc.xml中配置的视图解析器                   ViewResolver viewResolver = (ViewResolver) beanContainerMap.get("spring.springmvc.ViewResolver");                   String prefix = viewResolver.getPrefix();                   String suffix = viewResolver.getSuffix();                   MyModelAndView myModelAndView = (MyModelAndView) method.invoke(object, resultParameters.toArray());                   //将request和model中的数据绑定,也就是渲染视图                   bindingRequestAndModel(myModelAndView,request);                   String returnViewName = myModelAndView.getView();                   //返回的路径                   String resultAddress = prefix + returnViewName + suffix;                   try {                       request.getRequestDispatcher(resultAddress).forward(request,response);                   } catch (ServletException e) {                       e.printStackTrace();                   }               }           }       }   }}

首先是绑定方法和url,是Handler类,用如下对象绑定

Map<String, Method> handlerMapping = new ConcurrentHashMap<>();
package spring.springmvc;import lombok.extern.slf4j.Slf4j;import spring.Utils.AnnotationUtils;import spring.annotation.MyController;import spring.annotation.MyRequestMapping;import spring.exception.springmvcException;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.Map;import java.util.Set;import java.util.concurrent.ConcurrentHashMap;/*** @ClassName Handler* @Description  遍历bean容器,在有controller注解的类中有requestmapping扫描的方法,则将方法和url和方法绑定* @Data 2018/7/3* @Author xiao liang*/@Slf4jpublic class Handler {   public static Map<String, Method> bindingRequestMapping(Map<String, Object> beanContainerMap){       Map<String, Method> handlerMapping = new ConcurrentHashMap<>();       if (beanContainerMap != null){           Set<Map.Entry<String, Object>> entries = beanContainerMap.entrySet();           for (Map.Entry<String, Object> entry :                   entries) {               Class aClass = entry.getValue().getClass();               Annotation annotation = aClass.getAnnotation(MyController.class);               Method[] methods = aClass.getMethods();               if (!AnnotationUtils.isEmpty(annotation) && methods != null){                   for (Method method:                           aClass.getMethods()) {                       MyRequestMapping requestMappingAnnotation = method.getAnnotation(MyRequestMapping.class);                       if (!AnnotationUtils.isEmpty(requestMappingAnnotation)){                           String key = requestMappingAnnotation.value();                           handlerMapping.put(key,method);                       }                   }               }           }       }       else{           throw new springmvcException("实例化bean异常,没有找到容器");       }       return handlerMapping;   }}

参数绑定支持

  1. @MyRequestMapping(用来绑定简单数据类型)

  2. @MyModelAndAttribute(绑定实体类)

  3. 不写注解,直接写实体类。

下面先贴一下这一部分的结构关系图

这里用多态的设计思想,对于bindingParamter方法写了两种实现,方便大家自行扩展

package spring.springmvc;import spring.Utils.AnnotationUtils;import spring.Utils.isBasicTypeUtils;import spring.annotation.MyModelAttribute;import spring.annotation.MyRequstParam;import spring.exception.springmvcException;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Method;import java.lang.reflect.Parameter;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;/*** @ClassName Binding* @Description* @Data 2018/7/4* @Author xiao liang*/public class Binding {   public static  List<Object> bingdingMethodParamters(Map<String, Method> bindingRequestMapping, HttpServletRequest request) {       List<Object> resultParameters  = new ArrayList<>();       Set<Map.Entry<String, Method>> entries = bindingRequestMapping.entrySet();       for (Map.Entry<String, Method> entry :               entries) {           Method method = entry.getValue();           Parameter[] parameters = method.getParameters();           for (Parameter parameter :                   parameters) {       //遍历每个参数,如果参数存在注解,将这个参数添加到resultParameters中               if (!AnnotationUtils.isEmpty(parameter.getAnnotations())){                   Object resultParameter = null;                   try {                       resultParameter = bingdingEachParamter(parameter, request);                   } catch (IllegalAccessException e) {                       e.printStackTrace();                       throw new springmvcException("绑定参数异常");                   } catch (NoSuchMethodException e) {                       e.printStackTrace();                       throw new springmvcException("绑定参数异常");                   } catch (InstantiationException e) {                       e.printStackTrace();                       throw new springmvcException("绑定参数异常");                   }                   resultParameters.add(resultParameter);               }           }       }       return resultParameters;   }private static Object bingdingEachParamter(Parameter parameter, HttpServletRequest request) throws IllegalAccessException, NoSuchMethodException, InstantiationException {        //如果注解是MyRequstParam,则用BindingByMyRequstParam来执行装配        if (!AnnotationUtils.isEmpty(parameter.getAnnotation(MyRequstParam.class))){            BindingParamter bindingParamter = new BindingByMyRequstParam();            Object resultParameter = bindingParamter.bindingParamter(parameter, request);            return resultParameter;        }        //如果注解是MyModelAttribute,则用BindingByMyModelAttribute来执行装配        else if (!AnnotationUtils.isEmpty(parameter.getAnnotation(MyModelAttribute.class))){            BindingParamter bindingParamter = new BindingByMyModelAttribute();            Object resultParameter = bindingParamter.bindingParamter(parameter,request);            return resultParameter;        }        //在没有注解的时候,自动识别,如果是基本数据类型用MyRequstParam装配,如果是用户自定义类型用MyModelAttribute装配        else if(parameter.getAnnotations() == null || parameter.getAnnotations().length ==0){            boolean flag = isBasicTypeUtils.isBasicType(parameter.getType().getSimpleName());            if (flag){                BindingParamter bindingParamter = new BindingByMyRequstParam();                Object resultParameter = bindingParamter.bindingParamter(parameter, request);                return resultParameter;            }            else{                BindingParamter bindingParamter = new BindingByMyModelAttribute();                Object resultParameter = bindingParamter.bindingParamter(parameter,request);                return resultParameter;            }        }        return null;    }}

下面是接口BindingParamter 和两个实现类BindingByMyModelAttribute和BindingByMyRequstParam

package spring.springmvc;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Parameter;/*** @ClassName BindingRoles* @Description* @Data 2018/7/4* @Author xiao liang*/public interface BindingParamter {    Object bindingParamter(Parameter parameter, HttpServletRequest request) throws IllegalAccessException, InstantiationException, NoSuchMethodException;}
package spring.springmvc;import spring.Utils.StringUtils;import spring.annotation.MyRequstParam;import spring.exception.springmvcException;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Parameter;/*** @ClassName BindingByMyRequstParam* @Description 参数注解是MyMyRequstParam时,绑定数据的类* @Data 2018/7/4* @Author xiao liang*/public class BindingByMyRequstParam implements BindingParamter {   @Override   public Object bindingParamter(Parameter parameter, HttpServletRequest request) {       MyRequstParam myRequstParam = parameter.getAnnotation(MyRequstParam.class);       //获得注解的value值       String MyRequstParamValue = myRequstParam.value();       //获得参数的类名       String parameterType = parameter.getType().getSimpleName();       String parameter1 = request.getParameter(MyRequstParamValue);       if (StringUtils.isEmpty(parameter1)) {           throw new springmvcException("绑定参数异常");       }       //parameter1赋值       if (parameterType.equals("String")) {           return parameter1;       } else if (parameterType.equals("Integer") || parameterType.equals("int")) {         Integer binddingParameter =  Integer.valueOf(parameter1);         return binddingParameter;       }       return null;   }}
package spring.springmvc;import lombok.extern.slf4j.Slf4j;import spring.Utils.AnnotationUtils;import spring.Utils.ConvertUtis;import spring.Utils.GetMethodName;import spring.Utils.StringUtils;import spring.annotation.MyModelAttribute;import spring.exception.springmvcException;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Parameter;/*** @ClassName BindingByMyModelAttribute* @Description 参数注解是MyModelAttribute时,绑定数据的类* @Data 2018/7/4* @Author xiao liang*/@Slf4jpublic class BindingByMyModelAttribute implements   BindingParamter {   @Override   public Object bindingParamter(Parameter parameter, HttpServletRequest request) throws IllegalAccessException, InstantiationException, NoSuchMethodException {       MyModelAttribute myModelAttribute = parameter.getAnnotation(MyModelAttribute.class);       //获得参数的类名       Class<?> aClass = parameter.getType();       if (!AnnotationUtils.isEmpty(myModelAttribute)){           if (!aClass.getSimpleName().equals(myModelAttribute.value())){               throw new springmvcException("实体类绑定异常,请重新检查");           }       }       Field[] fields = aClass.getDeclaredFields();       Object object = aClass.newInstance();       //遍历每个属性,用set注入将值注入到对象中       for (Field field :               fields) {           //获得用户传来的值           String parameter1 = request.getParameter(field.getName());           if (!StringUtils.isEmpty(parameter1)){               //将用户传过来的值转换成对应的参数类型               Object setObject = ConvertUtis.convert(field.getType().getSimpleName(),parameter1);               String methodName = GetMethodName.getSetMethodNameByField(field.getName());               Method method = aClass.getMethod(methodName, field.getType());               try {                   //反射set注入                   method.invoke(object,setObject);               } catch (InvocationTargetException e) {                   log.error("{}属性赋值异常",field.getName());                   e.printStackTrace();               }           }       }       //返回对注入值后的对象       return object;   }}

绑定完参数,就该返回ModelAndView了,

package spring.springmvc;import lombok.Data;/*** @ClassName MyModelAndView* @Description* @Data 2018/7/4* @Author xiao liang*/@Datapublic class MyModelAndView {   private String view;   private MyModelMap modelMap;   public MyModelAndView(String view) {       this.view = view;   }}

view是视图名称,还有viewResolver,用来接收xml文件中定义的前缀和后缀。modelMap是数据域,最后渲染的时候要绑定到request中。

package spring.springmvc;import lombok.Data;/*** @ClassName ViewResolver* @Description 视图解析器 前缀和后缀* @Data 2018/7/4* @Author xiao liang*/@Datapublic class ViewResolver {   private String prefix = "";   private String suffix = "";}

最后的渲染类

package spring.springmvc;import javax.servlet.http.HttpServletRequest;import java.util.Map;import java.util.Set;/*** @ClassName BindingRequestAndModel* @Description* @Data 2018/7/6* @Author xiao liang*/public class BindingRequestAndModel {   //遍历modelMap,然后将model中的数据绑定到requst中   public static void bindingRequestAndModel(MyModelAndView myModelAndView, HttpServletRequest request) {       MyModelMap myModelMap = myModelAndView.getModelMap();       if (!myModelMap.isEmpty()){           Set<Map.Entry<String, Object>> entries1 = myModelMap.entrySet();           for (Map.Entry<String, Object> entryMap :                   entries1) {               String key = entryMap.getKey();               Object value = entryMap.getValue();               request.setAttribute(key,value);           }       }   }}

至此,最后在MyDispatcherServlet中用转发操作将试图返回。

request.getRequestDispatcher(resultAddress).forward(request,response);

我将此项目上传到了github,需要的童鞋可以自行下载。

https://github.com/836219171/MySSM

  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net