最近 和别人一块运维 开源 产品,后台需要用到 midway框架,所以进行学习。
首先就是midway的搭建,
首先 npm init midway ,初始化项目,选择 koa-v3 template
启动项目 npm run dev,此刻对应后台地址可以访问。
编写Controller
import { Controller,Get } from '@midwayjs/decorator'; @Controller('/') export class WeatherController{ @Get('/weather') async getWeatherInfo():Promise<string>{ return "Hello Weather!"; } }
添加参数处理
import { Controller,Get,Query } from '@midwayjs/decorator'; @Controller('/') export class WeatherController{ @Get('/weather') async getWeatherInfo(@Query('id') cityId:string):Promise<string> { return cityId; } }
编写Service
import { Provide } from '@midwayjs/decorator'; import { makeHttpRequest } from '@midwayjs/core'; import { WeatherInfo } from '../interface'; @Provide() export class WeatherService{ async getWeather(cityId:string):Promise<WeatherInfo> { const result = await makeHttpReauest(`http://www.weather.com.cn/data/cityinfo/${cityId}.html`,{ dataType:'json' }); if(result.state===200){ return result.data; } } }
在service里面 @Provide()是用来注入
在Controller中进行注入
@Inject()
weather:Weather;
weather.controller.ts代码修改如下
import { Controller,Get,Inject,Query } from '@midwayjs/decorator'; import { WeatherInfo } from '../interface'; import { WeatherService } from '../service/weather.service'; @Controller('/') export class WeatherController{ @Inject() weatherService:WeatherService; @Get('/weather') async getWeatherInfo(@Query('cityId') cityid:string):Promise<WeatherInfo>{ return this.weatherService.getWeather(cityid); } }
模板渲染
使用view-nunjucks组件
npm i @midwayjs/view-nunjucks --save
安装好组件之后在src/configuration.ts文件中启用组件
import * as view from '@midwayjs/view-nunjucks'; @Configuration({ import[view], importConfigs:[join(_dirname,'./config')] })
然后在src/config/config.default.ts中配置组件,指定 nunjucks模板。
import { MidwayConfig } from '@midwayjs/core'; export default{ view:{ defaultViewEngine: 'nunjucks' } }
然后在根目录设置模板内容,view/info.html
<!DOCTYPE html> <html> <head> <title>天气预报</title> <style> .weather_bg { background-color: #0d68bc; height: 150px; color: #fff; font-size: 12px; line-height: 1em; text-align: center; padding: 10px; } .weather_bg label { line-height: 1.5em; text-align: center; text-shadow: 1px 1px 1px #555; background: #afdb00; width: 100px; display: inline-block; margin-left: 10px; } .weather_bg .temp { font-size: 32px; margin-top: 5px; padding-left: 14px; } .weather_bg sup { font-size: 0.5em; } </style> </head> <body> <div class="weather_bg"> <div> <p> {{city}}({{WD}}{{WS}}) </p> <p class="temp">{{temp}}<sup>℃</sup></p> <p> 气压<label>{{AP}}</label> </p> <p> 湿度<label>{{SD}}</label> </p> </div> </div> </body> </html>
然后调整Controller代码,将返回JSON变成模板渲染
主要是用 @midwayjs/koa 里面的Context
this.ctx.render('info',result.weather);
错误处理
定义错误 在src/error/weather.error.ts
import { MidwayError } from '@midwayjs/core'; export class WeatherEmptyDataError extends MidwayError{ constructor(err?:Error){ super('weather data is empty',{ cause:error }); if(err?.stack){ this.stack = err.stack; } } }
在service代码中进行抛出错误
throw new WeatherEmptyDataError
通过拦截器进行错误处理
在src/filter/weather.filter.ts中进行处理
import { Catch } from '@midwayjs/decorator'; import { Context } from '@midwayjs/koa'; import { WeatherEmptyDataError } from '../error/weather.error'; @Catch(WeatherEmptyDataError) export class WeatherErrorFilter{ async catch(err:WeatherEmptyDataError,ctx:context){ ctx.logger.error(err); return '<html><body><h1>weather data is empty</h1></body></html>'; } }
然后在生命周期ready时候启用filter
在ContainerLifeCycle中的OnReady
里面启用this.app.useFilter([ WeatherErrorFilter ]);
单元测试
import { createApp, close, createHttpRequest } from '@midwayjs/mock'; import { Framework, Application } from '@midwayjs/koa'; describe('test/controller/weather.test.ts', () => { let app: Application; beforeAll(async () => { // create app app = await createApp<Framework>(); }); afterAll(async () => { // close app await close(app); }); it('should test /weather with success request', async () => { // make request const result = await createHttpRequest(app).get('/weather').query({ cityId: 101010100 }); expect(result.status).toBe(200); expect(result.text).toMatch(/北京/); }); it('should test /weather with fail request', async () => { const result = await createHttpRequest(app).get('/weather'); expect(result.status).toBe(200); expect(result.text).toMatch(/weather data is empty/); }); });