SpringMVC配置及底层原理
-
导入SpringMVC jar包
-
配置总(前端)控制器 web.xml
-
加入SpringMVC配置文件 src/appContext.xml
-
编写Controller 和 处理连接及方法
SpringMVC底层原理的模仿
1). 导入jar包用于解析xml文档
2). 写一个MyDispatcherServlet完成SpringMVC前端控制器DispatcherServlet的加载和运行时作用:
服务器启动时加载appContext.xml文件
MyDispatcherServlet类的编写注意
//加载时
/*
url接口 对应类方法字符串(urlStrMap)保存到 application 中
1. /fff.do com.senchen.controller.FirstController#f1
/sss.do com.senchen.controller.SecondController#s1
2. 反射出类型保存在一个 spring容器Map中 application 中
key(com.senchen.controller.FirstController) value( 实例 )
*/
1.获取SpringMVC配置文件的名字
String fileName = getInitParameter("ccc");
2.获得项目路径
System.out.println("1.." + getServletContext().getRealPath("")); //当前项目路径
System.out.println("1.." + getServletContext().getRealPath("/")); //当前项目路径
System.out.println("2.." + this.getClass().getResource("").getPath()); //当前类路径
System.out.println("2.." + this.getClass().getResource("/").getPath()); //当前项目的classes目录,最前面有个':'
3.去掉:后确定SpringMVC配置文件的位置
String webPath = this.getClass().getResource("/").getPath().substring(1);
String xmlPath="";
if( fileName.toLowerCase().startsWith( "classpath")){
xmlPath = webPath + fileName.substring( fileName.indexOf(":")+1 ); //
}else if( fileName.toLowerCase().startsWith("/web-inf")){
xmlPath = getServletContext().getRealPath("")+fileName;
}else {
xmlPath = fileName;
}
System.out.println(fileName+"!!!日志1.启动时读到 xml 目录位置: "+ xmlPath);
4.放置 urlStrMap 和 spring实例容器
//url 和 对应的字符串集合
Map<String,String> urlStrMap = new HashMap<String, String>();
this.getServletContext().setAttribute("URLMap", urlStrMap); //application.setAttribute
//handlerMapping
//spring容器集合
Map<String,Object> springIoc = new HashMap<String, Object>();
this.getServletContext().setAttribute("springMap", springIoc);//application.setAttribute
//web_application_context_attribute
5.读取XML文档 获得
url->fff
classPath->com.senchen.controller.FirstController
mdName->f1
<bean name="fff" class="com.senchen.controller.FirstController" method="f1"/>
urlStrMap中放入键:url,值:clsPath+"#"+mdName 方法
springIoc中放入键:url,值:Class.forName(clsPath)实例对象
//读取xml文档
SAXBuilder saxBuilder = new SAXBuilder();
InputStream in;
try {
// 1.创建一个输入流,将xml文件加载到输入流中
in = new FileInputStream( xmlPath );
InputStreamReader isr = new InputStreamReader(in, "UTF-8");
// 2.通过saxBuilder的build方法,将输入流加载到saxBuilder中
Document document = saxBuilder.build(isr);
// 3.通过document对象获取xml文件的根节点
Element rootElement = document.getRootElement();
System.out.println("!!!日志2...xml根:" + rootElement.getName() );
// 4.获取根节点下的子节点的List集合
List<Element> firstList = rootElement.getChildren();
for(Element bn :firstList){
String url = bn.getAttributeValue("name").trim();
String clsPath = bn.getAttributeValue("class").trim();
String mdName = bn.getAttributeValue("method").trim();;
System.out.println("!!!日志3...Mapped URL path ["+url+"] onto handler '"+clsPath+"'");
urlStrMap.put(url, clsPath+"#"+mdName); //urlMap
springIoc.put(url, Class.forName(clsPath).newInstance()); //spring实例Map
运行时的作用
//运行时
/*
A.运行 Dispatcher 接到 .do请求
B.截取出 /fff.do
C.找 application中的 urlStrMap
取出 类型 字符串,和 方法 f1
D.找application 中的spring容器中 的类型字符串 对应的 实例
E.f1.invoke
*/
1.接收到request.getRequestURI//.do请求例 tj1.1/fff.do
2.截取’/‘和’.'之间的url
String start = coming.substring( coming.lastIndexOf("/")+1 , coming.lastIndexOf(".") );
3.从ServletContext域中获得spring容器集合得到实例对象
Map<String,Object> spMap = (Map)this.getServletContext().getAttribute("springMap");
Object controller = spMap.get( start ); // fff
从ServletContext域中获得URLMap集合通过’#'截取出全类名和方法名
Map<String,String> urlMap = (Map)this.getServletContext().getAttribute("URLMap");
String claMd = urlMap.get( start ); // com.senchen.controller.FirstController#f1
String clsName = claMd.substring(0, claMd.lastIndexOf("#")); //com.senchen.controller.FirstController
String methodName = claMd.substring( claMd.lastIndexOf("#")+1 ); //f1
System.out.println("+++日志3..urlMap取出类 "+clsName +" 方法" + methodName);
4.通过反射和全类名得到对象类型
通过类型,方法名,反射得到方法
方法.invoke(实例对象)执行方法
//反射 类型
Class clxx = Class.forName( clsName );
//反射 方法
Method md = clxx.getMethod( methodName );
//调用 方法接收 返回值
Object ret = md.invoke( controller );
5.返回的处理判断是否重定向
//返回处理
if( null !=ret ){
String retView = (String)ret;
if( retView.startsWith("redirect")){ //重定向
response.sendRedirect( request.getContextPath() + retView.substring( retView.lastIndexOf(":")+1 ) );
}else{ //转发
request.getRequestDispatcher( retView ).forward(request, response);
}
}
6.appContext.xml配置文件
不用注解
用注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.senchen.controller"/>
<!-- url接口 对应类方法字符串(urlStrMap)保存到 application 中
1. /fff.do com.senchen.controller.FirstController#f1
/sss.do com.senchen.controller.SecondController#s1
2. 反射出类型保存在一个 spring容器Map中 application 中
key(com.senchen.controller.FirstController) value( 实例 )
A.运行 Dispatcher 接到 .do请求
B.截取出 /fff.do
C.找 application中的 urlStrMap
取出 类型 字符串,和 方法 f1
D.找application 中的spring容器中 的类型字符串 对应的 实例
E.f1.invoke
-->
<!-- 试图解析器 springMVC管理的jsp文件位置应该在 /WEB-INF/meto/ -->
<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/meto/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
概述
服务器启动时,把appContext.xml配置文件的名字存到<param-name>xxx</param-name>
xxx中,并且MyDispatcherServlet类也加载了执行init方法得到配置文件名,最后获得文件路径,然后解析xml文件得到url:访问路径,clsPath:类的全限定名,mdName:方法名,把他们保存到两个Map集合中,实例对象放在Spring容器中
urlStrMap.put(url, clsPath+"#"+mdName); //urlMap
springIoc.put(url, Class.forName(clsPath).newInstance() ); //spring实例Map
以上是模仿处理器映射器HandlerMapping
访问时,service方法把访问路径截取成集合里的url字符串,获得对应的全类名,方法名和实例对象,然后通过反射获得对象的类型和方法,执行之,
对于返回值,可以根据返回的字符串截取判断是重定向还是转发
以上是模仿处理器适配器HandlerAdapter