文章目錄
- 手擼一個mvc框架有多簡單
手擼一個mvc框架有多簡單
在web配置類中定義一個處理前端請求的servlet
web.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<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 {
//初始化方法 利用反射機制事先把類以及方法進行預處理
@Override
public void init(ServletConfig config) throws ServletException {
//讀取組態檔路徑
String path = config.getInitParameter("contentConfigLocation");
//組態檔內容轉換為輸入流
InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
//把組態檔的輸入流傳入此處理器 利用反射機制事先把組態檔中指定的類以及方法進行預處理
HandleMapping.load(is);
}
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1.獲取用戶請求的uri
String 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.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 被此注解添加的方法,會被用于處理請求
* 方法回傳的內容,以文字形式回傳到客戶端
*/
public @interface ResponseBody {
String value();
}
package com.zhou.mvc;
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
* 被此注解添加的方法,會被用于處理請求
* 方法回傳的內容,會直接重定向
*/
public @interface 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 {
@ResponseBody("/testLogin.do")
public String login(HttpServletRequest req, HttpServletResponse resp) {
return "login success";
}
@ResponseView("/reg.do")
public String reg(HttpServletRequest req, HttpServletResponse resp){
return "success.jsp";
}
}
把測驗類添加到組態檔 application.properties
#在這里配置用于處理請求的類,每一個類中可能包含0到n個處理請求的方法
a = com.zhou.gc.test2.test.UserController
測驗頁面:

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/298105.html
標籤:java
上一篇:java基礎-陣列(回顧)
