array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 【javaweb】自己动手实现简易的springmvc - 爱码网

 

【javaweb】自己动手实现简易的springmvc

 

自定义注解

MyController.java

package cn.huangyan.spring.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;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MyController {
	String value() default "";
}

MyService.java

package cn.huangyan.spring.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;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface MyService {
	String value() default "";
}

MyAutowired.java

package cn.huangyan.spring.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;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface MyAutowired {
	String value() default "";
}

MyRequestMapping.java

package cn.huangyan.spring.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;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface MyRequestMapping {
	String value() default "";
}

注意:

  1. ElementType.TYPE表示定义的这个注解以后可以用在类上;
  2. ElementType.METHOD表示这个注解可以用在方法上;

测试类

TestService.java

package cn.huangyan.spring.pack;

import cn.huangyan.spring.annotation.MyService;

@MyService("/testService")
public class TestService {
		
	public String testService() {
		return "testService";
	}
}

TestController.java

package cn.huangyan.spring.pack;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.huangyan.spring.annotation.MyAutowired;
import cn.huangyan.spring.annotation.MyController;
import cn.huangyan.spring.annotation.MyRequestMapping;

@MyController
@MyRequestMapping("/test")
public class TestController {
	
	@MyAutowired("/testService")
	private TestService testService;
	
	@MyRequestMapping("/index")
	public void testController(HttpServletRequest request, HttpServletResponse response) {
		String returnString = "testController:" + testService.testService();
		System.out.println("returnString ="+returnString);
		try {
			PrintWriter writer = response.getWriter();
			writer.write(returnString);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

中央控制器DispatcherServlet

package cn.huangyan.spring.pack;

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 cn.huangyan.spring.annotation.MyAutowired;
import cn.huangyan.spring.annotation.MyController;
import cn.huangyan.spring.annotation.MyRequestMapping;
import cn.huangyan.spring.annotation.MyService;

/**
 * Servlet implementation class MyDispatcherServlet
 */
public class MyDispatcherServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	// 存在当前加载的所有的类
	List<String> classNames = new ArrayList<String>();
	
	// 存储IOC容器的MAP
	Map<String,Object> beans = new HashMap<>();
	
	// 存储请求路径和方法的映射关系
	Map<String,Object> handlerMethd = new HashMap<>();

	public void init() throws ServletException{
		System.out.println("进来了");

		String basePackage = "cn.huangyan.spring";

		scanPackage(basePackage);

		classInstance();

		autoInject();

		handlerMapping();

		for(Entry<String,Object> entry : beans.entrySet()) {
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}
		System.out.println("----------------------------------------------------------------------");
		for(Entry<String,Object> entry : handlerMethd.entrySet()) {
			System.out.println(entry.getKey() + " = " + entry.getValue());
		}
	}


	// 第1步:springmvc的包扫描
	private void scanPackage(String basePackage) {
		String path = basePackage.replaceAll("\\.", "/"); // path = cn/huangyan/spring

		// file:/D:/ecli_space/workspace/myday06/target/classes/cn/huangyan/spring
		URL url = getClass().getClassLoader().getResource(path); //  注意path最前面没有/
		String filePath = url.getFile(); // /D:/ecli_space/workspace/myday06/target/classes/cn/itcast/cn/huangyan/spring
		File[] files = new File(filePath).listFiles();

		for(File file : files) {
			if(file.isDirectory()) {
				scanPackage(basePackage + "." + file.getName());
			}else {
				classNames.add(basePackage + "." + file.getName());
			}
		}
	}

	// 第2步:类实例化
	private void classInstance() {
		if(classNames.isEmpty()) {
			System.out.println("没有扫描到任何.class文件");
			return;
		}

		for(String className : classNames) {
			String realClassName = className.replace(".class", "");
			try {
				Class clazz = Class.forName(realClassName);
				
				// 判断此类有没有MyController注解
				if(clazz.isAnnotationPresent(MyController.class)) {
					//获得此clazz上的MyController注解
					MyController myController = (MyController) clazz.getAnnotation(MyController.class);
					Object instance = clazz.newInstance();
					//获得此clazz上的MyRequestMapping注解
					MyRequestMapping myRequestMapping = (MyRequestMapping) clazz.getAnnotation(MyRequestMapping.class);
					String mappingValue = myRequestMapping.value();
					beans.put(mappingValue, instance);
				}

				// 判断此类有没有MyService注解
				if(clazz.isAnnotationPresent(MyService.class)) {
					//获得此clazz上的MyService注解
					MyService myService = (MyService) clazz.getAnnotation(MyService.class);
					String serviceName = myService.value();
					Object instance = clazz.newInstance();
					beans.put(serviceName, instance);
				}

			} catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
				e.printStackTrace();
			}
		}
	}

	
	// 第3步:依赖注入(自动装配)
	private void autoInject() {
		if(beans.isEmpty()) {
			System.out.println("没有扫描到任何bean");
			return;
		}

		for(Entry<String,Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();

			Field[] fields = instance.getClass().getDeclaredFields();
			for(Field field : fields) {
				if(field.isAnnotationPresent(MyAutowired.class)) {
					MyAutowired myAutowired = field.getAnnotation(MyAutowired.class);
					String valueOfInject = myAutowired.value();
					Object instanceOfInject = beans.get(valueOfInject);

					field.setAccessible(true);

					try {
						// 最关键的,完成依赖注入
						field.set(instance, instanceOfInject);
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
		}

	}

	// 第4步:处理器映射处理
	private void handlerMapping() {
		if(beans.isEmpty()) {
			System.out.println("没有扫描到任何bean");
			return;
		}

		for(Entry<String,Object> entry : beans.entrySet()) {
			Object instance = entry.getValue();

			if(instance.getClass().isAnnotationPresent(MyController.class)) {
				MyRequestMapping myRequestMappingOfLevel1 = instance.getClass().getAnnotation(MyRequestMapping.class);
				// 获得类上的请求路径
				String mappingOfLevel1 = myRequestMappingOfLevel1.value();

				// 获得此实例对象的所有method
				Method[] methods = instance.getClass().getDeclaredMethods();
				for(Method method : methods) {
					if(method.isAnnotationPresent(MyRequestMapping.class)) {
						MyRequestMapping myRequestMappingOfLevel2 = method.getAnnotation(MyRequestMapping.class);
						// 获得方法上的请求路径
						String mappingOfLevel2 = myRequestMappingOfLevel2.value();

						String allMappingValue = mappingOfLevel1 + mappingOfLevel2;
						System.out.println(allMappingValue);
						handlerMethd.put(allMappingValue, method);
					}
				}
			}
		}
	}

	public MyDispatcherServlet() {
		super();
	}

	protected void doGet(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		System.out.println("doGet()............");

		String uri = request.getRequestURI(); // “/test/index”
		String ctxPath = request.getContextPath(); // 什么都没有
		String path = uri.replace(ctxPath, ""); // “/test/index”
		System.out.println("path.split(\"/\")[0] = " + path.split("/")[0]);
		System.out.println("path.split(\"/\")[1] = " + path.split("/")[1]); // path.split("/")[1] = test

		Method method = (Method) handlerMethd.get(path);
		Object controllerInstance = beans.get("/" + path.split("/")[1]);  // 这里最前面,还要加上一个/
		try {
			Object object = method.invoke(controllerInstance, request,response); // 传入了request和response对象;
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
		}

	}

	protected void doPost(HttpServletRequest request, HttpServletResponse response) 
			throws ServletException, IOException {
		System.out.println("doPost()............");		
	}

}

小结:

a)String realClassName = className.replace(".class", "");
            try {
                Class clazz = Class.forName(realClassName);

     Class.forName() 只能作用于cn.itcast.web.Servlet.MyDispatcherServlet这样的全路径名,

     不能作用于:cn.itcast.web.Servlet.MyDispatcherServlet.class

测试:

【javaweb】自己动手实现简易的springmvc

注意:

a)如果通过chrome浏览器发送请求,中央控制器中代码会发生空指针异常,因为chrome浏览器中有个关于html的插件,导致发送了两次请求;换了IE浏览器测试就好了;

小结:

1)   URL url = getClass().getClassLoader().getResource(path); //  注意path最前面没有/,path = cn/huangyan/spring
        String filePath = url.getFile();
        File[] files = new File(filePath).listFiles();

2)通过反射操作对象,获取Field,Method,set字段的值;

 

 

 

相关文章: