spring-moon
v0.0.6
Published
Core library for Spring Moon framework
Maintainers
Readme
Spring Moon
一个轻量级的 Node.js 框架,灵感来自 Spring Framework,支持分层架构和依赖注入。
✨ 特性
- 🚀 TypeScript 支持
- 💉 依赖注入容器(构造器注入)
- 🏗️ 分层架构装饰器(@Controller、@Service、@Mapper)
- 🔄 模块系统和组件扫描
- 🌐 请求上下文管理
- 📦 事务管理
- 🔒 HTTP 过滤器和处理器拦截器
- ⚙️ 配置文件支持(application.yml,类似 Spring Boot)
🎯 分层装饰器
类似 Spring Boot 的装饰器系统:
| 装饰器 | 用途 | 作用域 |
| ---------------- | ---------- | --------- |
| @Controller | 控制器层 | Request |
| @Service | 业务逻辑层 | Singleton |
| @Mapper | 数据访问层 | Singleton |
| @Component | 通用组件 | Singleton |
| @Configuration | 配置类 | Singleton |
| @Filter | HTTP 过滤器 | Singleton |
| @Interceptor | 处理器拦截器 | Singleton |
🚀 快速开始
安装
npm install spring-moon
# 或
pnpm add spring-moon
# 或
yarn add spring-moon基本使用
import { Controller, Service, Mapper, Module } from 'spring-moon'
// 数据访问层
@Mapper()
class UserMapper {
private users = [
{ id: 1, name: 'Alice', email: '[email protected]' },
{ id: 2, name: 'Bob', email: '[email protected]' },
]
findAll() {
return this.users
}
findById(id: number) {
return this.users.find(user => user.id === id)
}
}
// 业务逻辑层
@Service()
class UserService {
constructor(private userMapper: UserMapper) {}
getAllUsers() {
return this.userMapper.findAll()
}
getUserById(id: number) {
const user = this.userMapper.findById(id)
if (!user) {
throw new Error(`User with id ${id} not found`)
}
return user
}
}
// 控制器层
@Controller()
class UserController {
constructor(private userService: UserService) {}
@GetMapping('/api/users')
async handleGetAllUsers() {
return this.userService.getAllUsers()
}
@GetMapping('/api/users/:id')
async handleGetUser(@PathVariable('id') id: number) {
return this.userService.getUserById(id)
}
}
// 创建应用模块
const appModule = Module.create({
components: [
UserMapper, // @Mapper
UserService, // @Service
UserController, // @Controller
],
})
// 启动应用
async function bootstrap() {
const context = appModule.getContext()
const requestContext = context.startRequest()
try {
const userController = appModule.resolve<UserController>(UserController)
const allUsers = await userController.handleGetAllUsers()
console.log('All users:', allUsers)
const user = await userController.handleGetUser(1)
console.log('User 1:', user)
console.log(`Controllers: ${appModule.getControllers().length}`)
console.log(`Services: ${appModule.getServices().length}`)
console.log(`Mappers: ${appModule.getRepositories().length}`)
} finally {
context.endRequest()
}
}
bootstrap().catch(console.error)📚 核心概念
依赖注入
Spring Moon 使用构造器注入来管理依赖关系:
@Service()
class EmailService {
sendEmail(to: string, subject: string, body: string) {
console.log(`Sending email to ${to}: ${subject}`)
}
}
@Service()
class UserService {
constructor(
private userMapper: UserMapper,
private emailService: EmailService // 自动注入
) {}
async createUser(userData: any) {
const user = this.userMapper.create(userData)
await this.emailService.sendEmail(user.email, 'Welcome!', 'Welcome to our platform!')
return user
}
}作用域管理
- Singleton: 单例模式(默认),整个应用生命周期内只创建一个实例
- Request: 请求作用域,每个请求创建新实例
@Controller() // Request 作用域
class ApiController {}
@Service() // Singleton 作用域
class BusinessService {}配置系统(application.yml)
Spring Moon 支持类似 Spring Boot 的 YAML 配置文件,遵循"约定大于配置"的原则:
配置文件位置
YAML 仅从项目根下 resources/(与 src 同级)读取,不兼容 src/config 等其它路径:
resources/application.ymlresources/application-dev.ymlresources/application-prod.yml
多环境配置
支持多环境配置,通过 SPRING_PROFILES_ACTIVE 环境变量切换:
# 开发环境
SPRING_PROFILES_ACTIVE=dev pnpm run dev
# 生产环境
SPRING_PROFILES_ACTIVE=prod pnpm start配置文件示例
resources/application.yml(与 src 同级):
server:
port: 3000
host: localhost
spring:
moon:
application:
name: my-app
scanBasePackages: [] # 可选,默认扫描 src 目录
database:
url: postgresql://user:password@localhost:5432/dbnameresources/application-dev.yml:
server:
port: 3000
host: localhost
spring:
moon:
application:
name: my-app-devresources/application-prod.yml:
server:
port: 8080
host: 0.0.0.0
spring:
moon:
application:
name: my-app-prod配置优先级
配置优先级(从高到低):
- 环境变量(
SPRING_MOON_SERVER_PORT,DATABASE_URL等) application-{profile}.yml(环境特定配置)application.yml(基础配置)- 默认配置(约定)
读取配置
在代码中读取配置:
import { environment, getConfigValue } from 'spring-moon'
// 方式 1: 使用 Environment API
const port = environment.getNumber('server.port', 3000)
const dbUrl = environment.getString('database.url')
// 方式 2: 使用 getConfigValue
const appName = getConfigValue<string>('spring.moon.application.name')环境变量支持
支持以下环境变量:
SPRING_PROFILES_ACTIVE- 激活的环境(dev/prod)SPRING_MOON_SERVER_PORT- 服务器端口SPRING_MOON_SERVER_HOST- 服务器主机DATABASE_URL- 数据库连接 URLSPRING_MOON_DATABASE_URL- 数据库连接 URL(别名)SPRING_MOON_APPLICATION_NAME- 应用名称
模块系统
使用模块来组织和管理组件:
const userModule = Module.create({
components: [UserMapper, UserService, UserController],
})
const emailModule = Module.create({
components: [EmailService, EmailController],
})
const appModule = Module.create({
imports: [userModule, emailModule],
components: [AppController],
})请求上下文
管理请求级别的数据和状态:
const context = appModule.getContext()
// 开始请求
const requestContext = context.startRequest('req-123')
// 存储请求数据
context.setRequestData('userId', 123)
context.setRequestData('permissions', ['read', 'write'])
// 获取请求数据
const userId = context.getRequestData<number>('userId')
// 结束请求(清理资源)
context.endRequest()事务管理
简单的事务管理支持:
import { TransactionManager } from 'spring-moon'
const txManager = new TransactionManager()
async function transferMoney(fromId: number, toId: number, amount: number) {
const tx = await txManager.begin()
try {
// 添加操作到事务
txManager.addOperation(tx.id, {
type: 'debit',
data: { accountId: fromId, amount },
rollback: async () => {
// 回滚逻辑
await creditAccount(fromId, amount)
},
})
txManager.addOperation(tx.id, {
type: 'credit',
data: { accountId: toId, amount },
rollback: async () => {
await debitAccount(toId, amount)
},
})
// 提交事务
await txManager.commit(tx.id)
} catch (error) {
// 回滚事务
await txManager.rollback(tx.id)
throw error
}
}HTTP 过滤器
HTTP 过滤器作用于最外层 HTTP 请求链路,围绕整个 handleRequest 执行。适用于日志记录、CORS 处理、全局鉴权、统一 header 处理等场景。
import { Filter, HttpFilter, Request, Response } from 'spring-moon'
@Filter({ order: 0, patterns: ['/api/**'] })
class LoggingFilter implements HttpFilter {
order = 0
patterns = ['/api/**']
async doFilter(req: Request, res: Response, next: () => Promise<void>): Promise<void> {
const startTime = Date.now()
const method = req.method ?? 'GET'
const url = req.url ?? '/'
console.log(`📥 ${method} ${url} - Start`)
await next()
const duration = Date.now() - startTime
console.log(`📤 ${method} ${url} - End (${duration}ms)`)
}
}
@Filter({ order: 1, patterns: ['/api/**'], methods: ['POST', 'PUT', 'PATCH'] })
class BodySizeLimitFilter implements HttpFilter {
order = 1
patterns = ['/api/**']
methods = ['POST', 'PUT', 'PATCH']
async doFilter(req: Request, res: Response, next: () => Promise<void>): Promise<void> {
const contentLength = parseInt(req.headers['content-length'] || '0', 10)
const maxSize = 10 * 1024 * 1024 // 10MB
if (contentLength > maxSize) {
res.status(413).json({ error: 'Payload Too Large' })
return
}
await next()
}
}过滤器选项说明:
order: 执行顺序,数值越小越先执行(默认:0)patterns: 路径匹配模式- 精确匹配:
'/api/users' - 前缀匹配:
'/api/**'(匹配所有以/api/开头的路径)
- 精确匹配:
methods: HTTP 方法限定(大写),如['GET', 'POST']。不指定则匹配所有方法
处理器拦截器
处理器拦截器作用于"路由匹配 + 控制器方法调用"阶段,可以拦截控制器方法的执行,适用于权限验证、返回值包装、异常处理等场景。
import { Interceptor, HandlerInterceptor, HandlerContext, Request, Response } from 'spring-moon'
@Interceptor({ order: 0, patterns: ['/admin/**'], methods: ['GET', 'POST'] })
class AuthInterceptor implements HandlerInterceptor {
order = 0
patterns = ['/admin/**']
methods = ['GET', 'POST']
async preHandle(req: Request, res: Response, handlerCtx: HandlerContext): Promise<boolean> {
const token = req.headers['x-auth-token'] as string
if (!token || token !== 'secret-token') {
res.status(403).json({ error: 'Forbidden', message: 'Invalid authentication token' })
return false // 返回 false 中断后续处理
}
// 可以在这里设置请求上下文数据
console.log(`✅ Authenticated request to ${handlerCtx.controllerName}.${handlerCtx.methodName}`)
return true // 返回 true 或 void 继续处理
}
postHandle(req: Request, res: Response, handlerCtx: HandlerContext, result: any): any {
// 包装返回值
return {
success: true,
data: result,
timestamp: new Date().toISOString(),
}
}
async afterCompletion(req: Request, res: Response, handlerCtx: HandlerContext, error?: Error): Promise<void> {
if (error) {
console.error(`❌ Error in ${handlerCtx.controllerName}.${handlerCtx.methodName}:`, error.message)
} else {
console.log(`✅ Completed ${handlerCtx.controllerName}.${handlerCtx.methodName}`)
}
}
}
@Interceptor({ patterns: ['/api/**'] })
class ResponseTimeInterceptor implements HandlerInterceptor {
patterns = ['/api/**']
async preHandle(req: Request, res: Response, handlerCtx: HandlerContext): Promise<void> {
// 在请求对象上存储开始时间
;(req as any).startTime = Date.now()
}
postHandle(req: Request, res: Response, handlerCtx: HandlerContext, result: any): any {
const duration = Date.now() - ((req as any).startTime || Date.now())
// 在响应头中添加处理时间
res.setHeader('X-Response-Time', `${duration}ms`)
return result
}
}拦截器方法说明:
preHandle: 在控制器方法调用之前执行- 返回
false表示中断后续处理(不调用 controller) - 返回
true或void继续处理
- 返回
postHandle: 在控制器方法调用之后、响应写入之前执行- 可以修改返回值:返回新值将覆盖原返回值
- 返回
undefined则保留原值
afterCompletion: 在整个请求完成后执行(无论成功或异常)- 按拦截器顺序的逆序执行
- 适合做清理工作、日志记录等
执行顺序:
HTTP Request
↓
Filter Chain (按 order 顺序执行)
↓
Route Matching
↓
Interceptor.preHandle (按 order 顺序执行)
↓
Controller Method
↓
Interceptor.postHandle (按 order 顺序执行)
↓
Write Response
↓
Interceptor.afterCompletion (按 order 逆序执行)
↓
HTTP Response🛠️ CLI 工具
使用 spring-moon-cli 快速创建项目:
# 安装 CLI
npm install -g spring-moon-cli
# 创建新项目
spring-moon create my-app
# 进入项目目录
cd my-app
# 安装依赖
npm install
# 构建项目
npm run build
# 运行项目
npm start📖 API 文档
装饰器
@Component(name?)- 通用组件@Controller(path?)- 控制器@Service(name?)- 服务@Mapper(name?)- 数据访问层映射器(推荐)@Repository(name?)- 数据访问层(已废弃,请使用 @Mapper)@Configuration(name?)- 配置类@Filter(options?)- HTTP 过滤器@Interceptor(options?)- 处理器拦截器@Injectable(token?)- 可注入组件@Inject(token)- 依赖注入@Autowired- 自动装配
核心类
Container- 依赖注入容器Module- 模块管理ApplicationContext- 应用上下文TransactionManager- 事务管理器
🤝 贡献
欢迎贡献代码!请查看 贡献指南。
📄 许可证
MIT License - 查看 LICENSE 文件了解详情。
