最近看了几篇手写关于SpringMVC的文章,自己试了一下
先写俩注解Controller和Requesting
package com.my_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)
// 生命周期, 在运行时加载在内存
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
}
package com.my_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();
}
扫描包的工具类
package com.my_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;
/**
* @Auther: YANG_ZG
* @Date: 2018/9/8 9:36
* @Description: 用来扫描包下面的类
*/
public class ClassScanner {
/**
* 扫描某个包下所有的类
* @return Map> Map<类名, 类的class实例>
*/
public static Map> scannerScanner(String basePackge) {
Map> results = new HashMap<>();
// 把包名的.替换为/
String filePath = basePackge.replace(".","/");
// 通过类加载器获得完整路径
Enumeration dirs = null;
try {
dirs = Thread.currentThread().getContextClassLoader().getResources(filePath);
} catch (IOException e) {
e.printStackTrace();
}
// rootPath 真实的磁盘路径,.class文件的路径 /D:/IDEAWorkspaces/SpringMVC_myself/out/production/SpringMVC_myself/com/my_mvc/util
String rootPath = Thread.currentThread().getContextClassLoader().getResource(filePath).getPath();
// 取出路径多余的部分/D:/IDEAWorkspaces/SpringMVC_myself/out/production/SpringMVC_myself/
if (rootPath != null){
int i = rootPath.lastIndexOf(filePath);
// rootPath = rootPath.substring(i) + "/";
// 在Tomcat部署时候不需要 + "/"
rootPath = rootPath.substring(i);
}
while (dirs.hasMoreElements()){
URL url = dirs.nextElement();
// 根据url判断是否是文件对象
if (url.getProtocol().equals("file")){
File file = new File(url.getPath().substring(1));
scannerScanner(file, rootPath, results);
}
}
return results;
}
private static void scannerScanner(File folder, String rootPath, Map> classes){
// 拿到folder的所有文件对象
// 文件夹里为空,listFiles()返回为空
File[] files = folder.listFiles();
for (int i = 0; files != null && i < files.length; i++ ){
File file = files[i];
// 判断是否继续是个是文件夹,是文件夹继续递归
if (file.isDirectory()){
String tempPath = rootPath + file.getName() + "/";
scannerScanner(file, tempPath, classes);
}else {
String path = file.getAbsolutePath(); // 真实路径
if (path.endsWith(".class")){
// 将路径中的 \ 替换为 /
path = path.replace("\\", "/");
// 完整的路径
String className = rootPath + path.substring(path.lastIndexOf("/") + 1, path.indexOf(".class"));
className = className.replace("/", ".");
// System.out.println(className);
try {
classes.put(className, Class.forName(className));
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws IOException {
scannerScanner("com.my_mvc.util");
}
}
controller 抽象父类
package com.my_mvc.util;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @Auther: YANG_ZG
* @Date: 2018/9/8 11:26
* @Description: 所有的 controller 抽象父类
*/
public abstract class BaseController {
protected HttpServletRequest request;
protected HttpServletResponse response;
public 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
package com.my_mvc.servlet;
import com.my_mvc.annotation.Controller;
import com.my_mvc.annotation.RequestMapping;
import com.my_mvc.util.BaseController;
import com.my_mvc.util.ClassScanner;
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 java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* @Auther: YANG_ZG
* @Date: 2018/9/8 16:41
* @Description: DispatcherServlet
*/
@WebServlet(urlPatterns={"*.do"}, initParams = {@WebInitParam(name = "basePackage", value = "com.my_mvc")})
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = -3752494172091060171L;
// 存储controller实例,此写法单例。。。。。多例可以= null, 调用每次new 一个出来
private Map controllers = new HashMap<>();
// 反射调用的method
private Map methods = new HashMap<>();
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("================================");
// 在实际中,在xml中获得参数,,,现在@WebServlet 注解中先写死
String basePackage = config.getInitParameter("basePackage");
// 获得 包下 Map<类名, 类的class实例>
Map> classMap = ClassScanner.scannerScanner(basePackage);
Iterator iterator = classMap.keySet().iterator();
while (iterator.hasNext()){
String className = iterator.next();
Class clazz = classMap.get(className);
String path = "";
// 判断类是否存在Controller注解
if(clazz.isAnnotationPresent(Controller.class)){
System.out.println(clazz.getName() + " 是controller控制类。。。");
// 管理类
// 判断类是否被RequestMapping修饰
if (clazz.isAnnotationPresent(RequestMapping.class)){
// 取出注解值
RequestMapping rm = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
path = rm.value();
}
try {
// 单例可以直接 clazz.newInstance(), 如果是多例不再这里new,value只存一个class,
controllers.put(className, clazz.newInstance());
} catch (Exception e) {}
// 得到类中的所有方法
Method[] ms = clazz.getMethods();
for (Method method : ms) {
// 看方法是否存在RequestMapping注解,没有跳过
if (!method.isAnnotationPresent(RequestMapping.class)){
continue;
}
// System.out.println(method.getName() + " 方法的映射的对外路径为:" + path + method.getAnnotation(RequestMapping.class).value());
methods.put(path + method.getAnnotation(RequestMapping.class).value(), method);
}
}
}
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String requestURI = req.getRequestURI();
String contextPath = req.getContextPath();
int beginIndex = requestURI.indexOf(contextPath) + contextPath.length();
int endIndex= requestURI.indexOf(".do");
String mappingPath = requestURI.substring(beginIndex, endIndex);
Method method = methods.get(mappingPath);
// method.getDeclaringClass() 得到这个方法类的实例
// 单例写法 Object controller = controllers.get(method.getDeclaringClass().getName());
BaseController controller;
try {
controller = (BaseController) method.getDeclaringClass().newInstance();
controller = null;
controller = (BaseController) controllers.get(method.getDeclaringClass().getName());
// 这样可以在controller方法里使用request,response
controller.init(req, resp);
if (controller != null) {
method.invoke(controller);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
测试Controller类
package com.my_mvc;
import javax.servlet.http.HttpSession;
import com.my_mvc.annotation.Controller;
import com.my_mvc.annotation.RequestMapping;
import com.my_mvc.util.BaseController;
/**
* @author: YANG_ZG
* @date: 2018/9/8 17:49
* @Description: test
*/
@Controller
@RequestMapping("/test")
public class TestController extends BaseController{
@RequestMapping("/login")
public void login(){
System.out.println("test/login==================");
}
@RequestMapping("/add")
public void add(){
System.out.println("test/add==================");
System.out.println(request.getAttribute("msg"));
}
@RequestMapping("/delete")
public void delete(){
System.out.println("test/delete==================");
}
public void pp(){
}
}
把项目加载进tomcat服务器中启动http://localhost:8080/SpringMVC_myself/test/login.do