SpringMVC(手写简单实现)

SpringMVC

SpringMVC的运行流程

  1. 用户发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求调用HandlerMapping处理映射器
  3. 处理器映射器根据请求url找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
  4. DispatcherServlet通过HandlerAdapter处理器适配器调用处理器
  5. 执行处理器(Controller,也叫后端控制器)
  6. Controller执行完成返回ModelAndView
  7. HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
  8. DispatcherServlet将ModelAndView传给ViewReslover视图解析器
  9. ViewReslover解析后返回具体View
  10. DispatcherServlet对View进行渲染视图(即将模型数据填充至视图中)
  11. DispatcherServlet响应用户

回顾Servlet

概念

       Java Servlet 是运行在 Web 服务器或应用服务器上的程序,它是作为来自 Web 浏览器或其他 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中间层。

       使用 Servlet,可以很方便的收集来自网页表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。

Servlet声明周期

       Servlet 加载—>实例化—>服务—>销毁。

  • init():

       在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。

  • service():

       它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。

  • destroy():

      仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。

手写SpringMVC基本实现

/**
 * 1.自定义前端控制器DispatcherServlet
 *   拦截所有请求 (springmvc 基于servlet实现)
 * 2.继承HttpServlet 重写init()方法(只会执行一次)
 *   2.1获取当前包下所有的类
 *   2.2利用反射机制初始化所有的类,存放在SpringMVC容器中
 *      key(beanId),value(当前实例对象)
 *   2.3初始化HandlerMapping方法,将url和方法对应
 *      使用反射技术读取类的信息,存放在map集合中
 *           key为url请求地址,value为子map集合,
 *           key为方法名称,value为实例对象
 *      2.3.1 遍历springmvc bean容器 获取bean对象
 *      2.3.2 判断类上是否有加url映射注解
 *      2.3.3 判断方法上是否有加url映射地址
 *      2.3.4  拼接完整路径,装到SpringMVC容器中
 *3.重写doGet()、doPost()方法
 *   3.1获取请求url地址
 *   3.2从Map集合中获取控制对象
 *   3.3.使用url地址获取方法
 *   3.4.使用java的反射机制调用方法
 *   3.5.调用视图转换器渲染给页面展示
 */
//1.自定义前端控制器DispatcherServlet
public class DispatcherServletDemo extends HttpServlet {
    // springmvc 容器对象 key:类名id ,value 对象
    private ConcurrentHashMap<String, Object> springmvcBeans = new ConcurrentHashMap<String, Object>();
    // springmvc 容器对象 key:url ,value map key:方法名称 ,value 对象
    private ConcurrentHashMap<String, Map<String,Object>> urlMappings = new ConcurrentHashMap<String, Map<String,Object>>();
    //2.重写init()方法
    @Override
    public void init() throws ServletException {
        //2.1获取当前包下所有的类
        List<Class<?>> classes = ClassUtil.getClasses("controller");
        // 2.2利用反射机制初始化所有的类,存放在SpringMVC容器中
        try {
            loadSpringMVCBeanMap(classes);
        }catch (Exception e){

        }
        //2.3初始化HandlerMapping方法,将url和方法对应
        handlerMapping();
    }

    /**
     *利用反射机制初始化所有的类,存放在SpringMVC容器中
     * key(beanId),value(当前实例对象)
     * @param classes
     */
    private void loadSpringMVCBeanMap(List<Class<?>> classes) throws Exception {
        for(Class classInfo:classes){
            //是否有自定义Controller注解
            ControllerDemo controllerDemo = (ControllerDemo) classInfo.getDeclaredAnnotation(ControllerDemo.class);
            if(controllerDemo != null){
                //beanId默认首字母小写
                String beanId = ClassUtil.toLowerCaseFirstOne(classInfo.getSimpleName());
                //实例化对象
                Object obj = classInfo.newInstance();
                //装到SpringMVC容器中
                springmvcBeans.put(beanId,obj);
            }
        }
    }

    /**
     * 2.3初始化HandlerMapping方法,将url和方法对应
     *    2.3.1 遍历springmvc bean容器 获取bean对象
     *    2.3.2 判断类上是否有加url映射注解
     *    2.3.3 判断方法上是否有加url映射地址
     *    2.3.4  拼接完整路径,装到SpringMVC容器中
     */
    private void handlerMapping() {
        //2.3.1 遍历springmvc bean容器
        for(Map.Entry<String,Object> mvcbean : springmvcBeans.entrySet()){
            //获取bean对象
            Object object = mvcbean.getValue();
            //2.3.2 判断类上是否有加url映射注解
            Class<?> classInfo = object.getClass();
            RequestMappingDemo requestMappingDemo = classInfo.getDeclaredAnnotation(RequestMappingDemo.class);
            String baseUrl =  "";
            if(requestMappingDemo != null){
                baseUrl = requestMappingDemo.value();
            }
            //2.3.3 判断方法上是否有加url映射地址
            Method[] methods = classInfo.getMethods();
            for(Method method:methods){
                RequestMappingDemo requestMappingDemo1 = method.getDeclaredAnnotation(RequestMappingDemo.class);
                if(requestMappingDemo1 != null){
                    //2.3.4  拼接完整路径,装到SpringMVC容器中
                    baseUrl = baseUrl + requestMappingDemo1.value();
                    //map key:方法名称 ,value 对象
                    Map<String,Object> map = new HashMap<String, Object>();
                    map.put(method.getName(),object);
                    //springmvc 容器对象 key:url ,value map
                    urlMappings.put(baseUrl,map);
                }
            }
        }
    }

    //3.重写doGet()方法
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req,resp);
    }

    /**
     * 3.重写doGet()、doPost()方法
     *  *   3.1获取请求url地址
     *  *   3.2从Map集合中获取控制对象
     *  *   3.3.使用url地址获取方法和实例对象
     *  *   3.4.使用java的反射机制调用方法
     *  *   3.5.调用视图转换器渲染给页面展示
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //3.1获取请求url地址
        String requestURI = req.getRequestURI();
        //3.2从Map集合中获取控制对象
        Map<String, Object> map = urlMappings.get(requestURI);
        //3.3.根据url地址获取方法
        String methodName = map.entrySet().iterator().next().getKey();
        //获得实例对象
        Object object = map.entrySet().iterator().next().getValue();
        try {
            //3.4.使用java的反射机制调用方法
            String resultPage = (String) object.getClass().getMethod(methodName).invoke(object);
            //3.5.调用视图转换器渲染给页面展示
            extResourceViewResolver(resultPage, req, resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //3.5.调用视图转换器渲染给页面展示
    private void extResourceViewResolver(String resultPage, HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 根路径
        String prefix = "/";
        String suffix = ".jsp";
        req.getRequestDispatcher(prefix + resultPage + suffix).forward(req, resp);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值