開發環境配置好,那麼咱們能夠編寫代碼了html
因爲BasicMVC框架的對象交由BasicIOC容器託管,因此啓動JavaWeb項目時,將程序全部的對象使用Ioc內核的機制加載到容器池裏面。java
基於這個緣由:咱們實現DispacherServlet控制器跳轉必須首先完成如下三個動做web
1.咱們必須在Web啓動是建立一個ApplicationContext容器操做對象;mvc
2.咱們必須須要一個配置類,來得到建立容器的信息app
3.根據請求得路徑跳轉到對應Controller的對應映射路徑的方法框架
1.實現Web程序啓動BasicIoc容器jsp
--在用於測試的web項目,建立一個配置類IocCofing,並在web.xml做爲DispacherServlet參數配置,以及編寫一個用於測試是否啓動了Ioc容器的UserController類ide
|
--配置類IocConfig代碼--測試
1 package org.webmvc.cofig; 2 3 import ioc.core.annotation.ComponentScan; 4 import ioc.core.annotation.Configuration; 5 6 //使用定義@Configuration定義該類是一個配置類 7 @Configuration 8 //使用ComponentScan設置掃描包的路徑 9 @ComponentScan(basePackages={"org.webmvc.controller"}) 10 public class IocConfig { 11 12 }
--web.xml代碼--ui
1 <?xml version="1.0" encoding="UTF-8"?> 2 <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"> 3 <display-name>webmvc-demo-test-01</display-name> 4 <servlet> 5 <servlet-name>dispacherServlet</servlet-name> 6 <servlet-class>ioc.webmvc.DispacherServlet</servlet-class> 7 <init-param> 8 <!-- 設置配置類的類全名 --> 9 <param-name>cofig</param-name> 10 <param-value>org.webmvc.cofig.IocConfig</param-value> 11 </init-param> 12 </servlet> 13 <servlet-mapping> 14 <servlet-name>dispacherServlet</servlet-name> 15 <url-pattern>*.do</url-pattern> 16 </servlet-mapping> 17 </web-app>
-編寫一個用於測試的UserController類--
1 package org.webmvc.controller; 2 3 import ioc.core.annotation.stereotype.Controller; 4 5 @Controller 6 public class UserController { 7 8 public void login(){ 9 System.out.println("-登陸Controller-"); 10 } 11 }
2.編寫BasicMVCMVC框架的DispacherServlet類的init方法。得到配置參數,以及啓動BaiscIoC容器。
|
代碼以下:
1 package ioc.webmvc; 2 3 import java.io.IOException; 4 5 import javax.servlet.ServletConfig; 6 import javax.servlet.ServletException; 7 import javax.servlet.http.HttpServlet; 8 import javax.servlet.http.HttpServletRequest; 9 import javax.servlet.http.HttpServletResponse; 10 11 import ioc.core.impl.AnntationApplicationContext; 12 13 /** 14 * 核心控制,用於攔截全部的請求,MVC框架的入口。 15 * @author ranger 16 * @date 2017-11-08 17 * 18 */ 19 public class DispacherServlet extends HttpServlet { 20 21 private static final long serialVersionUID = -5969172674760020122L; 22 private AnntationApplicationContext contextApplication=null; 23 24 25 /** 26 * 啓動Web程序時,得到配置的參數 27 */ 28 @Override 29 public void init(ServletConfig config) throws ServletException { 30 //1.配置參數是配置類的類全名 31 String parameter = config.getInitParameter("config"); 32 //2.查看是否有參數了 33 System.out.println(parameter); 34 try { 35 //3.將字符串使用反射技術,轉成一個Class類 36 Class<?> classType = Class.forName(parameter); 37 //4.將對象加載到容器裏面 38 this.contextApplication=new AnntationApplicationContext(classType); 39 } catch (ClassNotFoundException e) { 40 e.printStackTrace(); 41 } 42 } 43 44 45 46 @Override 47 protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 48 System.out.println("-測試成功--"); 49 super.service(request, response); 50 } 51 }
3.啓動index.jsp,點擊請求。容器打印出加載的對象內存地址。說明成功。
確認經過web程序啓動就可使用BaiscIoc容器託管全部對象後。
咱們須要理解請求能夠找到對應的執行方法這個問題?
要解決這個問題,必需要有一個地方標識請求路徑和方法的關係。這裏我經過一個@RequestMapping註解來標識請求路徑和執行方法的關係。
(1)在業務控制器設置標識方法對應請求路徑的註解(@RequestMapping),必須指定映射路徑
(2)請求到核心控制器是掃描全部業務控制器。得到對應的方法。
1. 定義一個註解RequestMapping來聲明路徑與方法的關係
1 package ioc.webmvc.annotation; 2 3 import java.lang.annotation.Documented; 4 import java.lang.annotation.ElementType; 5 import java.lang.annotation.Retention; 6 import java.lang.annotation.RetentionPolicy; 7 import java.lang.annotation.Target; 8 9 @Retention(RetentionPolicy.RUNTIME) 10 /* 11 * 12 * 指定能夠在方法以及類上面使用面使用 13 * 1.在方法上面,指定請求路徑 14 * 2.在類上面用於指定命名空間 15 */ 16 17 @Target(value={ElementType.METHOD,ElementType.TYPE}) 18 @Documented 19 public @interface RequestMapping { 20 /** 21 * 沒有默認值,表示必需要填寫 22 * @return 23 */ 24 String value(); 25 26 }
2.得到全部Controller類型的對象。用於判斷路徑對應的方法。
在容器的實現類ContextImpl裏面增長一個檢索業務控制器對象的方法。
實現方式分爲兩步:標紅的代碼
(1)在容器定義接口中定義一個方法
package ioc.core; import java.util.Map; /** * Ioc框架的容器接口 * @author ranger * */ public interface Context { /** * 用於得到容器中的全部對象 * @return */ Map<String,Object> getObjects(); /** * 用於得到容器中的全部業務控制器對象 * @return */ Map<String,Object> getControllerObjects(); /** * 用於增長容器中的對象 * @param key * @param value */ void addObject(String key, Object value); /** * 根據類的類型以及設置的對象名返回容器對象 * 若是傳入的類型容器中有對應key的對象,並且返回類型是兼容的,直接返回對應的對象。 * 若是傳入的類型容器中有沒有對應key的對象,那麼判斷傳入的類型是否和容器的對象的找到惟一配置的。 * 若是傳入類型惟一匹配,返回對象。若是沒有或者配配多個對象,都報一個RuntimeException異常 * @param classType * @return */ Object getObject(Class<?> classType,String key); }
(2)在實現類ContextImpl實現該方法,先增長一個getObjectsByComponentType方法編寫經過組件註解類型返回對象,再實現getControllerObjects()方法。
1 /** 2 * 用於經過傳入標識組件類型的註解,返回對應類型的註解 註解類型分別爲: Controller Service Repository 3 * Component 4 * 5 * @param componentsType 6 * @return 7 */ 8 public Map<String, Object> getObjectsByComponentType(Class<? extends Annotation> componentsType) { 9 // 1.建立一個存儲指定組件類型的Map 10 Map<String, Object> componentsObjects = new HashMap<String, Object>(); 11 // 2.得到全部的容器對象 12 Map<String, Object> objects = this.getObjects(); 13 // 3.得到Map中全部的對象的Set集合 14 Set<Entry<String, Object>> entrySet = objects.entrySet(); 15 // 4.得到Set集合迭代器 16 Iterator<Entry<String, Object>> iterator = entrySet.iterator(); 17 // 5.循環判斷 18 while (iterator.hasNext()) { 19 Entry<String, Object> entry = iterator.next(); 20 // 6.得到當前對象的類類型,用於得到該類的類結構中的組件註解 21 Class<?> classType = entry.getValue().getClass(); 22 // 7.容器裏的對象是不是指定註解類型的,若是是加入到componentsObjects中 23 Annotation annotation = classType.getDeclaredAnnotation(componentsType); 24 if (annotation != null) { 25 componentsObjects.put(entry.getKey(), entry.getValue()); 26 } 27 28 } 29 // 8.返回指定組件類型的對象 30 return componentsObjects; 31 } 32 33 /** 34 * 返回業務控制器Controller註解類型的全部對象 35 */ 36 @Override 37 public Map<String, Object> getControllerObjects() { 38 return this.getObjectsByComponentType(Controller.class); 39 }
3.測試代碼得到的getObjectsByComponentType方法是否成功,輸出指定的類型對象,說明成功。
1 package ioc.core.test; 2 3 import java.util.Map; 4 5 import org.junit.Test; 6 7 import ioc.core.annotation.stereotype.Service; 8 import ioc.core.impl.AnntationApplicationContext; 9 import ioc.core.impl.ContextImpl; 10 import ioc.core.test.config.Config; 11 12 public class ContextImplTest { 13 14 15 @Test 16 public void getObjectsByComponentsType(){ 17 AnntationApplicationContext applicationContext=new AnntationApplicationContext(Config.class); 18 ContextImpl context = (ContextImpl) applicationContext.getContext(); 19 Map<String, Object> componentObjects = context.getObjectsByComponentType(Service.class); 20 System.out.println(componentObjects+"=========================="); 21 22 } 23 24 }
--測試結果,輸出的就是指定類型的對象
3.得到頁面的請求路徑匹配Controller對象中的方法的路徑。
--建立一個ControllerRelolver類編寫,檢索方法的@RequestMapping註解
1 package ioc.webmvc.impl; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.util.Collection; 6 import java.util.Iterator; 7 import java.util.Map; 8 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import ioc.core.Context; 13 import ioc.webmvc.annotation.RequestMapping; 14 15 public class ControllerRelolver { 16 17 /** 18 * 經過傳入的參數,執行路徑對應的業務控制器(Controller)的方法 19 * @param request 20 * @param response 21 * @param context 22 * @return 23 * @throws IllegalAccessException 24 * @throws IllegalArgumentException 25 * @throws InvocationTargetException 26 */ 27 public String execute(HttpServletRequest request,HttpServletResponse response,Context context) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException{ 28 //1.得到請求過來的路徑 29 String uri = request.getRequestURI(); 30 //2.根據路徑規則,得到映射路徑 31 String path = this.pathRule(uri); 32 //3.經過路徑得到容器中對應的業務控制器的對象和執行方法 33 MappingEnttiy mappingEnttiy = this.getRequestMethod(path, context); 34 //4.得到執行方法 35 Method method = mappingEnttiy.getMethod(); 36 //5.得到路徑對應的業務控制器 37 Object controller = mappingEnttiy.getController(); 38 //6.執行方法,執行方法必須有request,response兩個參數 39 Object resultObject = method.invoke(controller, request,response); 40 if(resultObject!=null){ 41 //7.返回執行方法返回的映射字符串 42 return (String) resultObject; 43 } 44 return null; 45 } 46 /** 47 * 設置路徑的規則 48 * 路徑規則爲,保留/,去掉後綴。 49 * 如: 50 * 請求路徑:http://localhost:8080/webmvc-demo-test-01/test.do 51 * 合法的映射路徑爲:/test 52 * 53 * @param url 傳入的爲請求路徑 54 * @return 符合規則的路徑字符串 55 * 56 */ 57 private String pathRule(String url){ 58 //1.建立一個String構建字符串 59 StringBuilder sb=new StringBuilder(url); 60 System.out.println(url); 61 //2.刪除路徑最後一個/以前的全部字符 62 sb.delete(0, url.lastIndexOf("/")); 63 System.out.println(sb.toString()+"刪除後的字符串長度:"+sb.length()); 64 //3.刪除(.)後面的後綴 65 sb.delete(sb.lastIndexOf("."),sb.length()); 66 return sb.toString(); 67 } 68 69 /** 70 * 經過路徑得到對應的業務控制器對象和執行方法 71 * @param path 72 * @param context 73 * @return 74 */ 75 private MappingEnttiy getRequestMethod(String path,Context context){ 76 //1.得到Controller全部的Controller對象 77 Map<String, Object> controllerObjects = context.getControllerObjects(); 78 System.out.println("-getRequestMethod-業務控制器對象池:"+controllerObjects); 79 //2.得到業務控制器池裏面的全部值 80 Collection<Object> values = controllerObjects.values(); 81 //3.遍歷 82 Iterator<Object> iterator = values.iterator(); 83 while (iterator.hasNext()) { 84 //4.得到業務控制器池中當前對象 85 Object object = iterator.next(); 86 //5.得到當前對象的類類類型 87 Class<? extends Object> classType = object.getClass(); 88 //6.經過對象的類類型,得到對象的方法列表 89 Method[] methods = classType.getMethods(); 90 //7.循環判斷方法是否有RequestMapping註解 91 for(Method method:methods){ 92 RequestMapping mapping = method.getDeclaredAnnotation(RequestMapping.class); 93 //8.RequestMapping註解存在,並且等於映射路徑,返回該方法的方法和當前對象 94 if(mapping!=null&&mapping.value().equals(path)){ 95 //9.聲明內部類MappingEnttiy來封裝映射的方法和對象。建立這個類的對象 96 MappingEnttiy entity=new MappingEnttiy(); 97 entity.setController(object); 98 entity.setMethod(method); 99 return entity; 100 } 101 } 102 103 } 104 105 return null; 106 } 107 /** 108 * 聲明一個私有的內部類對象,用於存儲執行檢索業務控制器時返回的數據 109 * @author ranger 110 * 111 */ 112 private class MappingEnttiy{ 113 //1.當前映射路徑對應的對象 114 private Object controller; 115 //2.當前映射路徑對應的方法 116 private Method method; 117 118 public Object getController() { 119 return controller; 120 } 121 public void setController(Object controller) { 122 this.controller = controller; 123 } 124 public Method getMethod() { 125 return method; 126 } 127 public void setMethod(Method method) { 128 this.method = method; 129 } 130 131 } 132 }
4.核心控制器(DispacherServlet)調用這個業務控制解釋器(ControllerRelolver),標紅處
1 package ioc.webmvc; 2 3 import java.io.IOException; 4 import java.lang.reflect.InvocationTargetException; 5 6 import javax.servlet.ServletConfig; 7 import javax.servlet.ServletException; 8 import javax.servlet.http.HttpServlet; 9 import javax.servlet.http.HttpServletRequest; 10 import javax.servlet.http.HttpServletResponse; 11 12 import ioc.core.impl.AnntationApplicationContext; 13 import ioc.webmvc.impl.ControllerRelolver; 14 15 /** 16 * 核心控制,用於攔截全部的請求,MVC框架的入口。 17 * 18 * @author ranger 19 * @date 2017-11-08 20 * 21 */ 22 public class DispacherServlet extends HttpServlet { 23 24 private static final long serialVersionUID = -5969172674760020122L; 25 private AnntationApplicationContext contextApplication = null; 26 27 /** 28 * 啓動Web程序時,得到配置的參數 29 */ 30 @Override 31 public void init(ServletConfig config) throws ServletException { 32 // 1.配置參數是配置類的類全名 33 String parameter = config.getInitParameter("config"); 34 // 2.查看是否有參數了 35 System.out.println(parameter); 36 try { 37 // 3.將字符串使用反射技術,轉成一個Class類 38 Class<?> classType = Class.forName(parameter); 39 // 4.將對象加載到容器裏面 40 this.contextApplication = new AnntationApplicationContext(classType); 41 42 } catch (ClassNotFoundException e) { 43 e.printStackTrace(); 44 } 45 } 46 47 @Override 48 protected void service(HttpServletRequest request, HttpServletResponse response) 49 throws ServletException, IOException { 50 51 52 ControllerRelolver rs = new ControllerRelolver(); 53 try { 54 String result= rs.execute(request, response, contextApplication.getContext()); 55 if(result!=null){ 56 //返回執行方法 57 request.getRequestDispatcher(result).forward(request, response); 58 } 59 } catch (IllegalAccessException e) { 60 // TODO Auto-generated catch block 61 e.printStackTrace(); 62 } catch (IllegalArgumentException e) { 63 // TODO Auto-generated catch block 64 e.printStackTrace(); 65 } catch (InvocationTargetException e) { 66 // TODO Auto-generated catch block 67 e.printStackTrace(); 68 } 69 } 70 }
1.測試的Web項目代碼目錄
2.代碼以下
--IocConfig--
1 package org.webmvc.cofig; 2 3 import ioc.core.annotation.ComponentScan; 4 import ioc.core.annotation.Configuration; 5 6 //使用定義@Configuration定義該類是一個配置類 7 @Configuration 8 //使用ComponentScan設置掃描包的路徑 9 @ComponentScan(basePackages={"org.webmvc.controller"}) 10 public class IocConfig { 11 12 }
--UserController--
1 package org.webmvc.controller; 2 3 import javax.servlet.http.HttpServletRequest; 4 import javax.servlet.http.HttpServletResponse; 5 6 import ioc.core.annotation.stereotype.Controller; 7 import ioc.webmvc.annotation.RequestMapping; 8 9 @Controller 10 public class UserController { 11 12 /** 13 * 路徑規則: 14 * 1.必須包括有/開頭 15 * 2.後綴必須忽略不寫 16 * 如:http://localhost:8080/webmvc-demo-test-01/test.do 17 * 對應的映射路徑爲:/test 18 * 19 */ 20 @RequestMapping(value = "/login") 21 public String login(HttpServletRequest request,HttpServletResponse response){ 22 System.out.println("-登陸Controller-"); 23 return "/login.jsp"; 24 25 } 26 27 }
---請求頁面index.jsp--
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <a href="${pageContext.request.contextPath }/login.do">test</a> </body> </html>
---返回頁面login.jsp--
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>Insert title here</title> 8 </head> 9 <body> 10 登陸成功! 11 </body> 12 </html>
2.測試結
|