手撸一个mvc框架有多简单
在web配置类中定义一个处理前端请求的servlet
web.xml 配置
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"version="4.0"><!-- 定义一个集中处理前端请求的servlet--><servlet><servlet-name>DispatcherServlet</servlet-name><servlet-class>com.zhou.mvc.DispatcherServlet</servlet-class><!-- 定义初始化参数 用于解析配置文件中的类信息--><init-param><param-name>contentConfigLocation</param-name><param-value>application.properties</param-value></init-param><!-- 服务器一启动此类就加载--><load-on-startup>0</load-on-startup></servlet><servlet-mapping><!-- 所有带有.do结尾的请求都被映射到此类中--><servlet-name>DispatcherServlet</servlet-name><url-pattern>*.do</url-pattern></servlet-mapping></web-app>
DispatcherServlet 类
package com.zhou.mvc;import javax.servlet.ServletConfig;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;public class DispatcherServlet extends HttpServlet {//初始化方法 利用反射机制事先把类以及方法进行预处理@Overridepublic void init(ServletConfig config) throws ServletException {//读取配置文件路径String path = config.getInitParameter("contentConfigLocation");//配置文件内容转换为输入流InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);//把配置文件的输入流传入此处理器 利用反射机制事先把配置文件中指定的类以及方法进行预处理HandleMapping.load(is);}@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//1.获取用户请求的uriString uri = req.getRequestURI();HandleMapping.MVCMapping mapping = HandleMapping.get(uri);if(mapping==null){resp.sendError(404,"自定义MVC:映射地址不存在"+uri);return;}Object obj = mapping.getObj();Method method = mapping.getMethod();String result = null;try {//利用反射直接调用此方法并且获得此方法的返回值result = (String) method.invoke(obj, req, resp);} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}switch (mapping.getType()){case TEXT://如果是纯文本就利用打印流直接写回前端页面resp.getWriter().write(result);break;case VIEW://如果是视图 就直接进行重定向resp.sendRedirect(result);break;}}}
HandleMapping 类
package com.zhou.mvc;import java.io.IOException;import java.io.InputStream;import java.lang.annotation.Annotation;import java.lang.reflect.Method;import java.util.Collection;import java.util.HashMap;import java.util.Map;import java.util.Properties;/*** 映射器(包含了大量的网址与方法的对应关系),封装了一个每一个uri所对应的映射对象*/public class HandleMapping {//key为uri 值为映射对象private static Map<String, MVCMapping> data = new HashMap<>();public static MVCMapping get(String uri){return data.get(uri);}public static void load(InputStream is) {// 定义存储配置文件中的类信息的集合Properties ppt = new Properties();try {//装载后的数据结构与hashMap类似 key为配置文件的=左,值为=右(类路径)ppt.load(is);} catch (IOException e) {e.printStackTrace();}//获得所有类路径的集合Collection<Object> values = ppt.values();//遍历每一个类的项目路径for (Object cla : values) {String claasName = (String) cla;try {//加载配置文件中描述的每一个类Class c = Class.forName(claasName);//创建这个类的对象Object o = c.getConstructor().newInstance();//获取这个类的所有方法Method[] methods = c.getMethods();//遍历所有方法for (Method m : methods) {//得到此方法上的所有注解Annotation[] as = m.getAnnotations();if (as != null) {for (Annotation a : as) {if (a instanceof ResponseBody) {//说明此方法用于返回字符串给客户端MVCMapping mapping = new MVCMapping(o,m,ResponseType.TEXT);//key为uri 值为映射对象MVCMapping put = data.put(((ResponseBody) a).value(), mapping);if (put != null){//存在了重复的请求地址throw new RuntimeException("请求地址重复"+((ResponseBody) a).value());}} else if (a instanceof ResponseView) {//说明此方法,用于返回界面给客户端MVCMapping mapping = new MVCMapping(o,m,ResponseType.VIEW);MVCMapping put = data.put(((ResponseView) a).value(), mapping);if (put != null){//存在了重复的请求地址throw new RuntimeException("请求地址重复"+((ResponseView) a).value());}}}}}} catch (Exception e) {e.printStackTrace();}}}/*** 映射对象,每一个对象封装了一个方法,用于处理请求*/public static class MVCMapping {private Object obj;private Method method;private ResponseType type;public MVCMapping() {}public MVCMapping(Object obj, Method method, ResponseType type) {this.obj = obj;this.method = method;this.type = type;}public Object getObj() {return obj;}public void setObj(Object obj) {this.obj = obj;}public Method getMethod() {return method;}public void setMethod(Method method) {this.method = method;}public ResponseType getType() {return type;}public void setType(ResponseType type) {this.type = type;}}}
ResponseBody 和 ResponseView 注解类
package com.zhou.mvc;import java.lang.annotation.*;/*** 被此注解添加的方法,会被用于处理请求* 方法返回的内容,以文字形式返回到客户端*/public ResponseBody {String value();}
package com.zhou.mvc;import java.lang.annotation.*;/*** 被此注解添加的方法,会被用于处理请求* 方法返回的内容,会直接重定向*/public ResponseView {String value();}
ResponseType 枚举类
package com.zhou.mvc;public enum ResponseType {TEXT,VIEW;}
测试控制类:
package com.zhou.gc.test2.test;import com.zhou.mvc.ResponseBody;import com.zhou.mvc.ResponseView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class UserController {public String login(HttpServletRequest req, HttpServletResponse resp) {return "login success";}public String reg(HttpServletRequest req, HttpServletResponse resp){return "success.jsp";}}
把测试类添加到配置文件 application.properties
#在这里配置用于处理请求的类,每一个类中可能包含0到n个处理请求的方法a = com.zhou.gc.test2.test.UserController
测试页面:

作者:JuiRing
链接:https://blog.csdn.net/LLLlucky_boy/article/details/120122147
评论
