手写SpringMVC框架
来源:互联网 发布:let it go 英文歌词 编辑:程序博客网 时间:2024/05/16 06:45
springmvc在项目中的作用
- 处理请求,把请求分发到不同的类和方法中
- ioc 依赖注入,创建实例。配置的方式和annotation的方式,今天实现annotation的方式
- aop 动态代理,事物控制,让程序员只专注于写自己的业务代码
步骤
定义包结构
com.annotationcom.controllercom.servicecom.service.implcom.servlet
自定义注解
元注解的作用就是负责注解其他注解 1.@Target, :作用目标,作用在方法上、变量上、还是类上 2.@Retention,用于描述注解的生命周期: SOURCE:在源文件中有效 CLASS:在class文件中有效 RUNTIME:在运行时有效 3.@Documented,javadoc此类的工具文档化自定义4个注解:Controller,Service,RequestMapping,Qualifier注解就是存储信息的,跟xml功能差不多,存储了信息后,程序读到注解上面的信息做相应的操作
3、包扫描
包扫描的目的根据basepackage,就是基包(代码中指的是com),扫描下面的子包以及子包下的类拿到包下的所有类文件后,我们就可以得到文件名有包名有文件名,我们就可以通过反射new出这些类的实例目的就是扫描基包下的所有的类文件,根据文件获取类的完整类名:包名+类名通过文件的方式去扫描
4、把所有的类new出实例后,我们就要把类中的依赖关系注入进去
拿到类的Class对象拿到field对象拿到field上面的annotation对象根据annotation对象拿annotation对象的属性把属性当key拿到map中的实例然后field。set把实例设置进去
5、建立一个url与类中方法的映射关系
其实是同样的做法拿到类的Class对象拿到Method对象拿到Method上面的annotation对象把url和method对象存到map中
代码
自定义注解
package com.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;@Target({ ElementType.TYPE }) // 注解在类上@Retention(RetentionPolicy.RUNTIME)@Documented // 可以不写 用来文档打包的public @interface Controller { String value() default "";}package com.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;@Target({ ElementType.FIELD }) // 注解在字段上@Retention(RetentionPolicy.RUNTIME)@Documented // 可以不写 用来文档打包的public @interface Qualifier { String value() default "";}package com.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;@Target({ ElementType.METHOD }) // 注解在方法上@Retention(RetentionPolicy.RUNTIME)@Documented // 可以不写 用来文档打包的public @interface ResquestMapping { String value() default "";}package com.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;@Target({ ElementType.TYPE }) // 注解在类上@Retention(RetentionPolicy.RUNTIME)@Documented // 可以不写 用来文档打包的public @interface Service { String value() default "";}
包扫描 IOC 和 handlerMapping
package com.servlet;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 java.util.Map.Entry;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.annotation.Controller;import com.annotation.Qualifier;import com.annotation.ResquestMapping;import com.annotation.Service;public class DispatcherServlet extends HttpServlet { private static final long serialVersionUID = 1L; // 定义基包下的文件的全限定名集合 List<String> packageNames = new ArrayList<>(); // 定义实例化对象的map key为注解的value value为类的实例 Map<String, Object> instanceMap = new HashMap<>(); // 定义路径与方法映射集合 Map<String, Object> handlerMap = new HashMap<>(); @Override public void init() throws ServletException { /* 包扫描 */ // 根据basepackage,就是基包(代码中指的是com),扫描下面的子包以及子包下的类 // 拿到包下的所有类文件后,我们就可以得到文件名 // 有包名有文件名,我们就可以通过反射new出这些类的实例 // 目的就是扫描基包下的所有的类文件,根据文件获取类的完整类名:包名+类名 // 通过文件的方式去扫描 System.out.println(this.getClass().getClassLoader().getResource("/"));// null System.out.println(this.getClass().getClassLoader().getResource(""));// file:/D:/Users/workspace-sts-3.7.1.RELEASE/SpringMVC/target/classes/ System.out.println(this.getClass().getClassLoader().getResource("com"));// file:/D:/Users/workspace-sts-3.7.1.RELEASE/SpringMVC/target/classes/com System.out.println(DispatcherServlet.class.getClassLoader().getResource("/com"));// null scanPackage("com");// spring中 是在xml中配置的 try { // 拿到类的Class对象 filterAndInstance(); // 依赖注入 // 拿到field对象 // 拿到field上面的annotation对象 // 根据annotation对象拿annotation对象的属性 // 把属性当key拿到map中的实例 // 然后field。set把实例设置进去 ioc(); // 建立路径方法映射 handlerMap(); // 打印实例化对象的map for (Entry<String, Object> entry : instanceMap.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } // 打印路径与方法映射集合map for (Entry<String, Object> entry : handlerMap.entrySet()) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } catch (Exception e) { e.printStackTrace(); } } /** * @Title: ioc * @Description: 路径方法映射 */ private void handlerMap() { if (instanceMap.isEmpty()) { return; } // 遍历 实例集合 取得方法 包含 RequestMapping 注解 for (Entry<String, Object> entry : instanceMap.entrySet()) { if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) { Controller controllerAn = entry.getValue().getClass().getAnnotation(Controller.class); String ctvalue = controllerAn.value(); Method[] methods = entry.getValue().getClass().getMethods(); for (Method method : methods) { if (method.isAnnotationPresent(ResquestMapping.class)) { ResquestMapping annotation = method.getAnnotation(ResquestMapping.class); String rmvalue = annotation.value(); handlerMap.put("/" + ctvalue + "/" + rmvalue, method); } } } } } /** * @Title: ioc * @Description: 属性依赖注入 */ private void ioc() throws IllegalArgumentException, IllegalAccessException { // 如果 map 为空 说明没有实例化对象 返回 if (instanceMap.isEmpty()) { return; } // 遍历 实例集合 for (Entry<String, Object> entry : instanceMap.entrySet()) { if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) { // 获取 当前实例的字段 Field[] fields = entry.getValue().getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); // 如果包含指定注解 那么通过该注解的 value 向正在遍历的实例化对象中注入 指定对象 if (field.isAnnotationPresent(Qualifier.class)) { Qualifier annotation = field.getAnnotation(Qualifier.class); String value = annotation.value(); field.set(entry.getValue(), instanceMap.get(value)); } } } } } /** * @Title: filterAndInstance * @Description: 定义过滤方法 添加需要实例化的类到instanceMap */ private void filterAndInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (packageNames.isEmpty()) { return; } for (String className : packageNames) { // 反射 获取对象 className去掉.class Class<?> clazz = Class.forName(className.replace(".class", "")); // 根据注解判断是否需要实例化 if (clazz.isAnnotationPresent(Controller.class)) { Object instance = clazz.newInstance(); Controller annotation = clazz.getAnnotation(Controller.class); String key = annotation.value(); instanceMap.put(key, instance); } else if (clazz.isAnnotationPresent(Service.class)) { Object instance = clazz.newInstance(); Service annotation = clazz.getAnnotation(Service.class); String key = annotation.value(); instanceMap.put(key, instance); } } } /** * @Title: scanPackage * @Description: 定义包扫描方法 */ private void scanPackage(String basepackage) { // 将基包中的.转换为/ 才能遍历其下的文件 URL url = this.getClass().getClassLoader().getResource(replaceTo(basepackage)); String pathFile = url.getFile();// 得到绝对路径的字符串 File file = new File(pathFile); String[] files = file.list(); for (String path : files) { File eachFile = new File(pathFile + "/" + path); if (eachFile.isDirectory()) { // 递归迭代 scanPackage(basepackage + "." + eachFile.getName()); } else { // 是文件 添加其全类名 // 返回 com.xxx.class System.out.println("初始加载基包下的所有文件: " + basepackage + "." + eachFile.getName()); packageNames.add(basepackage + "." + eachFile.getName()); } } } /** * @Title: replaceTo * @Description: 将路径中的 "." 转换为 "/" */ private String replaceTo(String path) { return path.replaceAll("\\.", "/"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String uri = req.getRequestURI(); // 获取工程名字 String contextPath = req.getContextPath(); // 截取uri 去掉工程名字 /index/insert String path = uri.replace(contextPath, ""); Method method = (Method) handlerMap.get(path); try { // path.split("/")=["",index,insert] method.invoke(instanceMap.get(path.split("/")[1]), new Object[] { req, resp, null }); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } }}
controller 和 service
package com.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.annotation.Controller;import com.annotation.Qualifier;import com.annotation.ResquestMapping;import com.service.IndexService;import com.service.MyService;//设计这里的index 也是相当于springMVC中RequestMapping的作用@Controller("index")public class IndexController { @Qualifier("myServiceImpl") private MyService myService; @Qualifier("indexServiceImpl") private IndexService indexService; @ResquestMapping("insert") // 不能带有"/" 设计不带 public String insert(HttpServletRequest request, // HttpServletResponse response, // String param) { // URL: http://localhost:8080/SpringMVC/index/update // URI: /SpringMVC/index/update System.err.println("URL: " + request.getRequestURL()); System.err.println("URI: " + request.getRequestURI()); myService.insert(); indexService.insert(); return null; } @ResquestMapping("delete") // 不能带有"/" 设计不带 public String delete(HttpServletRequest request, // HttpServletResponse response, // String param) { System.err.println("URL: " + request.getRequestURL()); System.err.println("URI: " + request.getRequestURI()); myService.delete(); indexService.delete(); return null; } @ResquestMapping("update") // 不能带有"/" 设计不带 public String update(HttpServletRequest request, // HttpServletResponse response, // String param) { System.err.println("URL: " + request.getRequestURL()); System.err.println("URI: " + request.getRequestURI()); myService.update(); indexService.update(); return null; } @ResquestMapping("select") // 不能带有"/" 设计不带 public String select(HttpServletRequest request, // HttpServletResponse response, // String param) { System.err.println("URL: " + request.getRequestURL()); System.err.println("URI: " + request.getRequestURI()); myService.select(); indexService.select(); return null; }}
package com.service;public interface IndexService { int insert(); int delete(); int update(); int select();}package com.service;public interface MyService { int insert(); int delete(); int update(); int select();}
package com.service.impl;import com.annotation.Service;import com.service.IndexService;@Service("indexServiceImpl")public class IndexServiceImpl implements IndexService { @Override public int insert() { System.out.println("IndexServiceImpl的insert"); return 0; } @Override public int delete() { System.out.println("IndexServiceImpl的delete"); return 0; } @Override public int update() { System.out.println("IndexServiceImpl的update"); return 0; } @Override public int select() { System.out.println("IndexServiceImpl的select"); return 0; }}package com.service.impl;import com.annotation.Service;import com.service.MyService;@Service("myServiceImpl")public class MyServiceImpl implements MyService { @Override public int insert() { System.out.println("MyServiceImpl的insert"); return 0; } @Override public int delete() { System.out.println("MyServiceImpl的delete"); return 0; } @Override public int update() { System.out.println("MyServiceImpl的update"); return 0; } @Override public int select() { System.out.println("MyServiceImpl的select"); return 0; }}
web.xml
<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" 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_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> <!-- 自定义前端控制器 --> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>com.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <!-- 1:*.do *.action 拦截以.do结尾的请求 (不拦截 jsp png jpg .js .css) 2:/ 拦截所有请求 (不拦截.jsp) 建议使用此种 方式 (拦截 .js.css .png) (放行静态资源) 3:/* 拦截所有请求(包括.jsp) 此种方式 不建议使用 --> <url-pattern>/*</url-pattern> </servlet-mapping></web-app>
OK 大功告成!!!
阅读全文
0 0
- 手写springMVC框架
- 手写SpringMVC框架
- 手写SpringMVC框架
- 手写简单的springmvc框架
- 深度解析SpringMvc实现原理手写SpringMvc框架
- 纯手写SpringMVC框架,用注解实现springmvc过程
- 深度解析SpringMvc实现原理手写SpringMvc框架
- 纯手写SpringMVC框架,用注解实现springmvc过程
- 手写springmvc
- 自己手写一个springmvc
- 手写struts2框架
- 手写JSON解析框架
- 手写依赖注入框架
- 手写mvp框架
- Android 手写数据库框架
- 手写jQuery框架
- 手写EventBus框架
- 手写spring ioc框架
- 由循环次数设定引发的一些思考
- chapter10_2图片读取覆盖像素
- Android之自定义ListView
- 博客开张
- Java中的native使用
- 手写SpringMVC框架
- TEST
- requests库入门-8-POST方法举例
- Java中将html转化为字符转
- Plugin with id 'com.github.dcendents.android-maven' not found
- ==和equals的区别
- ubuntu中如何查看系统信息(uname)
- Calendar
- 欢迎使用CSDN-markdown编辑器