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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--参数自动映射篇(6/8)...

發布時間:2023/12/10 asp.net 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--参数自动映射篇(6/8)... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

前情概要

路由、action的掃描、發現、注冊搞定之后,后來我發現在我們的action里面獲取參數往往都是通過request對象來一個一個獲取。同樣的一行代碼我們不厭其煩的重復寫了無數次。遂想著那我們能不能像后端程序一樣做得更自動化一些呢?
所以,接下來我們再來完成一個比較重要的功能,那就是參數的自動綁定。

參數的自動綁定實現思路

依靠ts的裝飾器特性,我們能做在方法上,在類上,在方法的參數上,在類的屬性成員上通通可以加上裝飾器來存放一些額外的數據。那理論上我們在編碼階段就可以通過一定的手段把這個標記加載我們需要處理的方法、類、參數等上面,等到運行時的時候可以根據這些額外的參數來幫我們做一些重復性的工作。

  • 在需要使用到的方法參數、類、屬性上增加我們的特定標識,標記當前參數需要自動解析,并記錄一些諸如類型拉、名稱啦等的一些額外屬性。
  • 在action的調用階段,根據規則先把參數解析好。在傳遞進去。
  • 完事兒,這就是我們的參數自動綁定功能。
  • 參數的自動綁定實現---裝飾器實現

    部分代碼,只貼了fromquery,其他幾個formbody,fromheader之類的基本一樣,都是調用makeActionParameterDescriptor方法

    /*** 指示當前參數從request對象的query中解析* * @export* @param {(target?: any) => Function} type * @returns {Function} */ export function fromQuery(type: (target?: any) => Function): Function; /*** 指示當前參數從request對象的query中解析* * @export* @returns {Function} */ export function fromQuery(): Function {var thatArg = arguments;return function (target: Object, propertyKey: string, parameterIndex: number) {makeActionParameterDescriptor('query', thatArg, target, propertyKey, parameterIndex);} } function makeActionParameterDescriptor(parameterFromType: parameterFromType, thatArg: IArguments, target: Object, propertyKey: string, parameterIndex: number) {//非聲明在屬性和參數上if (!propertyKey) return;var paramType = undefined;var val = new ActionParamDescriptor();val.parameterName = propertyKey;val.target = target;val.parameterIndex = parameterIndex;val.parameterFromType = parameterFromType;val.parameterTypeType = 'simple'if (typeof parameterIndex === 'undefined') {//聲明在類的屬性上val.localtionType = 'classProperty'} else {//聲明在action的參數上val.localtionType = 'methodParameter'val.actionMethodName = propertyKey;val.parameterName = getArgs((target as any)[propertyKey])[parameterIndex];}//復雜類型if (thatArg.length > 0) {val.parameterTypeType = 'complex'val.parameterType = thatArg[0](target);}SetActionParamDescriptor(val); } function getArgs(func: Object) {//匹配函數括號里的參數 var method = func.toString();method = method.length > 500 ? method.substring(0, 500) : method;method = method.replace("\r|\n|\\s", "")var args = method.match(/.*?\(.*?\)/i);if (args == null) throw Error('can not match method parameters');method = args[0];method = method.replace(/.*?\(|\)/, "").replace(')', '');//分解參數成數組 var arr = method.split(",").map(function (arg) {//去空格和內聯注釋 return arg.replace(/\/\*.*\*\//, "").trim();}).filter(function (args) {//確保沒有undefineds return args;});return arr }

    ActionParamDescriptor 對象結構

    export declare type parameterFromType = 'query' | 'body' | 'form' | 'header' | 'cookie' | 'auto' export class ActionParamDescriptor {/*** action參數的action名稱* * @type {string}* @memberof ActionParamDescriptor*/actionMethodName: string/*** 參數名稱* * @type {string}* @memberof ActionParamDescriptor*/parameterName: string/*** 參數所在類* * @type {Object}* @memberof ActionParamDescriptor*/target: Object/*** 參數類型的類別* * @type {('complex' | 'simple')}* @memberof ActionParamDescriptor*/parameterTypeType: 'complex' | 'simple'/*** 參數對象的類型(class)對象* * @type {Function}* @memberof ActionParamDescriptor*/parameterType: Function/*** 參數所在參數類別的順序* * @type {(number | undefined)}* @memberof ActionParamDescriptor*/parameterIndex: number | undefined/*** 當前參數屬性屬于什么類型* * @type {('classProperty'|'methodParameter')}* @memberof ActionParamDescriptor*/localtionType: 'classProperty' | 'methodParameter'/*** 標記參數應該從什么地方解析* * @type {parameterFromType}* @memberof ActionParamDescriptor*/parameterFromType: parameterFromType }

    參數的自動綁定實現---基本使用方法

    可以在action上標記某一個參數從什么地方(query、form、body、cookie、header)進行解析,
    也可以標記某個參數是一個復雜的查詢參數,可以指定這個參數的類型。
    當然復雜的查詢class的每一個屬性都可以指定解析來源,當然也必須使用裝飾器來修飾一下,不然我們就沒法知道有這個屬性需要進行解析啦。

    import { BaseController, post, fromQuery, fromBody, fromCookie, fromHeader, property } from "../src/index" export class demoActionBodyParams {id: string;name: string;pageSize: number;body: {req_bb: string} } export class demoActionQueryParams {@property()id: string;@property()name: string;@property()pageSize: number;@fromCookie()cookieName: string;@fromHeader()headerName: string;@fromBody()body: any; } export class demoController extends BaseController {@post()demoAction(@fromQuery(type => demoActionQueryParams) query: demoActionQueryParams,@fromQuery() p2: string,@fromBody() req_body: demoActionBodyParams) {return { query, p2, req_body }} }

    參數的自動綁定實現---參數的說明元數據保存

    reflect-metadata 目前來說也還是ts的一個實驗性特性。可以用來輔助我們保存一些額外的數據。或者也可以理解成它是一個系統級別的靜態字典。
    那我們把對參數的一些特別設置都通過reflect-metadata保存下來,其實這里我們自己使用一個對象來保存也是可以的。

    const request_params_auto_bind_MetadataKey = Symbol("request_params_auto_bind_MetadataKey"); export function SetActionParamDescriptor(val: ActionParamDescriptor) {(val as any).targetName = val.target.constructor.nameif (val.parameterType) (val as any).parameterTypeName = val.parameterType.nameconsole.log('SetActionParamDescriptor', JSON.stringify(val));var arr: ActionParamDescriptor[] = [];if (val.localtionType === 'methodParameter') {arr = Reflect.getMetadata(request_params_auto_bind_MetadataKey, val.target, val.actionMethodName) || [];arr.push(val);Reflect.defineMetadata(request_params_auto_bind_MetadataKey, arr, val.target, val.actionMethodName);} else {arr = Reflect.getMetadata(request_params_auto_bind_MetadataKey, val.target) || [];arr.push(val);Reflect.defineMetadata(request_params_auto_bind_MetadataKey, arr, val.target);} }

    參數的自動綁定實現---參數的自動解析和對象生成

    嗯,大概是一些雜亂無章的代碼(^_^)。
    主要思路:

  • 獲得當前action的參數描述對象
  • 根據參數描述對象中的配置來解析參數
  • 就這么簡單,完事兒
  • //開始參數的自動解析操作var agrs = bindActionParameter(desc.ControllerType, desc.ControllerTypeName, desc.ActionType, desc.ActionName, req)function bindActionParameter(controllerType: Function, controllerName: string, actionType: Object, actionName: string, req: core.Request) { //獲得當前action的所有參數描述對象var arr = Reflect.getMetadata(request_params_auto_bind_MetadataKey, controllerType.prototype, actionName) || [] as ActionParamDescriptor[];var args = [arr.length];for (let index = 0; index < arr.length; index++) {args[arr[index].parameterIndex as number] = getParameterValue(req, arr[index], arr[index])//循環挨個進行解析}return args; } function bindClassParameter(req: core.Request, target: any, methodParmeterdesc: ActionParamDescriptor): any {var arr = Reflect.getMetadata(request_params_auto_bind_MetadataKey, target.prototype) as ActionParamDescriptor[];var obj = new target();for (let index = 0; index < arr.length; index++) {var desc = arr[index];obj[desc.parameterName] = getParameterValue(req, desc, methodParmeterdesc);}return obj; } function getParameterValue(req: core.Request, desc: ActionParamDescriptor, methodParmeterdesc: ActionParamDescriptor): any {//判斷當前action的參數是基本類型參數,還是復雜類型參數。如果是復雜類型就走class綁定邏輯。if (desc.parameterTypeType === 'simple' || (desc.localtionType === 'methodParameter' && desc.parameterFromType === 'body')) {return getparameterInRequest(desc.parameterFromType, desc.parameterName, req, methodParmeterdesc);} else if (desc.parameterTypeType === 'complex') {return bindClassParameter(req, desc.parameterType, methodParmeterdesc)}else throw Error('not support parameter type ' + desc.parameterTypeType) } //根據參數的不同配置進行不同解析。 function getparameterInRequest(fromType: parameterFromType, parameterName: string, req: core.Request, methodParmeterdesc: ActionParamDescriptor): any {switch (fromType) {case 'query':return getCompatibleParam(req.query, parameterName)case 'body':return req.bodycase 'header':return getCompatibleParam(req.headers, parameterName)case 'cookie':return getCompatibleParam(req.cookies, parameterName)case 'form':return getCompatibleParam(req.body, parameterName)case 'auto':return getparameterInRequest(methodParmeterdesc.parameterFromType, parameterName, req, methodParmeterdesc);}return undefined; } //忽略參數的大小寫問題。 function getCompatibleParam(obj: any, propertyName: string) {var lower = propertyName.toLowerCase();for (const key in obj) {if (obj.hasOwnProperty(key) && key.toLowerCase() == lower) {return obj[key];}} }

    需要說明的是,在這里有一個問題沒有解決。當參數指定類型為body的時候,我們沒有對參數進行更多的解析。也就意味著我申明的對象只有2個屬性,提交的body有3個屬性,最終在action里面的這個參數能拿到3個屬性。一直猶豫是否要做這里是否要做filter。
    從后端的角度來說是毫無疑問的,不可能我一個class只聲明了2個屬性,而到運行時的時候能取出來3個屬性。這是不可能的。
    但從前端的角度來講,這也許是一個比較好的特性。某些時候更省事情。比較接口部分參數透傳的時候之類的。

    參數的自動解析大致就到這里了,嗯,這部分代碼可能有點小邏輯。又加上沒有注釋有點難理解。不過我覺得這樣挺好的,哈哈哈

    轉載于:https://www.cnblogs.com/calvinK/p/nodejs-mvc-params-auto-mapping.html

    總結

    以上是生活随笔為你收集整理的【nodejs】让nodejs像后端mvc框架(asp.net mvc)一样处理请求--参数自动映射篇(6/8)...的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。