ioc4ts v1.2.5-beta
ioc4ts ( IoC container for TypeScript )
简单介绍
IoC (Inversion of Control,控制反转),最早是从 Spring 框架中接触到这个概念,简单的说就是将创建对象的权力交给 IoC 容器管理,以达到模块之间的松耦合。ioc4ts 框架实现了简单的 IoC 容器,并接入 axios, 完成接口返回数据与对象实例之间的映射。
目前不建议在生产环境中使用 ioc4ts
安装
npm install ioc4ts
# 或者
yarn add ioc4ts
引入
import BeanFactory, { Get, Property, ReturnType, PathVariable } from 'ioc4ts'
配置 tsconfig.json
将 tsconfig.json 中的 experimentalDecorators
选项设置为 true
{
"experimentalDecorators": true
}
教程
实现的功能如下:
ApplicationContext
应用上下文@HttpRequest
注解@Property
注解@ReturnType
注解@Get
注解@Post
注解@Put
注解@Delete
注解@PathVariable
注解@RequestHeader
注解@RequestParam
注解@RequestBody
注解
ApplicationContext
应用上下文
ApplicationContext
是一个单例,通过 getInstance
方法获取 ApplicationContext
的实例。
const context = ApplicationContext.getInstance()
获取 BeanFactory
的方法为 getBeanFactory()
:
const context = ApplicationContext.getInstance()
const beanFactory = context.getBeanFactory()
@HttpRequest
注解
@HttpRequest
用于修饰一个类,作用是向 BeanFactory
注入这个类的实例作为一个 HttpRequest
的单例,@HttpRequest
修饰的类需要实现 HttpRequestInterface
接口,(注意:如果不实现 HttpRequestInterface
接口的话,也需要提供一个 request
方法,用于实现 Http 请求,这是由于 TypeScript 无法判断类实例是否实现了某个接口)
@HttpRequest()
class AxiosHttpRequest implements HttpRequestInterface {
private instance: AxiosInstance
constructor() {
this.instance = axios.create({ baseURL: 'http://localhost:3000' })
}
request(config: HttpRequestConfig<unknown>): Promise<AxiosResponse<Object>> {
return this.instance.request({
method: config.method,
url: config.path,
params: config.params,
headers: config.headers,
data: config.data
})
}
}
@Property
注解
@Property
注解用于修饰类的属性,需要提供一个 name
参数,用于定义从源(source
: 也就是一个 JSON
对象)中的名为 name
字段中的获取值。注意:@Property
注解目前不会做类型检查
class User {
@Property('name')
name: number
}
@ReturnType
注解
@ReturnType
注解用于修饰类的方法,用来定义方法的返回类型,目前需要配合 @Get
,@Post
等 Http 请求注解一起使用。(注意:类中不要定义同名的静态方法和成员方法!)
class User {
@ReturnType("User")
@Get('/user/1')
getById() {}
}
@Get
注解
@Get
注解用于修饰类的方法,被修饰的方法被调用时,方法体中的代码将不会被执行,取而代之的是执行一个 Http 的 Get
请求。
class User {
@Get('/user/1')
static getById() {}
}
@Post
注解
用法同 @Get
class User {
@Post('/user')
static create() {}
}
@Put
注解
用法同 @Get
class User {
@Put('/user/1')
static modify() {}
}
@Delete
注解
用法同 @Get
class User {
@Delete('/user/1')
static delete() {}
}
@PathVariable
注解
@PathVariable
用来修饰方法的参数,用于定义路径变量,需要提供一个 name
参数,与路径字符串中被 {}
包裹的变量名相同。
class User {
@Get('/user/{id}')
static getById(@PathVariable("id") id: number) {}
}
@RequestHeader
注解
@RequestHeader
用来修饰方法的参数,用来定义 Http 请求头的某个属性。
class User {
@Get('/user/1')
static getById(@RequestHeader("X-Token") token: string) {}
}
@RequestParam
注解
@RequestParam
用来修饰方法的参数,用来定义 Http 请求的某个路径参数。
class User {
@Get('/user')
static getByAge(@RequestParam("age") age: number) {}
}
@RequestBody
注解
@RequestBody
用来修饰方法的参数,用来定义 Http 请求的请求体内容。
class User {
@Post('/user')
static create(@RequestBody() user: User) {}
}
使用案例
1. 初始化 TypeScript 项目
以 yarn 为例子:
# 初始化项目
yarn init
# 全局安装 TypeScript
yarn global add typescript
# 初始化 TypeScript 项目
tsc -init
# 安装 ioc4ts
yarn add ioc4ts
2. 配置 tsconfig.json
将 tsconfig.json 中的 experimentalDecorators
选项设置为 true
, 并配置 include
选项。
{
"include": ["index.ts"],
"compilerOptions": {
"experimentalDecorators": true
}
}
3. 编写源文件 index.ts
import BeanFactory, { Get, Property, ReturnType, PathVariable } from 'ioc4ts'
class User {
// Property 没有做类型检查,如果 name 是其他类型也会映射成功
@Property("name")
name?: string;
@Property("age")
age?: number;
@Get("/{role}/{ID}")
@ReturnType("User")
static find(@PathVariable('role') role: string, @PathVariable('ID') id: number) {
// 加上 Get 注解以后,方法体内的代码不执行
console.log("User.find()");
}
self() {
console.log(`我是${this.name}, 我的年龄是${this.age}`);
}
}
class Teacher {
@Property("name")
teacherName?: string;
@Property("age")
teacherAge?: string;
self() {
console.log(`我是${this.teacherName}, 是一位老师, 我的年龄是${this.teacherAge}`);
}
}
const beanFactory = BeanFactory.getInstance();
const UserClass = beanFactory.getBeanClass("User");
UserClass.find('user', 1)
.then((user: User) => {
user.self();
})
.catch((err: any) => {
console.log(err);
});
4. 编写后端接口文件 server.js
const http = require('http')
http.createServer((req, res) => {
if(req.url === '/user/1') {
console.log(req.url, 'success')
const user = {
name: 'zhangsan',
age: '18'
}
res.writeHead(200, {'content-type': 'text/json'})
res.write(JSON.stringify(user))
} else {
res.writeHead(404)
}
res.end()
}).listen(3000)
console.log("Server is running, listening port 3000 ...")
5. 运行
运行服务器
node server.js
编译 index.ts
tsc
运行编译出来的 index.js
node index.js
6. 更改 index.ts, 再次编译运行,查看效果
ReturnType
注解的值改成 'Teacher'
后,将调用 Teacher
的 self()
方法
@ReturnType("Teacher")
@Get("/user/1")
static list() {}
需要注意的点
- 多个文件中的不同类的类名也不能相同,(例如:
Teacher
的类名不能设置与User
相同) @Property
注解中的值,对应接口返回的字段。@Property
没有做类型检查,如果name
是其他类型也会映射成功。- 加上
@Get
注解以后,方法体内的代码console.log("User.find()")
将不会被执行。
版本发布计划
1.2.x-beta 版需要实现的功能:
JSX
语法解析- 嵌套属性实现
- 实现
@Autowired
注解 - 假如
UserMapper
在UserListView
之后定义,UserMapper
找不到的问题需要解决。
示例:
@View("id", "UserListView")
class UserListView {
@Autowired("UserMapper")
userMapper: UserMapper
}
class UserMapper {
}
Todos
PropertyDefinition
需要实现,并且实现单例bean
的依赖注入,单例bean
的循环依赖问题需要解决。- 属性注入的类型转换需要实现。
- 实现
JSX
语法的解析 - 获取某个
JSX
模块的属性依赖 - 其他要做的暂时没想到了...
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago