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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

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

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

文章目錄

前情概要

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

參數(shù)的自動(dòng)綁定實(shí)現(xiàn)思路

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

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

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

    /*** 指示當(dāng)前參數(shù)從request對象的query中解析* * @export* @param {(target?: any) => Function} type * @returns {Function} */ export function fromQuery(type: (target?: any) => Function): Function; /*** 指示當(dāng)前參數(shù)從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) {//非聲明在屬性和參數(shù)上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的參數(shù)上val.localtionType = 'methodParameter'val.actionMethodName = propertyKey;val.parameterName = getArgs((target as any)[propertyKey])[parameterIndex];}//復(fù)雜類型if (thatArg.length > 0) {val.parameterTypeType = 'complex'val.parameterType = thatArg[0](target);}SetActionParamDescriptor(val); } function getArgs(func: Object) {//匹配函數(shù)括號(hào)里的參數(shù) 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(')', '');//分解參數(shù)成數(shù)組 var arr = method.split(",").map(function (arg) {//去空格和內(nèi)聯(lián)注釋 return arg.replace(/\/\*.*\*\//, "").trim();}).filter(function (args) {//確保沒有undefineds return args;});return arr }

    ActionParamDescriptor 對象結(jié)構(gòu)

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

    參數(shù)的自動(dòng)綁定實(shí)現(xiàn)---基本使用方法

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

    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 }} }

    參數(shù)的自動(dòng)綁定實(shí)現(xiàn)---參數(shù)的說明元數(shù)據(jù)保存

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

    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);} }

    參數(shù)的自動(dòng)綁定實(shí)現(xiàn)---參數(shù)的自動(dòng)解析和對象生成

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

  • 獲得當(dāng)前action的參數(shù)描述對象
  • 根據(jù)參數(shù)描述對象中的配置來解析參數(shù)
  • 就這么簡單,完事兒
  • //開始參數(shù)的自動(dòng)解析操作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) { //獲得當(dāng)前action的所有參數(shù)描述對象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])//循環(huán)挨個(gè)進(jìn)行解析}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 {//判斷當(dāng)前action的參數(shù)是基本類型參數(shù),還是復(fù)雜類型參數(shù)。如果是復(fù)雜類型就走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) } //根據(jù)參數(shù)的不同配置進(jìn)行不同解析。 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; } //忽略參數(shù)的大小寫問題。 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];}} }

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

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

    轉(zhuǎn)載于:https://www.cnblogs.com/calvinK/p/nodejs-mvc-params-auto-mapping.html

    總結(jié)

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

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