首先我们需要新建一个Java Enterprise
工程,勾选上Web Application
先自定义两个注解,springmvc特别常用的两个注解
@Controller
被@Controller注解标记的类将会被识别为控制器
package com.mvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/*
* 表示只能标注使用在Java类上
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
@RequestMapping
再来个RequestMapping
package com.mvc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE, ElementType.METHOD}) // 注解运行在哪里
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期
public @interface RequestMapping {
public String value();
}
包扫描工具类ClassScanner
package com.mvc.util;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* 包扫描工具类
*
* @author Milk
*/
public class ClassScanner {
// 传递包名
public static Map<String, Class<?>> scannerClass(String basePackage) {
// Map<String, Class<?>> results = new HashMap<>();
String filePath = basePackage.replace(".", "/");
// com/mvc
try {
// 通过类加载器获取类的整个完整的磁盘路径
Enumeration<URL> dirs = Thread.currentThread().getContextClassLoader().getResources(filePath);
String rootPath = Thread.currentThread().getContextClassLoader().getResource(filePath).getPath();
System.out.println(rootPath);
// file:/D:/EclipseWorkSpacesCollections/HelloWorld/writeSpringmvc/build/classes/com/mvc
if (rootPath != null) {
// rootPath = rootPath.substring(rootPath.lastIndexOf(filePath)) + "/";
rootPath = rootPath.substring(rootPath.lastIndexOf(filePath));
// file:/D:/EclipseWorkSpacesCollections/HelloWorld/writeSpringmvc/build/classes/com/mvc/
}
while (dirs.hasMoreElements()) {
URL url = dirs.nextElement();
// 文件协议的url
System.out.println(url);
// file:/D:/EclipseWorkSpacesCollections/HelloWorld/writeSpringmvc/build/classes/com/mvc
// 如果是文件协议的链接
if (url.getProtocol().equals("file")) {
File file = new File(url.getPath().substring(1));
System.out.println("url.getPath():---> " + url.getPath());
System.out.println(file.getAbsolutePath());
scannerFile(file, rootPath);
}
}
} catch (IOException e) {
e.printStackTrace();
}
return classes;
}
private static Map<String, Class<?>> classes = new HashMap<>();
private static void scannerFile(File folder, String rootPath) {
File[] files = folder.listFiles();
/*
* 使用递归的方式来遍历文件夹下的文件
*/
if (files != null) {
for (int i = 0; i < files.length; i++) {
if (files[i].isDirectory()) {
// 如果是文件夹
scannerFile(files[i], rootPath);
} else {
if (files[i].getName().endsWith(".class")) {
// 如果这个文件是以.class结尾,那就是我们想要找的文件
// 获取全类名
System.out.println(files[i].getName());
System.out.println(files[i].getAbsolutePath());
System.out.println(rootPath);
String newPath = files[i].getAbsolutePath().replace("\\", "/");
System.out.println(newPath);
int lastIndex = newPath.lastIndexOf(".class");
int firstIndex = newPath.lastIndexOf(rootPath);
newPath = newPath.substring(firstIndex, lastIndex);
System.out.println(newPath);
String className = newPath.replace("/", ".");
// 最终获取到每个类的全类名
System.out.println(className);
try {
classes.put(className, Class.forName(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
System.out.println("-------------");
}
}
}
}
}
public static void main(String[] args) {
/*
* 将这个包下面的所有类,包括子包类全部扫描出来
*/
Map<String, Class<?>> scannerClass = ClassScanner.scannerClass("com.mvc");
System.out.println("遍历类名");
Set<Entry<String, Class<?>>> entrySet = scannerClass.entrySet();
for (Entry<String, Class<?>> v : entrySet) {
// key放类名,value放Class实例
System.out.println(v.getKey() + "--->" + v.getValue());
}
}
}
BaseController
BaseController主要封装request和response
package com.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
protected void init(HttpServletRequest request, HttpServletResponse response) {
this.request = request;
this.response = response;
}
public HttpServletRequest getRequest() {
return request;
}
public void setRequest(HttpServletRequest request) {
this.request = request;
}
public HttpServletResponse getResponse() {
return response;
}
public void setResponse(HttpServletResponse response) {
this.response = response;
}
}
DispatcherServlet
SpringMVC所有的请求都会交给DispatcherServlet
处理,我们模仿着来写一个
package com.mvc;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.mvc.annotation.Controller;
import com.mvc.annotation.RequestMapping;
import com.mvc.util.ClassScanner;
/*
* 简易版SpringMVC
*/
/**
* Servlet implementation class DispatcherServlet
*/
@WebServlet(urlPatterns = { "*.do" }, initParams = { @WebInitParam(name = "basePackage", value = "com.mvc") })
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 存储Controller实例
private Map<String, Object> controllers = new HashMap<>();
// 被反射调用的Method
private Map<String, Method> methods = new HashMap<>();
/**
* @see HttpServlet#HttpServlet()
*/
public DispatcherServlet() {
super();
}
/**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
String basePackage = config.getInitParameter("basePackage");
Map<String, Class<?>> cons = ClassScanner.scannerClass(basePackage);
Iterator<String> iterator = cons.keySet().iterator();
while (iterator.hasNext()) {
String className = iterator.next();
Class clazz = cons.get(className);
if (clazz.isAnnotationPresent(Controller.class)) {
String path = "";
if (clazz.isAnnotationPresent(RequestMapping.class)) {
RequestMapping reqAnno = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
path = reqAnno.value();
}
try {
controllers.put(className, clazz.newInstance());
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Method[] ms = clazz.getMethods();// 拿到这个控制类所有的公开的方法遍历
for (Method method : ms) {
// 如果没有这个RequestMapping注解,进入下一轮循环
if (!method.isAnnotationPresent(RequestMapping.class)) {
continue;
}
methods.put(path + method.getAnnotation(RequestMapping.class).value(), method);
}
}
}
}
/**
* @see Servlet#destroy()
*/
public void destroy() {
}
/**
* @see HttpServlet#service(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("userName", "I am your father!");
String uri = request.getRequestURI();
String contextPath = request.getContextPath();
System.out.println("uri" + uri);
System.out.println("contextPath" + contextPath);
/*
* 如果这个路径是 http://localhost:8080/writeSpringmvc/milk/index.do 我们最终获取到的就是index
*/
String mappingPath = uri.substring(uri.indexOf(contextPath) + contextPath.length(), uri.indexOf(".do"));
System.out.println(mappingPath);
Method method = methods.get(mappingPath);
BaseController controller = null;
// controller = controllers.get(method.getDeclaringClass().getName());
try {
// 返回一个IndexController的实例,并强制转换成BaseController,
// 多态,父类引用指向子类对象
controller = (BaseController) method.getDeclaringClass().newInstance();
System.out.println(controllers);
controller.init(request, response);
method.invoke(controller);
} catch (InstantiationException e1) {
e1.printStackTrace();
} catch (IllegalAccessException e1) {
e1.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
IndexController
写一个IndexController测试一下
package com.mvc;
import com.mvc.annotation.Controller;
import com.mvc.annotation.RequestMapping;
@Controller
@RequestMapping("/milk")
public class IndexController extends BaseController {
@RequestMapping("/index")
public void index() {
System.out.println("index方法被执行!" + request.getAttribute("userName"));
}
@RequestMapping("/search")
public void search() {
System.out.println("search方法被执行!");
}
@RequestMapping("/delete")
public void delete() {
System.out.println("delete方法被执行!");
}
}
启动Tomcat服务器,
访问http://localhost:8080/milk/index.do
成功执行。