• 通过注解实现一个简易的Spring mvc框架


       1.首先我们来搭建架构,就建一个普通的javaweb项目就OK了,具体目录如下:

      

      对于小白来说可以细看后面web.xml的配置,对javaweb有点研究可以忽略而过后面的web.xml配置。

          2.先上代码,运行起整个项目。再来聊聊思路。

        

              (1).Controller注解
         
    复制代码
    package com.wuqi.annotation;
    import java.lang.annotation.*;
    /**
     * Created by wuqi on 2017/3/22.
     */
    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Controller {
        String value() default "";
    }
    复制代码
         (2).Quatifier注解
          
    复制代码
    package com.wuqi.annotation;
    
    import java.lang.annotation.*;
    
    /**
     * Created by wuqi on 2017/3/25.
     */
    @Target({ ElementType.FIELD }) // 代表注解的注解
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Quatifier {
        String value() default "";
    }
    复制代码
          (3).RequestMapping注解
         
    复制代码
    package com.wuqi.annotation;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    /**
     * Created by Shock on 2017/3/22.
     */
    @Target({ ElementType.METHOD }) // 在方法上的注解
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface RequestMapping {
        String value() default "";
    }
    复制代码
              (4).Service注解
         
    复制代码
    package com.wuqi.annotation;
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    /**
     * Created by Shock on 2017/3/22.
     */
    @Target({ ElementType.TYPE })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    public @interface Service {
        String value() default "";
    }
    复制代码

     --------------------------------------------------------------------------------------------------------------------------

       

         (1).MyService接口
        
    复制代码
    package com.wuqi.service.impl;
    
    import java.util.Map;
    
    /**
     * Created by wuqi on 2017/3/23.
     */
    public interface MyService {
    
        int insert(Map map);
    
        int delete(Map map);
    
        int update(Map map);
    
        int select(Map map);
    
    }
    复制代码
         (2).MyServiceImpl类
        
    复制代码
    package com.wuqi.service.impl;
    import com.wuqi.annotation.Service;
    
    import java.util.Map;
    /**
     * Created by wuqi on 2017/3/23.
     */
    @Service("MyServiceImpl")
    public class MyServiceImpl implements MyService {
        @Override
        public int insert(Map map) {
            System.out.println("MyServiceImpl:" + "insert");
            return 0;
        }
    
        @Override
        public int delete(Map map) {
            System.out.println("MyServiceImpl:" + "delete");
            return 0;
        }
    
        @Override
        public int update(Map map) {
            System.out.println("MyServiceImpl:" + "update");
            return 0;
        }
    
        @Override
        public int select(Map map) {
            System.out.println("MyServiceImpl:" + "select");
            return 0;
        }
    }
    复制代码
          (3).SpringmvcService接口
        
    复制代码
    package com.wuqi.service.impl;
    
    import java.util.Map;
    
    /**
     * Created by wuqi on 2017/3/23.
     */
    public interface SpringmvcService {
        int insert(Map map);
    
        int delete(Map map);
    
        int update(Map map);
    
        int select(Map map);
    }
    复制代码
       (4).MyServiceImpl类
        
    复制代码
    package com.wuqi.service.impl;
    import com.wuqi.annotation.Service;
    
    import java.util.Map;
    /**
     * Created by wuqi on 2017/3/23.
     */
    @Service("SpringmvcServiceImpl")
    public class SpringmvcServiceImpl implements SpringmvcService{
        @Override
        public int insert(Map map) {
            System.out.println("SpringmvcServiceImpl:" + "insert");
            return 0;
        }
        @Override
        public int delete(Map map) {
            System.out.println("SpringmvcServiceImpl:" + "delete");
            return 0;
        }
        @Override
        public int update(Map map) {
            System.out.println("SpringmvcServiceImpl:" + "update");
            return 0;
        }
        @Override
        public int select(Map map) {
            System.out.println("SpringmvcServiceImpl:" + "select");
            return 0;
        }
    
    }
    复制代码

     --------------------------------------------------------------------------------------------------------------------------

       

      (1).SpringmvcController类
      
    复制代码
    package com.wuqi.controller;
    import com.wuqi.annotation.*;
    import com.wuqi.service.impl.MyService;
    import com.wuqi.service.impl.SpringmvcService;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * Created by wuqi on 2017/3/23.
     */
    @Controller("wuqi")
    public class SpringmvcController {
        @Quatifier("MyServiceImpl")
        MyService myService;
        @Quatifier("SpringmvcServiceImpl")
        SpringmvcService smService;
    
        @RequestMapping("insert")
        public String insert(HttpServletRequest request, HttpServletResponse response, String param) {
            myService.insert(null);
            smService.insert(null);
            return null;
        }
    
        @RequestMapping("delete")
        public String delete(HttpServletRequest request, HttpServletResponse response, String param) {
            myService.delete(null);
            smService.delete(null);
            return null;
        }
    
        @RequestMapping("update")
        public String update(HttpServletRequest request, HttpServletResponse response, String param) {
            myService.update(null);
            smService.update(null);
            return null;
        }
    
        @RequestMapping("select")
        public String select(HttpServletRequest request, HttpServletResponse response, String param) {
            myService.select(null);
            smService.select(null);
            return null;
        }
    }
    复制代码

      --------------------------------------------------------------------------------------------------------------------------

      

          (1).DispatcherServlet类继承 javax.servlet.http.HttpServlet类
      
    复制代码
    package com.wuqi.servlet;
    
    import com.wuqi.annotation.*;
    import com.wuqi.controller.SpringmvcController;
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    /**
     * Created by Shock on 2017/3/23.
     */
    public class DispatcherServlet extends HttpServlet{
        private static final long serialVersionUID = 1L;
        List<String> packageNames = new ArrayList<String>();
        // 所有类的实例,key是注解的value,value是所有类的实例
        Map<String, Object> instanceMap = new HashMap<String, Object>();
        Map<String, Object> handerMap = new HashMap<String, Object>();
        public DispatcherServlet() {
            super();
        }
    
        public void init(ServletConfig config) throws ServletException {
            // 包扫描,获取包中的文件
            scanPackage("com.wuqi");
            try {
                filterAndInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 建立映射关系
            handerMap();
            // 实现注入
            ioc();
        }
    
        private void filterAndInstance() throws Exception {
            if (packageNames.size() <= 0) {
                return;
            }
            for (String className : packageNames) {
                Class<?> cName = Class.forName(className.replace(".class", "").trim());
                if (cName.isAnnotationPresent(Controller.class)) {
                    Object instance = cName.newInstance();
                    Controller controller = (Controller) cName.getAnnotation(Controller.class);
                    String key = controller.value();
                    instanceMap.put(key, instance);
                } else if (cName.isAnnotationPresent(Service.class)) {
                    Object instance = cName.newInstance();
                    Service service = (Service) cName.getAnnotation(Service.class);
                    String key = service.value();
                    instanceMap.put(key, instance);
                } else {
                    continue;
                }
            }
        }
    
        private void ioc() {
    
            if (instanceMap.isEmpty())
                return;
            for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
                // 拿到里面的所有属性
                Field fields[] = entry.getValue().getClass().getDeclaredFields();
                for (Field field : fields) {
                    field.setAccessible(true);// 可访问私有属性
                    if (field.isAnnotationPresent(Quatifier.class));
                    Quatifier quatifier = field.getAnnotation(Quatifier.class);
                    String value = quatifier.value();
                    field.setAccessible(true);
                    try {
                        field.set(entry.getValue(), instanceMap.get(value));
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
            SpringmvcController wuqi = (SpringmvcController) instanceMap.get("wuqi");
            System.out.print(wuqi);
        }
    
        /**
         * 扫描包下的所有文件
         *
         * @param Package
         */
        private void scanPackage(String Package) {
            URL url = this.getClass().getClassLoader().getResource("/" + replaceTo(Package));// 将所有的.转义获取对应的路径
            String pathFile = url.getFile();
            File file = new File(pathFile);
            String fileList[] = file.list();
            for (String path : fileList) {
                File eachFile = new File(pathFile + path);
                if (eachFile.isDirectory()) {
                    scanPackage(Package + "." + eachFile.getName());
                } else {
                    packageNames.add(Package + "." + eachFile.getName());
                }
            }
        }
    
        /**
         * 建立映射关系
         */
        private void handerMap() {
            if (instanceMap.size() <= 0)
                return;
            for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
                if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) {
                    Controller controller = (Controller) entry.getValue().getClass().getAnnotation(Controller.class);
                    String ctvalue = controller.value();
                    Method[] methods = entry.getValue().getClass().getMethods();
                    for (Method method : methods) {
                        if (method.isAnnotationPresent(RequestMapping.class)) {
                            RequestMapping rm = (RequestMapping) method.getAnnotation(RequestMapping.class);
                            String rmvalue = rm.value();
                            handerMap.put("/" + ctvalue + "/" + rmvalue, method);
                        } else {
                            continue;
                        }
                    }
                } else {
                    continue;
                }
    
            }
        }
    
        private String replaceTo(String path) {
            return path.replaceAll("\.", "/");
        }
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doPost(req, resp);
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String url = req.getRequestURI();
            String context = req.getContextPath();
            String path = url.replace(context, "");
            Method method = (Method) handerMap.get(path);
            SpringmvcController controller = (SpringmvcController) instanceMap.get(path.split("/")[1]);
            try {
                method.invoke(controller, new Object[] { req, resp, null });
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
    复制代码

    所有的代码已经贴上,还有个web.xml

      
    复制代码
    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
               xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
              http://java.sun.com/xml/ns/javaee/web-app_3_1.xsd"
               version="3.1">
        <servlet>
            <servlet-name>testServlet</servlet-name>
            <servlet-class>com.wuqi.servlet.DispatcherServlet</servlet-class>
        </servlet>
        <!-- ... -->
        <servlet-mapping>
            <servlet-name>testServlet</servlet-name>
            <url-pattern>/*</url-pattern>
        </servlet-mapping>
    </web-app>
    复制代码

      3.好了代码已经贴上了,现在需要来说说思路,因为有代码了,所以用代码来将思路,这样更容易理解代码的含义。之后可以根据自己的程度去试着写。

    •     首先我们需要扫描包中的所有文件(DispatcherServlet -> init(ServletConfig config) -> scanPackage("com.wuqi")),也就是含有注解的文件。然后将该包下的所有文件都存入packageNames集合中。
    •        这时我们拿到了包下所有的文件,但我们只需要含有我们指定注解的那部分文件,因此需要过滤出我们想要的文件即可,并且在过滤的过程中,我们可以将过滤出来的类通过Class.forName来直接实例化并储存起来。存放到instanceMap集合中,并为其设置对应的key值,该key值就是类注解的value。
    •           然后遍历instanceMap集合中的所有对象,获取指定注解的对象,并通过反射获取该对象的所有的方法,遍历所有的方法,将指定注解的方法存入handerMap,key为拼接字符串("/" + 对象变量名 + "/" + 方法名),value为方法(Method)。
    •           然后我们可以遍历instanceMap集合中的所有对象,通过反射获取对象的所有属性值(字段)集合,然后遍历属性值集合,将属性值含有指定注解的,通过Field的set方法为该属性值赋值,这时就将对象注入了。(也就是往Controller中注入Service对象)
    •          最后就可以通过反射的invoke方法调用某个对象的某个方法。(此时对象存于instanceMap,而方法都存于handerMap)

    参考链接:

  • 相关阅读:
    ES6判断对象是否为空
    mui、拍照、个推推送消息【问题链接】
    查找SAP某个Tcode下已经实施的增强
    MySQL 事务
    Go 学习线路图
    Nginx 限流配置
    Redis 内存优化
    2021年 github被墙最新hosts-每日更新
    Nginx 反向代理与负载均衡详解
    完美实现跨域 iframe 高度自适应
  • 原文地址:https://www.cnblogs.com/xiohao/p/9006204.html
Copyright © 2020-2023  润新知