Springmvc入门(十七)手写简易springmvc

目录

1.先编写@Controller和@RequestMapping注解

2.实现DispatcherServlet

3.编写Controller测试类

4.注册使用自定义的DispatcherServlet


根据前文中,我们了解到DispatcherServlet其实就是个servlet,首先他先进行初始化,将所有HandlerMapping进行缓存(Map存储),初始化其他各种组件。它将请求的处理都集中到doDispatch方法,交由HandlerMapping去找到对应的处理的method,HandlerAdapter去调用这个method,所以HandlerAdapter就相当于反射执行方法,但是这里包含比较多的参数赋值,请求路径的参数,session中的参数等等,然后返回ModelAndView,ViewResolver解析视图,渲染视图等等之后返回给用户。我们如何来实现一个简易的springmvc框架。

1.先编写@Controller和@RequestMapping注解

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

2.实现DispatcherServlet


import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

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

import org.apache.jasper.tagplugins.jstl.core.Param;

import springmvc.myspringmvc.annotation.MyController;
import springmvc.myspringmvc.annotation.MyRequestMapping;

public class MyDispatcherServlet extends HttpServlet {
    //需要扫描的包,这里就固定了,有需要的可以在文件中配置读取
	private String packageName = "springmvc.myspringmvc.controller";
	// ioc容器
	private Map<String, Object> iocMap = new HashMap<>();
	// url -> method进行映射
	private Map<String, Object> handlerMapping = new HashMap<>();
	// url -> 类的对象进行映射
	private Map<String, Object> urlMapping = new HashMap<>();

	@Override
	public void init() throws ServletException {
		// 先进行初始化
		// 1.扫描包中所有的类,然后如果此类的注解是@MyController的类进行加载
		Long startTime = System.currentTimeMillis();
		initClass(packageName);
		Long endTime = System.currentTimeMillis();
		// 2.对@MyRequestMapping的注解进行加载
		initHandle();
	}

	private void initHandle() {
		// 从ioc容器中所有的类进行遍历
		iocMap.forEach((key, value) -> {
			String path = "";
			Class<?> clazz = null;
			try {
				clazz = Class.forName(key);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
			// 判断此类是不是有@MyRequestMapping的注解
			if (clazz != null && clazz.isAnnotationPresent(MyRequestMapping.class)) {
				// 获取标签中的值
				path += clazz.getAnnotation(MyRequestMapping.class).value();
			}
			// 获取类中所有的method
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				// 判断方法上是否有有@MyRequestMapping的注解
				if (method.isAnnotationPresent(MyRequestMapping.class)) {
					String url = path + method.getAnnotation(MyRequestMapping.class).value();
					urlMapping.put(url, value);
					handlerMapping.put(url, method);
				}
			}
		});

	}

	private void initClass(String packageName) {
		System.out.println(packageName);
		URL uri = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
		// 扫描路径下的文件
		File directory = new File(uri.getFile());
		// 如果扫描到的是文件夹,则递归扫描
		for (File file : directory.listFiles()) {
			System.out.println(packageName + " " + file.getName());
			if (file.isDirectory()) {
				initClass(packageName + "." + file.getName());
			} else {
				String className = packageName + "." + file.getName();
				try {
					if (className.lastIndexOf(".class") != -1 || className.lastIndexOf(".class") != -1) {
						className = className.substring(0, className.lastIndexOf("."));
					}
					Class<?> clazz = Class.forName(className);
					// 判断类是不是有@MyController注解
					if (clazz.isAnnotationPresent(MyController.class)) {
						// 进行初始化,确保是单例对象
						if (iocMap.get(className) == null) {
							Object obj = clazz.newInstance();
							iocMap.put(className, obj);
						}
					}
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				} catch (InstantiationException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}

	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		try {
			doDispatch(req, resp);
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
			e.printStackTrace();
		}
	}

	private void doDispatch(HttpServletRequest req, HttpServletResponse resp)
			throws IOException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		String url = req.getRequestURI();
		String context = req.getContextPath();
		// 去掉请求路径的前缀
		url = url.replaceAll(context, "");
		if (urlMapping.get(url) != null) {

			// 获取method
			Method method = (Method) handlerMapping.get(url);
			// 获取method的参数类型
			Class[] parameters = method.getParameterTypes();
			// 获取请求的参数
			Map<String, String[]> reqMap = req.getParameterMap();
			// 作为反射时传入方法的value值
			Object[] values = new Object[parameters.length];
			int i = 0;
			for (Class clazz : parameters) {
				String requestParam = clazz.getSimpleName();
				if (requestParam.equals("HttpServletRequest")) {
					values[i++] = req;
				} else if (requestParam.equals("HttpServletResponse")) {
					values[i++] = resp;
				} else {
					int flag = i;
					reqMap.forEach((k, v) -> {
						String val = Arrays.toString(v).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
						values[flag] = val;
					});
					i++;
				}
			}
			// 反射执行方法
			method.invoke(urlMapping.get(url), values);
		} else {
			resp.getWriter().println("404,resource not find");
		}
	}
}

3.编写Controller测试类


import java.io.IOException;

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

import org.springframework.http.HttpRequest;

import springmvc.myspringmvc.annotation.MyController;
import springmvc.myspringmvc.annotation.MyRequestMapping;

@MyController
public class MyControllerTest {

	@MyRequestMapping("/test")
	public void test(HttpServletRequest request, HttpServletResponse response, String username) {
		try {
			response.getWriter().println("success, this is test,username = " + username);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@MyRequestMapping("/ok")
	public void ok(HttpServletRequest request, HttpServletResponse response) {
		try {
			response.getWriter().println("success,this is ok");
		} catch (IOException e) {
			e.printStackTrace();
		}

	}
}

4.注册使用自定义的DispatcherServlet

        <servlet>
		<servlet-name>mySpringmvc</servlet-name>
		<servlet-class>springmvc.myspringmvc.servlet.MyDispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>mySpringmvc</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

5.测试

先来测试个不存在的,因为自定义的DispatcherServlet没有实现视图解析器,所以访问视图也是无法访问的,因为被我们的DispatcherServlet拦截了。

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SpringMVC是一个基于Java的Web框架,可以帮助我们快速地构建Web应用程序。下面是一个简单的SpringMVC入门示例,让你了解如何编写一个SpringMVC应用程序。 1. 创建Maven项目 首先,我们需要创建一个Maven项目。在Eclipse或者IntelliJ IDEA中,选择创建一个Maven项目,并添加SpringMVC依赖。 2. 配置web.xml 在web.xml文件中,我们需要配置DispatcherServlet。DispatcherServlet是SpringMVC的核心组件,它拦截所有的请求并将它们分发给相应的控制器。 ```xml <web-app> <display-name>Spring MVC Application</display-name> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> ``` 在这个配置中,我们将DispatcherServlet的URL模式设置为"/",这意味着它将拦截所有的请求。contextConfigLocation参数指定了Spring配置文件的路径。 3. 配置dispatcherServlet-servlet.xml 在dispatcherServlet-servlet.xml文件中,我们需要配置SpringMVC相关的组件,例如控制器、视图解析器等等。 ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" 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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.example.controller" /> <mvc:annotation-driven /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/views/" /> <property name="suffix" value=".jsp" /> </bean> </beans> ``` 在这个配置中,我们使用<context:component-scan>扫描了我们的控制器所在的包。我们还使用<mvc:annotation-driven>启用了SpringMVC的注解驱动,并使用<bean>配置了一个视图解析器,将逻辑视图名映射为物理视图。 4. 编写控制器 ```java @Controller public class HelloController { @RequestMapping("/") public String hello() { return "hello"; } } ``` 在这个示例中,我们编写了一个控制器,使用@RequestMapping注解将"/"映射到hello()方法。hello()方法返回一个字符串"hello",这代表逻辑视图名。当DispatcherServlet收到一个请求并且URL匹配"/"时,它将会调用hello()方法,然后将逻辑视图名"hello"映射为物理视图名"/WEB-INF/views/hello.jsp"。 5. 编写视图 在"/WEB-INF/views/"目录下创建一个名为"hello.jsp"的JSP文件。 ```html <!DOCTYPE html> <html> <head> <title>Hello SpringMVC</title> </head> <body> <h1>Hello SpringMVC</h1> </body> </html> ``` 6. 运行应用程序 将应用程序部署到一个Web服务器上,并访问"http://localhost:8080/",你应该会看到一个"Hello SpringMVC"的页面。 以上就是一个简单的SpringMVC入门示例,希望能帮助你快速入门SpringMVC框架。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值