當(dāng)前位置:
首頁(yè) >
前端技术
> javascript
>内容正文
javascript
实现简单的注解型MVC框架 —— 低配SpringMVC
生活随笔
收集整理的這篇文章主要介紹了
实现简单的注解型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的方法
-
向反射獲取的函數(shù)中傳入任意數(shù)量且不同類型的參數(shù)的方法
前提知識(shí):JAVA中的引用類型都繼承于Object,通過(guò)向上轉(zhuǎn)型,可以用Object類型引用各種引用類型
第一步:將基本類型轉(zhuǎn)為包裝類型
第二步:將所有參數(shù)放入Object數(shù)組中
第三步:調(diào)用相應(yīng)的函數(shù)
總結(jié)
以上是生活随笔為你收集整理的实现简单的注解型MVC框架 —— 低配SpringMVC的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 屏幕识图提取文字快捷键(屏幕识图提取文字
- 下一篇: Springboot配置通过URL访问图