package com.liugh.servlet;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.liugh.annotation.MyController;
import com.liugh.annotation.MyRequestMapping;
public class MyDispatcherServlet extends HttpServlet {
private Properties properties = new Properties();
private List<String> classNames = new ArrayList<>();
private Map<String, Object> ioc = new HashMap<>();
private Map<String, Method> handlerMapping = new HashMap<>();
private Map<String, Object> controllerMap = new HashMap<>();
@Override
public void init(ServletConfig config) throws ServletException {
// 1.加载配置文件
doLoadConfig(config.getInitParameter("contextConfigLocation"));
// 2.初始化所有相关联的类,扫描用户设定的包下面所有的类
doScanner(properties.getProperty("scanPackage"));
// 3.拿到扫描到的类,通过反射机制,实例化,并且放到ioc容器中(k-v beanName-bean) beanName默认是首字母小写
doInstance();
// 4.初始化HandlerMapping(将url和method对应上)
initHandlerMapping();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
// 处理请求
doDispatch(req, resp);
} catch (Exception e) {
resp.getWriter().write("500!! Server Exception");
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
if (handlerMapping.isEmpty()) {
return;
}
String url = req.getRequestURI();
String contextPath = req.getContextPath();
// 拼接url并把多个/替换成一个
url = url.replace(contextPath, "").replaceAll("/+", "/");
if (!this.handlerMapping.containsKey(url)) {
resp.getWriter().write("404 NOT FOUND!");
return;
}
Method method = this.handlerMapping.get(url);
// 获取方法的参数列表
Class<?>[] parameterTypes = method.getParameterTypes();
// 获取请求的参数
Map<String, String[]> parameterMap = req.getParameterMap();
// 保存参数值
Object[] paramValues = new Object[parameterTypes.length];
// 方法的参数列表
for (int i = 0; i < parameterTypes.length; i++) {
// 根据参数名称,做某些处理
String requestParam = parameterTypes[i].getSimpleName();
if (requestParam.equals("HttpServletRequest")) {
// 参数类型已明确,这边强转类型
paramValues[i] = req;
continue;
}
if (requestParam.equals("HttpServletResponse")) {
paramValues[i] = resp;
continue;
}
if (requestParam.equals("String")) {
for (Entry<String, String[]> param : parameterMap.entrySet()) {
String value = Arrays.toString(param.getValue()).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
paramValues[i] = value;
}
}
}
// 利用反射机制来调用
try {
method.invoke(this.controllerMap.get(url), paramValues);// obj是method所对应的实例
// 在ioc容器中
} catch (Exception e) {
e.printStackTrace();
}
}
private void doLoadConfig(String location) {
// 把web.xml中的contextConfigLocation对应value值的文件加载到留里面
InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(location);
try {
// 用Properties文件加载文件里的内容
properties.load(resourceAsStream);
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关流
if (null != resourceAsStream) {
try {
resourceAsStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private void doScanner(String packageName) {
// 把所有的.替换成/
URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
File dir = new File(url.getFile());
for (File file : dir.listFiles()) {
if (file.isDirectory()) {
// 递归读取包
doScanner(packageName + "." + file.getName());
} else {
String className = packageName + "." + file.getName().replace(".class", "");
classNames.add(className);
}
}
}
private void doInstance() {
if (classNames.isEmpty()) {
return;
}
for (String className : classNames) {
try {
// 把类搞出来,反射来实例化(只有加@MyController需要实例化)
Class<?> clazz = Class.forName(className);
if (clazz.isAnnotationPresent(MyController.class)) {
ioc.put(toLowerFirstWord(clazz.getSimpleName()), clazz.newInstance());
} else {
continue;
}
} catch (Exception e) {
e.printStackTrace();
continue;
}
}
}
private void initHandlerMapping() {
if (ioc.isEmpty()) {
return;
}
try {
for (Entry<String, Object> entry : ioc.entrySet()) {
Class<? extends Object> clazz = entry.getValue().getClass();
if (!clazz.isAnnotationPresent(MyController.class)) {
continue;
}
// 拼url时,是controller头的url拼上方法上的url
String baseUrl = "";
if (clazz.isAnnotationPresent(MyRequestMapping.class)) {
MyRequestMapping annotation = clazz.getAnnotation(MyRequestMapping.class);
baseUrl = annotation.value();
}
Method[] methods = clazz.getMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(MyRequestMapping.class)) {
continue;
}
MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
String url = annotation.value();
url = (baseUrl + "/" + url).replaceAll("/+", "/");
// 这里应该放置实例和method
handlerMapping.put(url, method);
controllerMap.put(url, clazz.newInstance());
System.out.println(url + "," + method);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 把字符串的首字母小写
*
* @param name
* @return
*/
private String toLowerFirstWord(String name) {
char[] charArray = name.toCharArray();
charArray[0] += 32;
return String.valueOf(charArray);
}
}
分享到:
相关推荐
Spring、SpringMVC和Mybatis是Java开发中最常用的三大开源框架,它们的整合使用,通常被称为SSM框架。这个框架组合提供了完整的后端服务解决方案,包括依赖注入(DI)、面向切面编程(AOP)、模型-视图-控制器(MVC...
SpringMVC是Spring框架的一个模块,专为构建Web应用程序提供模型-视图-控制器(MVC)架构。这个“springMVC练手代码”压缩包包含的资源可以帮助初学者或开发者深入了解并实践SpringMVC的基本操作和核心概念。 首先...
SpringMVC是一款强大的Java web开发框架,用于构建高效、可维护的Web应用程序。在这个"SpringMVC demo 完整源码实例下载"中,我们能够深入理解并学习SpringMVC的核心概念和实际应用。 首先,SpringMVC是Spring框架...
【狂神SpringMVC配套课程代码】一共8个模块,大概可以看我的博客,都是自己学配套整理的 欢迎大家作为学习SpringMVC的参考!! 下面附上狂神B站课程网址,和我的博客笔记(共8章) 狂神老师B站课程:...
SpringMVC是一个强大的Java Web开发框架,由Spring社区开发,它是Spring生态系统的重要组成部分,主要用于构建后端服务。SpringMVC以其灵活的配置、高度模块化和优秀的性能深受开发者喜爱。在这个"springmvc实战项目...
### SpringMVC基础知识详解 #### 一、SpringMVC简介 **SpringMVC**是Spring框架中的一个重要组成部分,主要用于Web应用程序的开发。它遵循MVC(Model-View-Controller)设计模式,帮助开发者构建清晰、可维护的Web...
SpringMVC 是一款基于 Java 的轻量级 Web 开发框架,它是 Spring 框架的重要组成部分,主要用于构建 MVC(Model-View-Controller)模式的 Web 应用程序。本教程将深入探讨 SpringMVC 的核心概念、配置以及实际应用。...
SpringMVC和SQLiteJDBC是两个在Java开发中常见的组件,它们分别用于构建Web应用程序和服务端数据存储。这里我们详细探讨这两个技术以及它们如何协同工作。 **SpringMVC** SpringMVC是Spring框架的一个模块,专门...
本教程将详细阐述如何使用四个关键组件——Maven、SpringMVC、MyBatis和Log4j——来搭建一个强大的Web应用框架,旨在提高开发效率并优化项目管理。 **Maven** 是一个流行的项目管理和综合工具,它通过统一的构建...
【SpringMVC】 SpringMVC是Spring框架的一部分,它是一个用于构建Web应用程序的轻量级、模型-视图-控制器(MVC)架构。SpringMVC通过将业务逻辑、控制逻辑和显示逻辑分离,提高了代码的可维护性和可测试性。在...
SpringMVC、Hibernate和Spring是Java开发中三大核心框架,它们各自负责应用程序的不同层面:SpringMVC用于处理HTTP请求和响应,Hibernate则是持久层框架,负责数据库操作,而Spring作为全能容器,提供依赖注入和面向...
SpringMVC和MyBatis是Java Web开发中的两个核心框架,它们在构建高效、模块化的应用程序方面发挥着重要作用。SpringMVC是Spring框架的一部分,主要负责处理HTTP请求和响应,而MyBatis则是一个轻量级的持久层框架,...
**SpringMVC 入门小程序详解** SpringMVC是Spring框架的一个重要模块,它是一个用于构建Web应用程序的轻量级、模型-视图-控制器(MVC)框架。本入门程序旨在帮助初学者理解并掌握SpringMVC的基本概念和工作流程,...
SpringMVC和Mybatis是Java开发中非常流行的两个框架,它们在企业级Web应用开发中起着关键作用。SpringMVC作为Spring框架的一部分,主要负责处理HTTP请求和响应,而Mybatis则是一个轻量级的持久层框架,专注于数据库...
SpringMVC 拦截器项目是一个典型的 Web 应用开发示例,它利用 SpringMVC 框架中的拦截器(Interceptor)机制来实现特定的功能,如权限控制、日志记录、性能统计等。SpringMVC 是 Spring 框架的一部分,专为构建基于 ...
《尚硅谷SpringMVC部分全套教学文档笔记》涵盖了SpringMVC框架的核心概念和技术,通过一系列章节深入浅出地讲解了SpringMVC的各个方面。以下是基于这些文档内容的详细知识点总结: 1. **SpringMVC概述与HelloWorld*...
Java基于Spring+SpringMVC+MyBatis实现的学生信息管理系统源码,SSM+Vue的学生管理系统。 Java基于Spring+SpringMVC+MyBatis实现的学生信息管理系统源码,SSM+Vue的学生管理系统。 Java基于Spring+SpringMVC+...
SpringMVC是Spring框架的一部分,专门用于构建Web应用程序的模型-视图-控制器(MVC)架构。在本文中,我们将深入探讨SpringMVC 5.0版本的关键特性、使用方法以及它如何增强Web开发的效率。 首先,SpringMVC 5.0是...
在本项目中,我们主要探讨的是如何将SpringMVC、MyBatis、PostgreSQL数据库以及Maven构建工具进行有效的整合,以实现一个高效且模块化的Web应用开发环境。以下是关于这些技术及其整合的关键知识点的详细说明: **1....