日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 前端技术 > javascript >内容正文

javascript

实现简单的注解型MVC框架 —— 低配SpringMVC

發(fā)布時(shí)間:2023/12/3 javascript 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 实现简单的注解型MVC框架 —— 低配SpringMVC 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

    • 目標(biāo)
    • 最終效果展示
    • 基本步驟
      • 1. 解析控制器類:
      • 2. 解析處理函數(shù):
      • 3. 解析處理函數(shù)變量名:
      • 4. 監(jiān)聽(tīng)TCP連接:
      • 5. 實(shí)現(xiàn)路由函數(shù):
    • 知識(shí)點(diǎn)總結(jié)

目標(biāo)

  • 與SpringMvc定義Controller類似效果

最終效果展示

主類

package org.example;import com.zcj.Accepter; import com.zcj.annotation.SummerApplication;import java.io.IOException;//標(biāo)注控制器類 @SummerApplication("org.example.MainController") public class App {public static void main( String[] args ) throws IOException {Accepter accepter = new Accepter();accepter.run(App.class);} }

控制器類

package org.example;import com.zcj.annotation.Controller; import com.zcj.annotation.Param; import com.zcj.entity.Response;public class MainController {//標(biāo)注處理的路徑@Controller("/hello")public Response hello(@Param("name") String name){return new Response(200, Response.HTML, "<h1>Hello,"+ name + "</h1>");} }

瀏覽器訪問(wèn):

基本步驟

1. 解析控制器類:

利用反射解析@SummerApplication注解所包含的類,獲得該類中的處理函數(shù)

2. 解析處理函數(shù):

獲取控制器類中包含@Controller的方法,建立處理函數(shù)映射表

3. 解析處理函數(shù)變量名:

獲取處理函數(shù)中包含@Param的參數(shù),建立處理函數(shù)變量名表用于獲取請(qǐng)求中的參數(shù)

/*** 解析控制器類中的處理函數(shù)* @param clazz 控制器類的Class* @throws ClassNotFoundException* @throws IllegalAccessException* @throws InstantiationException*/private void analysisController(Class clazz) throws ClassNotFoundException, IllegalAccessException, InstantiationException {System.out.println("解析控制器類.....");if (!clazz.isAnnotationPresent(SummerApplication.class)) {System.out.println("ERROR: 未指定控制器類");return;}SummerApplication summerApplication = (SummerApplication) clazz.getAnnotation(SummerApplication.class);String classPack = summerApplication.value();// Class.forName 可以得到Class對(duì)象,并且如果這個(gè)類沒(méi)有被加載過(guò)它將會(huì)初始化這個(gè)類。Class controllerClazz = Class.forName(classPack);controllers = (T) controllerClazz.newInstance();System.out.println("控制器類:" + controllerClazz);System.out.println("\n*************************************************************************************************************************" +"\n* 路徑\t\t|參數(shù)\t\t\t\t| 處理函數(shù)");//反射解析控制器類Method[] methods = controllerClazz.getMethods();for (Method method : methods) {if (!method.isAnnotationPresent(Controller.class)) continue;Controller annotation = method.getAnnotation(Controller.class);//將函數(shù)加入映射表controllerMap.put(annotation.value(), method);Parameter[] parameterList = method.getParameters();List<String> paramNameList = null;if (parameterList.length > 0) {//獲取參數(shù)變量名paramNameList = new ArrayList<>();for (Parameter param : parameterList) {//判斷是否出現(xiàn) @Paramif (!param.isAnnotationPresent(Param.class)) continue;Param paramAnnotation = param.getAnnotation(Param.class);paramNameList.add(paramAnnotation.value());}//處理函數(shù)變量名映射表paramNameMap.put(annotation.value(), paramNameList);}System.out.println("* " + annotation.value() + " | " + paramNameList + " | " + method);}System.out.println("*************************************************************************************************************************\n");System.out.println("解析控制器類完成");}

4. 監(jiān)聽(tīng)TCP連接:

獲取請(qǐng)求的方法(POST,GET),請(qǐng)求的路徑,請(qǐng)求參數(shù)等

/*** 啟動(dòng)連接監(jiān)聽(tīng)* @param clazz 啟動(dòng)類*/public void run(Class clazz) {//解析控制器類try {analysisController(clazz);} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {System.out.println("ERROR: 控制器類不存在, 請(qǐng)檢查 @SummerApplication 注解的類名");return;}//啟動(dòng)監(jiān)聽(tīng)連接System.out.println("==============================================\n\n等待遠(yuǎn)程連接,端口號(hào)為:" + serverSocket.getLocalPort() + "\n\n==============================================\n");while (true) {try {Socket client = serverSocket.accept();synchronized (System.out) {System.out.println("==============================================\n連接的遠(yuǎn)程主機(jī)地址:" + client.getRemoteSocketAddress() + "\n==============================================\n");}executorService.submit(() -> {//處理請(qǐng)求handlerRequest(client);});} catch (IOException ioException) {System.out.println(ioException);//關(guān)閉線程池executorService.shutdown();}}}

請(qǐng)求解析函數(shù)

/*** 此函數(shù)用于解析請(qǐng)求并分配請(qǐng)求到相應(yīng)的處理函數(shù)* @param client 連接請(qǐng)求的Socket*/private void handlerRequest(Socket client) {try (InputStream input = client.getInputStream()) {try (OutputStream output = client.getOutputStream()) {try (PrintWriter writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output, StandardCharsets.UTF_8)))) {try (BufferedReader reader = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {//請(qǐng)求頭String requestHeader;int contentLength = 0;//請(qǐng)求的類型String requestType = null;//請(qǐng)求的路徑String requestPath = null;//請(qǐng)求參數(shù)String requestParams = null;//參數(shù)類型String contentType = null;while ((requestHeader = reader.readLine()) != null && !requestHeader.isEmpty()) {synchronized (System.out) {System.out.println(requestHeader);}//獲得請(qǐng)求的類型,路徑if (requestHeader.startsWith("POST") || requestHeader.startsWith("GET")) {String[] line = requestHeader.split(" ");requestType = line[0];int end = line[1].indexOf("?");if (end == -1) requestPath = line[1];else requestPath = line[1].substring(0, end);}//獲得參數(shù)類型if (requestHeader.startsWith("Content-Type")) {String[] line = requestHeader.split(": ");contentType = line[1];}//獲得Get參數(shù)if (requestHeader.startsWith("GET")) {int begin = requestHeader.indexOf("?") + 1;if (begin == 0) {requestParams = "";} else {int end = requestHeader.indexOf("HTTP/") - 1;//GET的參數(shù)requestParams = requestHeader.substring(begin, end);}}//獲取POST請(qǐng)求內(nèi)容長(zhǎng)度if (requestHeader.startsWith("Content-Length")) {int begin = requestHeader.indexOf("Content-Lengh:") + "Content-Length:".length() + 1;String postParamterLength = requestHeader.substring(begin).trim();contentLength = Integer.valueOf(postParamterLength);}}//獲取POST請(qǐng)求參數(shù)字符串StringBuffer sb = new StringBuffer();if (contentLength > 0) {for (int i = 0; i < contentLength; i++) {sb.append((char) reader.read());}requestParams = sb.toString();}//將字符串轉(zhuǎn)UTF-8requestParams = URLDecoder.decode(requestParams, "UTF-8");System.out.println(requestParams);synchronized (System.out) {System.out.println("請(qǐng)求類型:" + requestType);System.out.println("請(qǐng)求路徑:" + requestPath);System.out.println("請(qǐng)求參數(shù)類型:" + contentType);System.out.println("請(qǐng)求參數(shù):" + requestParams);}//發(fā)送回復(fù)Response resp = null;if (requestType.equals("POST") && !contentType.equals("application/x-www-form-urlencoded")) {//只接受 application/x-www-form-urlencoded 的參數(shù)resp = new Response(400, Response.HTML, "<h1>400<h4>POST請(qǐng)求的參數(shù)格式必須為 application/x-www-form-urlencoded</h4></h1>");} else {//將請(qǐng)求分配到相應(yīng)的處理函數(shù)resp = dispatch(requestPath, requestParams);}writer.write(resp.toString());writer.flush();client.close();synchronized (System.out) {System.out.println("\n=============================================\nWARING:" + client.getRemoteSocketAddress() + " is disconnected.\n=============================================\n");}}}} catch (InstantiationException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {client.close();System.out.println("ERROR: 分配請(qǐng)求失敗");e.printStackTrace();}} catch (IOException e) {try {client.close();} catch (IOException ignored) {}synchronized (System.out) {System.out.println("\n=============================================\nWARING:" + client.getRemoteSocketAddress() + " is disconnected.\n=============================================\n");}}}

5. 實(shí)現(xiàn)路由函數(shù):

利用處理函數(shù)變量名表獲取參數(shù),并將參數(shù)轉(zhuǎn)為處理函數(shù)所需類型,利用處理函數(shù)映射表將請(qǐng)求轉(zhuǎn)發(fā)到對(duì)應(yīng)的處理函數(shù),返回結(jié)果

/*** @param requestPath 請(qǐng)求的路徑* @param requestParams 請(qǐng)求的參數(shù)字符串* @return Response http回復(fù)類* @throws NoSuchMethodException* @throws IllegalAccessException* @throws InvocationTargetException* @throws InstantiationException*/private Response dispatch(String requestPath, String requestParams) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {Response resp = null;if (!controllerMap.containsKey(requestPath)) {//處理函數(shù)不存在return new Response(404, Response.HTML, "<h1>404<h4>請(qǐng)求的資源不存在</h4></h1>");}//調(diào)用處理函數(shù)Method method = controllerMap.get(requestPath);//獲取方法的參數(shù)類型Class<?>[] paramterTypes = method.getParameterTypes();if (paramterTypes.length == 0) {//不需要參數(shù)//invoke()第一個(gè)參數(shù)為調(diào)用方法的實(shí)例return (Response) controllerMap.get(requestPath).invoke(controllers);}//檢驗(yàn)參數(shù)//解析參數(shù)字符傳LinkedHashMap<String, String> paramMap = Params.toMap(requestParams);if (paramMap == null) {//沒(méi)有所需參數(shù)return new Response(400, Response.HTML, "<h1>參數(shù)錯(cuò)誤,請(qǐng)檢查</h1>");}//獲得方法的參數(shù)變量名表List<String> paramNameList = paramNameMap.get(requestPath);//方法的參數(shù)Object[] params = new Object[paramterTypes.length];for (int i = 0; paramMap != null && i < paramterTypes.length; i++) {//參數(shù)的類型Class paramType = paramterTypes[i];if (allowType.contains(paramType) && !paramMap.containsKey(paramNameList.get(i))) {//參數(shù)缺漏return new Response(400, Response.HTML, "<h1 style=\"color:red;\">參數(shù)錯(cuò)誤, 缺少:" + paramNameList.get(i) + "[ " + paramterTypes[i].getName() + " ]</h1>");}//將String 轉(zhuǎn)為 所需的類型,只支持基本類型或自定義類(不包括集合)String param = paramMap.get(paramNameList.get(i));//將基本類型轉(zhuǎn)為包裝類型if (paramType.equals(int.class)) {paramType = Integer.class;} else if (paramType.equals(boolean.class)) {paramType = Boolean.class;}if (paramType.equals(String.class)) {params[i] = param;} else if (paramType.equals(Integer.class) || paramType.equals(Boolean.class)) {//將參數(shù)轉(zhuǎn)為所需類型Object instance = paramType.getConstructor(String.class).newInstance(param);params[i] = instance;} else {//自定義類Object o = Params.toObject(requestParams, paramType);params[i] = o;}}//調(diào)用控制器return (Response) controllerMap.get(requestPath).invoke(controllers, params);}

知識(shí)點(diǎn)總結(jié)

  • 將字符串轉(zhuǎn)UTF-8的方法
String utf8Str = URLDecoder.decode(str, "UTF-8");
  • 向反射獲取的函數(shù)中傳入任意數(shù)量且不同類型的參數(shù)的方法

    前提知識(shí):JAVA中的引用類型都繼承于Object,通過(guò)向上轉(zhuǎn)型,可以用Object類型引用各種引用類型

    第一步:將基本類型轉(zhuǎn)為包裝類型
    第二步:將所有參數(shù)放入Object數(shù)組中
    第三步:調(diào)用相應(yīng)的函數(shù)

//...轉(zhuǎn)換步驟省略,可參照 基本步驟的5. dispatch函數(shù) //len為參數(shù)的數(shù)量 Object[] parmas = new Object[len] //....放入?yún)?shù)到 params 數(shù)組 method.invoke(instance, params)

總結(jié)

以上是生活随笔為你收集整理的实现简单的注解型MVC框架 —— 低配SpringMVC的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。