分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 网页技术

一起写框架-MVC框架-基础功能-DispacherServlet控制器的实现(三)

发布时间:2023-09-06 01:24责任编辑:傅花花关键词:MVC

实现功能

开发环境配置好,那么我们可以编写代码了

由于BasicMVC框架的对象交由BasicIOC容器托管,所以启动JavaWeb项目时,将程序所有的对象使用Ioc内核的机制加载到容器池里面。

基于这个原因:我们实现DispacherServlet控制器跳转必须首先完成以下三个动作

1.我们必须在Web启动是创建一个ApplicationContext容器操作对象;

2.我们必须需要一个配置类,来获得创建容器的信息

3.根据请求得路径跳转到对应Controller的对应映射路径的方法

实现步骤

第一步:我们必须需要一个配置类,来获得创建容器的信息

1.实现Web程序启动BasicIoc容器

--在用于测试的web项目,创建一个配置类IocCofing,并在web.xml作为DispacherServlet参数配置,以及编写一个用于测试是否启动了Ioc容器的UserController类

--配置类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代码--

 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 ranger16 ?* @date 2017-11-0817 ?*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 ????@Override29 ????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 ????@Override47 ????protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {48 ?????????System.out.println("-测试成功--");49 ????????super.service(request, response);50 ????}51 }

3.启动index.jsp,点击请求。容器打印出加载的对象内存地址。说明成功。

第二步:根据请求得路径跳转到对应Controller的对应映射路径的方法

确认通过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 @Documented19 public @interface RequestMapping {20 ????/**21 ?????* 没有默认值,表示必须要填写22 ?????* @return23 ?????*/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.创建一个存储指定组件类型的Map10 ????????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 ????@Override37 ????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 ????@Test16 ????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 ranger110 ?????*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 ranger19 ?* @date 2017-11-0820 ?*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 ????@Override31 ????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 ????@Override48 ????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 block61 ????????????e.printStackTrace();62 ????????} catch (IllegalArgumentException e) {63 ????????????// TODO Auto-generated catch block64 ????????????e.printStackTrace();65 ????????} catch (InvocationTargetException e) {66 ????????????// TODO Auto-generated catch block67 ????????????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 @Controller10 public class UserController {11 ????12 ????/**13 ?????* 路径规则:14 ?????* 1.必须包括有/开头15 ?????* 2.后缀必须忽略不写16 ?????* 如:http://localhost:8080/webmvc-demo-test-01/test.do17 ?????* 对应的映射路径为:/test18 ?????* ?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.测试结

一起写框架-MVC框架-基础功能-DispacherServlet控制器的实现(三)

原文地址:http://www.cnblogs.com/zhuyuejiu/p/7820255.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved