手擼一個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);//創(chuàng)建這個類的對象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
評論
圖片
表情
