當前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
实现简单的注解型MVC框架 —— 低配SpringMVC
生活随笔
收集整理的這篇文章主要介紹了
实现简单的注解型MVC框架 —— 低配SpringMVC
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 目標
- 最終效果展示
- 基本步驟
- 1. 解析控制器類:
- 2. 解析處理函數:
- 3. 解析處理函數變量名:
- 4. 監聽TCP連接:
- 5. 實現路由函數:
- 知識點總結
目標
- 與SpringMvc定義Controller類似效果
最終效果展示
主類
package org.example;import com.zcj.Accepter; import com.zcj.annotation.SummerApplication;import java.io.IOException;//標注控制器類 @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 {//標注處理的路徑@Controller("/hello")public Response hello(@Param("name") String name){return new Response(200, Response.HTML, "<h1>Hello,"+ name + "</h1>");} }瀏覽器訪問:
基本步驟
1. 解析控制器類:
利用反射解析@SummerApplication注解所包含的類,獲得該類中的處理函數
2. 解析處理函數:
獲取控制器類中包含@Controller的方法,建立處理函數映射表
3. 解析處理函數變量名:
獲取處理函數中包含@Param的參數,建立處理函數變量名表用于獲取請求中的參數
/*** 解析控制器類中的處理函數* @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對象,并且如果這個類沒有被加載過它將會初始化這個類。Class controllerClazz = Class.forName(classPack);controllers = (T) controllerClazz.newInstance();System.out.println("控制器類:" + controllerClazz);System.out.println("\n*************************************************************************************************************************" +"\n* 路徑\t\t|參數\t\t\t\t| 處理函數");//反射解析控制器類Method[] methods = controllerClazz.getMethods();for (Method method : methods) {if (!method.isAnnotationPresent(Controller.class)) continue;Controller annotation = method.getAnnotation(Controller.class);//將函數加入映射表controllerMap.put(annotation.value(), method);Parameter[] parameterList = method.getParameters();List<String> paramNameList = null;if (parameterList.length > 0) {//獲取參數變量名paramNameList = new ArrayList<>();for (Parameter param : parameterList) {//判斷是否出現 @Paramif (!param.isAnnotationPresent(Param.class)) continue;Param paramAnnotation = param.getAnnotation(Param.class);paramNameList.add(paramAnnotation.value());}//處理函數變量名映射表paramNameMap.put(annotation.value(), paramNameList);}System.out.println("* " + annotation.value() + " | " + paramNameList + " | " + method);}System.out.println("*************************************************************************************************************************\n");System.out.println("解析控制器類完成");}4. 監聽TCP連接:
獲取請求的方法(POST,GET),請求的路徑,請求參數等
/*** 啟動連接監聽* @param clazz 啟動類*/public void run(Class clazz) {//解析控制器類try {analysisController(clazz);} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {System.out.println("ERROR: 控制器類不存在, 請檢查 @SummerApplication 注解的類名");return;}//啟動監聽連接System.out.println("==============================================\n\n等待遠程連接,端口號為:" + serverSocket.getLocalPort() + "\n\n==============================================\n");while (true) {try {Socket client = serverSocket.accept();synchronized (System.out) {System.out.println("==============================================\n連接的遠程主機地址:" + client.getRemoteSocketAddress() + "\n==============================================\n");}executorService.submit(() -> {//處理請求handlerRequest(client);});} catch (IOException ioException) {System.out.println(ioException);//關閉線程池executorService.shutdown();}}}請求解析函數
/*** 此函數用于解析請求并分配請求到相應的處理函數* @param client 連接請求的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))) {//請求頭String requestHeader;int contentLength = 0;//請求的類型String requestType = null;//請求的路徑String requestPath = null;//請求參數String requestParams = null;//參數類型String contentType = null;while ((requestHeader = reader.readLine()) != null && !requestHeader.isEmpty()) {synchronized (System.out) {System.out.println(requestHeader);}//獲得請求的類型,路徑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);}//獲得參數類型if (requestHeader.startsWith("Content-Type")) {String[] line = requestHeader.split(": ");contentType = line[1];}//獲得Get參數if (requestHeader.startsWith("GET")) {int begin = requestHeader.indexOf("?") + 1;if (begin == 0) {requestParams = "";} else {int end = requestHeader.indexOf("HTTP/") - 1;//GET的參數requestParams = requestHeader.substring(begin, end);}}//獲取POST請求內容長度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請求參數字符串StringBuffer sb = new StringBuffer();if (contentLength > 0) {for (int i = 0; i < contentLength; i++) {sb.append((char) reader.read());}requestParams = sb.toString();}//將字符串轉UTF-8requestParams = URLDecoder.decode(requestParams, "UTF-8");System.out.println(requestParams);synchronized (System.out) {System.out.println("請求類型:" + requestType);System.out.println("請求路徑:" + requestPath);System.out.println("請求參數類型:" + contentType);System.out.println("請求參數:" + requestParams);}//發送回復Response resp = null;if (requestType.equals("POST") && !contentType.equals("application/x-www-form-urlencoded")) {//只接受 application/x-www-form-urlencoded 的參數resp = new Response(400, Response.HTML, "<h1>400<h4>POST請求的參數格式必須為 application/x-www-form-urlencoded</h4></h1>");} else {//將請求分配到相應的處理函數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: 分配請求失敗");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. 實現路由函數:
利用處理函數變量名表獲取參數,并將參數轉為處理函數所需類型,利用處理函數映射表將請求轉發到對應的處理函數,返回結果
/*** @param requestPath 請求的路徑* @param requestParams 請求的參數字符串* @return Response http回復類* @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)) {//處理函數不存在return new Response(404, Response.HTML, "<h1>404<h4>請求的資源不存在</h4></h1>");}//調用處理函數Method method = controllerMap.get(requestPath);//獲取方法的參數類型Class<?>[] paramterTypes = method.getParameterTypes();if (paramterTypes.length == 0) {//不需要參數//invoke()第一個參數為調用方法的實例return (Response) controllerMap.get(requestPath).invoke(controllers);}//檢驗參數//解析參數字符傳LinkedHashMap<String, String> paramMap = Params.toMap(requestParams);if (paramMap == null) {//沒有所需參數return new Response(400, Response.HTML, "<h1>參數錯誤,請檢查</h1>");}//獲得方法的參數變量名表List<String> paramNameList = paramNameMap.get(requestPath);//方法的參數Object[] params = new Object[paramterTypes.length];for (int i = 0; paramMap != null && i < paramterTypes.length; i++) {//參數的類型Class paramType = paramterTypes[i];if (allowType.contains(paramType) && !paramMap.containsKey(paramNameList.get(i))) {//參數缺漏return new Response(400, Response.HTML, "<h1 style=\"color:red;\">參數錯誤, 缺少:" + paramNameList.get(i) + "[ " + paramterTypes[i].getName() + " ]</h1>");}//將String 轉為 所需的類型,只支持基本類型或自定義類(不包括集合)String param = paramMap.get(paramNameList.get(i));//將基本類型轉為包裝類型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)) {//將參數轉為所需類型Object instance = paramType.getConstructor(String.class).newInstance(param);params[i] = instance;} else {//自定義類Object o = Params.toObject(requestParams, paramType);params[i] = o;}}//調用控制器return (Response) controllerMap.get(requestPath).invoke(controllers, params);}知識點總結
- 將字符串轉UTF-8的方法
-
向反射獲取的函數中傳入任意數量且不同類型的參數的方法
前提知識:JAVA中的引用類型都繼承于Object,通過向上轉型,可以用Object類型引用各種引用類型
第一步:將基本類型轉為包裝類型
第二步:將所有參數放入Object數組中
第三步:調用相應的函數
總結
以上是生活随笔為你收集整理的实现简单的注解型MVC框架 —— 低配SpringMVC的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 屏幕识图提取文字快捷键(屏幕识图提取文字
- 下一篇: 野生牛舌草的图片(湿润的旷地里,生长着1