手写简易SpringMVC 框架

  • 手撕简易SpringMVC框架
    mvc 整体架构
    在这里插入图片描述
    新建一个动态 Web 工程。整体机构如下:
    在这里插入图片描述
    1. 手写自己的Dispather 类,继承 HttpServlet
@PackageScann
public class MyDispather extends HttpServlet {

    private static final long serialVersionUID = -7154047248664853493L;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("doget" + req.getRequestURI() + ":==:" + req.getRequestURL());
        resp.sendRedirect("/pages/index.html");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.err.println("dispather service()" + Thread.currentThread().getName());
        String requestURI = req.getRequestURI();
        if (requestURI.endsWith("/")) {
            requestURI = requestURI.substring(0, requestURI.length() - 1);
        }
        if (IOCUtils.getUrlMaps().containsKey(requestURI)) {
            Method method = IOCUtils.getUrlMaps().get(requestURI);
            try {
                method.invoke(IOCUtils.newInstance(method), req, resp);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            resp.getWriter().write("The URL NOT Found");
        }
    }

    @Override
    public void destroy() {
        System.err.println("dispather destory()");
    }

    /**
     * 获取所有的自定义注解类,并且实例化,并且收入BeanMap 中
     */
    @Override
    public void init() throws ServletException {
        System.out.println("dispather init()");
        // 获取扫描路径下所有的class文件,实例化注解的bean.
        IOCUtils.getBasePackage(this.getClass());
        IOCUtils.createBeanMaps();

    }

}
    1. 自定义过滤器,处理请求乱码问题
public class MyServletFilter implements Filter {

    @Override
    public void destroy() {
        System.out.println("=========过滤器销毁了=================");
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
        throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest)request;
        HttpServletResponse res = (HttpServletResponse)response;
        System.out.println("过滤器执行操作" + req.getQueryString());
        req.setCharacterEncoding("utf-8");

        // 解决浏览器中文乱码
        res.setHeader("content-type", "text/html;charset=utf-8");
        // 解决get请求乱码
        MyRequestWarp reqs = new MyRequestWarp(req);
        chain.doFilter(reqs, res);
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("过滤器初始化");
    }

}

    1. 自定义增强 HttpServletRequestWrapper 类,对请求的参数进行解码
public class MyRequestWarp extends HttpServletRequestWrapper {

    private HttpServletRequest request;

    public MyRequestWarp(HttpServletRequest request) {
        super(request);
        this.request = request;
    }

    // 对请求request 对象的数据进行统一编码
    @Override
    public Map<String, String[]> getParameterMap() {
        // 获取请求方式
        String method = request.getMethod();
        if ("POST".equalsIgnoreCase(method)) {
            try {
                request.setCharacterEncoding("utf-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            Map<String, String[]> map = request.getParameterMap();
            return map;
        } else if ("get".equalsIgnoreCase(method)) {
            // get请求单独对请求参数单个装换
            Map<String, String[]> map = request.getParameterMap();
            System.out.println(map + ">>>>");
            if (map == null) {
                return super.getParameterMap();
            }
            Set<String> keySet = map.keySet();
            String[] value = null;
            String utf = null;
            try {
                for (String string : keySet) {
                    value = map.get(string);
                    for (int i = 0; i < value.length; i++) {
                        // 字符串转码
                        utf = new String(value[i].getBytes("iso-8859-1"), "utf-8");
                        value[i] = utf;
                    }
                }
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return super.getParameterMap();
    }

    @Override
    public String getParameter(String name) {
        // 通过value获取值
        String[] values = getParameterValues(name);
        if (values != null) {
            return values[0];
        }
        return super.getParameter(name);
    }

    @Override
    public String[] getParameterValues(String name) {
        // 通过map 集合获取值
        Map<String, String[]> parameterMap = getParameterMap();
        if (parameterMap != null) {
            return parameterMap.get(name);
        }
        return super.getParameterValues(name);
    }
}

    1. 自定义 注解 Controller ,Service,RequestMapping,AutoWired,packScann
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) 声明注解的使用范围. TYPE: 注解可以用在类上 FIELD:注解可以用在属性上 METHOD:用在方法上 PARAMETER:用在参数声明上面 CONSTRUCTOR:用在构造方法上面 LOCAL_VARIABLE:用在本地变量上面 @Retention(RetentionPolicy.SOURCE) 声明注解的有效范围 RetentionPolicy.SOURCE: 该注解只在源码中有效! RetentionPolicy.CLASS: 该注解在源码中,和字节码中有效!(默认) RetentionPolicy.RUNTIME: 该注解在源码中,和字节码中有效,运行字节码的时候有效!

MyController 控制层注解

/**
 * 自定义控制层注解
 * 
 * @author Donald 2019/03/23 21:08:55
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyController {
    String value() default "";
}

MyService 服务层注解

/**
 * 自动定义控制层
 * 
 * @author Donald 2019/03/23 21:58:49
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyService {
    String value() default "";
}

MyRequestMapping 请求注解

/**
 * 自定义请求url 映射
 * 
 * @author Donald 2019/03/23 22:07:26
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyRequestMapping {
    String value() default "";
}

PackageScann包扫描注解

/**
 * 包扫描注解
 * 
 * @author Donald 2019/03/23 22:38:33
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PackageScann {
    String value() default "";
}

参数自动注入注解

/**
 * 自定义自动注入
 * 
 * @author Donald 2019/03/23 22:07:39
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAutowired {

    String value() default "";
}
    1. 核心IOC 容易类 处理对bean 的管理,请求映射
public class IOCUtils {

    private IOCUtils() {}

    private static HashMap<String, Object> beanMaps = new HashMap<>();

    private static HashMap<String, Class<?>> classMaps = new HashMap<>();

    private static HashMap<String, Method> urlMaps = new HashMap<>();

    private static String basePackage = null;

    private static Class<?> clazz = null;

    public static HashMap<String, Object> getBeanMaps() {
        return beanMaps;
    }

    public static HashMap<String, Method> getUrlMaps() {
        return urlMaps;
    }

    public static HashMap<String, Class<?>> getClassMaps() {
        return classMaps;
    }

    /**
     * 获取扫描的包名。默认为dispather所在的包名
     * 
     * @return
     * @throws IOException
     */
    public static void getBasePackage(Class<?> clazz) {
        IOCUtils.clazz = clazz;
        PackageScann annotation = clazz.getAnnotation(PackageScann.class);
        if (annotation == null) {
            return;
        }
        String className = clazz.getTypeName();
        basePackage =
            "".equals(annotation.value()) ? className.substring(0, className.lastIndexOf(".")) : annotation.value();
        // 获取指定包下面的所有的class 文件
        getClassFiles();
    }

    /**
     * 获取包名及其子包下面的所有的class文件
     */
    private static void getClassFiles() {
        // 将com.feifan 转换成文件夹形式com/feifan 再类加载读取文件
        String fileString = basePackage.replaceAll("\\.", "/");
        // 得到com/feifan的绝对地址 、D:xxx/com/feifan
        String rootPath = clazz.getClassLoader().getResource(fileString).getPath();
        // 直留着com/feifan,拼接类全名
        if (rootPath != null)
            rootPath = rootPath.substring(rootPath.indexOf(fileString));
        try {
            Enumeration<URL> enumeration = clazz.getClassLoader().getResources(fileString);
            while (enumeration.hasMoreElements()) {
                URL url = (URL)enumeration.nextElement();
                if (url.getProtocol().equals("file")) {
                    // 如果是文件
                    File file = new File(url.getPath().substring(1));
                    Scanner(file, rootPath);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 封装类名,字节码 classMaps
     * 
     * @param file
     * @param rootPath
     */
    private static void Scanner(File file, String rootPath) {
        File[] files = file.listFiles();
        for (int i = 0; files != null && i < files.length; i++) {
            File file2 = files[i];
            if (file2.isDirectory()) {
                Scanner(file2, rootPath + file2.getName() + "/");
            } else {
                if (file2.getName().endsWith(".class")) {
                    String classname = (rootPath + file2.getName()).replaceAll("/", ".");
                    // 去掉.class 后缀字节码存入
                    classname = classname.substring(0, classname.lastIndexOf("."));
                    try {
                        classMaps.put(classname, Class.forName(classname));
                    } catch (ClassNotFoundException e) {
                        // TODO 获取字节码文件异常
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 生成自定义注解注解的bean
     */
    public static void createBeanMaps() {
        if (classMaps == null) {
            return;
        }
        Class<?> clazz = null;
        String pathRoot = "";
        String path = "";
        String beanKey = "";
        for (Map.Entry<String, Class<?>> entry : classMaps.entrySet()) {
            clazz = entry.getValue();
            // 控制层注解
            if (clazz.isAnnotationPresent(MyController.class)) {
                if (clazz.isAnnotationPresent(MyRequestMapping.class)) {
                    pathRoot = clazz.getAnnotation(MyRequestMapping.class).value();
                    if (!pathRoot.startsWith("/")) {
                        pathRoot = "/" + pathRoot;
                    }
                    if (!pathRoot.endsWith("/")) {
                        pathRoot = pathRoot + "/";
                    }
                }
                // url 映射路径
                Method[] methods = clazz.getDeclaredMethods();
                for (Method method : methods) {
                    if (method.isAnnotationPresent(MyRequestMapping.class)) {
                        path = method.getAnnotation(MyRequestMapping.class).value();
                        if (path.startsWith("/")) {
                            if (path.length() > 1) {
                                path = path.substring(path.indexOf("/") + 1);
                            } else {
                                path = "";
                            }
                        }
                        urlMaps.put(pathRoot + path, method);
                    }
                }

                beanKey = clazz.getSimpleName();
                beanKey = beanKey.substring(0, 1).toLowerCase() + beanKey.substring(1);
                try {
                    beanMaps.put(beanKey, clazz.newInstance());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // 服务层注解
            if (clazz.isAnnotationPresent(MyService.class)) {

                Class<?>[] classes = clazz.getInterfaces();
                try {
                    for (Class<?> class1 : classes) {
                        beanKey = class1.getSimpleName();
                        beanKey = beanKey.substring(0, 1).toLowerCase() + beanKey.substring(1);
                        beanMaps.put(beanKey, clazz.newInstance());
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                    e.printStackTrace();
                }

            }
        }

        createAutowried();
    }

    /**
     * 自动注入参数
     */
    private static void createAutowried() {

        if (classMaps == null) {
            return;
        }

        Class<?> clazz = null;
        String parm = "";
        String beanName = "";
        for (Map.Entry<String, Class<?>> entry : classMaps.entrySet()) {
            clazz = entry.getValue();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(MyAutowired.class)) {
                    parm = field.getType().toString();
                    parm = parm.substring(parm.lastIndexOf(".") + 1);
                    parm = parm.substring(0, 1).toLowerCase() + parm.substring(1);

                    beanName = clazz.getSimpleName();
                    beanName = beanName.substring(0, 1).toLowerCase() + beanName.substring(1);
                    try {
                        field.setAccessible(true);
                        field.set(beanMaps.get(beanName), beanMaps.get(parm));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    /**
     * 获取当前方法的主类
     * 
     * @param method
     * @return
     */
    public static Object newInstance(Method method) {
        String simpleName = method.getDeclaringClass().getSimpleName();
        simpleName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1);
        return beanMaps.get(simpleName);
    }
}
    1. 业务逻辑实现
      service 接口
public interface UserService {
    void printf();
}

service 实现类

@MyService
public class UserServiceImpl implements UserService {

    @Override
    public void printf() {
        System.err.println("UserServiceImpl>>>>>>");
    }

}

controller 类
BaseController 用来获取请求里面的requst,response

public class BaseController {

    protected HttpServletRequest request;
    protected HttpServletResponse response;

    protected void init(HttpServletRequest request, HttpServletResponse response) {
        this.request = request;
        this.response = response;
    }

    protected HttpServletRequest getRequest() {
        return request;
    }

    protected HttpServletResponse getResponse() {
        return response;
    }

}

控制层

@MyController
@MyRequestMapping("my")
public class UserController extends BaseController {

    @MyAutowired
    private UserService UserService;

    @MyRequestMapping("my")
    public String getMy(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        System.out.println("进来了" + req.getRequestURL());
        UserService.printf();
        // resp.setHeader("content-type", "text/html;charset=utf-8");
        resp.getWriter().write("恭喜你访问到控制层了>>>>" + req.getParameter("name"));
        return "my";
    }
}
    1. 配置Web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>SmsInterface</display-name>
    <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  
  <servlet>
    <servlet-name>springMVC</servlet-name>
    <servlet-class>com.feifan.MyDispather</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>springMVC</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
  
  <filter>
  	<filter-name>myFilter</filter-name>
  	<filter-class>com.feifan.Filter.MyServletFilter</filter-class>
  </filter>
  <filter-mapping>
  	<filter-name>myFilter</filter-name>
  	<url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

启动测试:
在这里插入图片描述
**

至此一波简易的mvc 弄完

**

链接:https://pan.baidu.com/s/1SzcMIrcOSxo7-S--UO3hWQ
提取码:ujg4

码云
https://gitee.com/ming524/HandMVC.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值