SpringMVC的核心实现

实现效果:实现在浏chrom输入地址localhost:8080/toLogin.do进入servlet最终转发到html页面

项目包

springmvc简单案例 springmvc案例代码_springmvc简单案例

实现步骤

# # 一:创建@RequestMapping注解->用于实现SpringMVC中的@RequestMapping注解

@Retention(RUNTIME)
	public @interface RequestMapping {
	
		public String value () default "";
	
	
	}

解释:
1)@Retention(RUNTIME)表示注解在运行期间有效
2)public String value () default中的value()为SpringMVC中的\hello
例:@RequestMapping("/toLogin.do")

# # 二:创建Handler类->方便利用java反射机制去调用一个对象的方法而设计的一个辅助类

Handler封装了:处理器实例已经对应的Method对象

public class Handler {
		// obj:处理器实例
		private Object obj;
		// mh:方法
		private Method mh;
		public Object getObj() {
			return obj;
		}
		public void setObj(Object obj) {
			this.obj = obj;
		}
		public Method getMh() {
			return mh;
		}
		public void setMh(Method mh) {
			this.mh = mh;
		}
		

	}

解释:
1)Object:存放处理器实例
2)Method:存放处理其实例中的方法

# # 三:创建HandlerMapping类->映射处理器->负责建立请求路径与处理器的对应关系

例:"/hello.do"应该由HelloControllerhello方法来处理
类设计:
成员变量:private Map<String,Handler>maps=new HashMap();
方法一·:public void process(List beans)
方法二· public Handler getHandler(String path)
1)maps用于存放请求路径和Handler的对应关系 key为请求路径 value为Handler对象

private Map<String,Handler>maps=new HashMap();

2)``HadlerMapping中核心方法process(List beans)`:负责变量存放对应关系

// 传入DispatcherServlet中获得的List集合:List集合为处理器实例
   public void process(List beans) {
   		// for循环获取每一个处理器实例
   		for(Object bean:beans) {
   			// 反射拿到所有方法
   			Method[]methods=bean.getClass().getDeclaredMethods();
   			// 遍历获得的方法
   			for(Method mh:methods) {
   				// 获取加在方法前的@RequestMapping注解
   				RequestMapping rm=mh.getDeclaredAnnotation(RequestMapping.class);
   				// 如果注解为空就说明没有找到合适的处理器,为空
   				if(rm!=null) {
   					// 获取注解中的value 请求路径 /*.do
   					String path=rm.value();
   					// 将method对象以及处理器实例封装到Handler对象
   					Handler handler=new Handler();
   					handler.setMh(mh);
   					handler.setObj(bean);
   					// 以请求路径作为key,以Handler对象作为value
   					// 将对应关系添加到map里
   					maps.put(path,handler);
   					
   				}
   			}
   		}
   		System.out.println("maps:"+maps);
   	}

3)HadlerMappingget方法getHandler(String path)根据请求路径获取对应的处理器Handler

public Handler getHandler(String path) {
   		return maps.get(path);
   }

# # 四:DispatcherServlet方法也是SpringMVC中的核心方法,负责处理分发请求(前端控制器)DispatcherServlet为一个Servlet

成员变量:private HandlerMapping handlerMapping;
方法一:public void init() throws ServletException {}初始化方法
方法二:protected void service(HttpServletRequest request, HttpServletResponse response) {}用于分发请求
1)handlerMapping为存储请求路径value和处理的关系handler

private HandlerMapping handlerMapping;

2)DispatcherServlet中核心方法也是初始化方法:用dom4j解析smartmvc.xml文件获取类全路径名,之后反射,存储Handler已经HandlerMapping也是一个初始化方法

public void init() throws ServletException {
			try {
				SAXReader saxReader=new SAXReader();
				InputStream in=getClass()
						.getClassLoader()
						.getResourceAsStream("smartmvc.xml");
				Document doc=saxReader.read(in);
				// 获得根元素 <beans></beans>
				Element root=doc.getRootElement();
				// 获得根元素下面的所有子元素
				List beans=new ArrayList();
				List<Element>elements=root.elements();
				for(Element ele:elements) {
					// 获取处理器类名
					String className=ele.attributeValue("class");
					System.out.println("className:"+className);
					// 将处理器实例化
					Object bean=Class.forName(className);
					System.out.println(bean);
					beans.add(bean);
				}
				// 将处理器实例交给HandlerMapping来处理
				handlerMapping=new HandlerMapping();
				handlerMapping.process(beans);
				
			} catch (Exception e) {
				System.out.println("初始化失败:"+e);
				e.printStackTrace();
			}
		}

2.5)smartmvc.xml代码如下

<?xml version="1.0" encoding="UTF-8"?>
	<beans>
		<!--
			配置处理器,其中,class属性用于指定处理器类名
		-->
		<bean class="controller.HelloController"/>
		<bean class="controller.LoginController"/>
	</beans>

xml文件通常存储反射对象的全路径名
3)DispatcherServlet中处理请求方法也是servlet中的处理业务的方法

@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		try {
			// 现获得请求资源路径
			String uri=request.getRequestURI();
			System.out.println("uri:"+uri);
			// 获得应用名
			String contextPath=request.getContextPath();
			System.out.println("contextPath:"+contextPath);
			// 将请求路径中到应用名截取掉,生成请求路径
			String path=uri.substring(contextPath.length());
			System.out.println("path:"+path);
			
			// 依据请求路径获取对应掉Handler对象
			Handler handler=handlerMapping.getHandler(path);
			if(handler==null) {
				response.sendError(404);
				System.out.println("没有对应到处理器");
				return;
			}
			Object bean=handler.getObj();
			Method mh=handler.getMh();
			/**
			 * 获取处理器的方法
			 * 先获得处理器方法的参数类型信息
			 */
			Class[]types=mh.getParameterTypes();
			// 获得返回值
			Object rv=null;
			if(types.length>0) {
				// params用于存放实际参数
				Object[]params=new Object[types.length];
				// 依据参数类型进行相应的赋值
				for(int i=0;i<types.length;i++) {
					if(types[i]==HttpServletRequest.class) {
						params[i]=request;
					}
					if(types[i]==HttpServletResponse.class) {
						params[i]=response;
					}
				}
				// 处理器方法带参数
				rv=mh.invoke(bean, params);
			}else {
				// 处理器方法不带参数
				rv=mh.invoke(bean);
			}		
			// 获得视图名
			String viewName=rv.toString();
			System.out.println("viewName:"+viewName);
			/*
			 * 处理视图名
			 * 如果视图名是以"redirect:"开头,则重定向,否则
			 * 默认转发到 "/WEB-INF/"+视图名+".jsp"
			 */
			if(viewName.startsWith("redirect:")) {
				// 生成重定向地址
				String redirectPath=contextPath+"/"+viewName.substring("redirect:".length());
				// 重定向
				response.sendRedirect(redirectPath);
			}else {
				// 生成转发地址
				String forwardPath="/WEB-INF/"+viewName+".jsp";
				// 转发
				request.getRequestDispatcher(forwardPath).forward(request, response);
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new ServletException(e);
		}
		
	}

# # 五:编写Controller类进行测试HelloController

public class HelloController {
		
		@RequestMapping(value = "/hello.do")
		public String hello() {
			System.out.println("HelloController hello()");
			// 返回视图名
			return "hello";
		}	
	}

hello.jsp代码

<%@ page language="java" contentType="text/html; charset=UTF-8"
	    pageEncoding="UTF-8"%>
	<!DOCTYPE html>
	<html>
	<head>
	<meta charset="UTF-8">
	<title>Insert title here</title>
	</head>
	<body>
		Hello SmartMVC
	</body>
	</html>

测试:在Chrom地址栏中敲入localhost:8080/hello.do就可以直接转发到hello.jsp了完成了SpringMVC的核心实现

实现思路:根据反射的api m.invoke(obj) m为方法 obj为类实例->通过Handler存储m和obj->HandlerMapping存储url和Handler的对应关系
最终实现(凑齐)m.invoke(obj)的参数实现代码