npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

j-spring-web

v1.1.2

Published

源码:[j-spring](https://github.com/892280082/j-spring) 轻量级的 IOC 库. 源码:[j-spring-web](https://github.com/892280082/j-spring-web) 基于 j-spring 和 express 的 WEB 框架。

Downloads

6

Readme

源码:j-spring 轻量级的 IOC 库. 源码:j-spring-web 基于 j-spring 和 express 的 WEB 框架。

前言

j-spring-web 就是换了壳的 express,这个项目并没有重复创建轮子,只是对喜欢 express 的人提供了更多的选择。对于 java 程序员,肯定能闻到熟悉的配方和味道。

源码阅读思路

1. 该框架是基于 j-spring 开发,所以最先要看的对象是启动类和 bean 的后置处理器!

1.1 启动类 SpringWebStarter

该类实例化了 Express 对象 app,即启动了 web 服务器!随后将 ExpressConfiguration 类对 app 进行配置, 最后将实体类 app:ExpressApp (该类信息导入自 j-spring0type-wrap) 注入到了 spring 的 bean 容器,方便后续的二次注入!

1.2 配置类后置处理器 ExpressAppEnhanceBeanProcessor

ExpressConfiguration:Express 配置类,用于对 express 进行配置。例如设置 app.get,app.use,设置 session,设置 bodyParse。

  • EjsViewConfigruation 设置 ejs 页面配置
  • ExpressMemorySessionConfiguration 设置内存 session,用于开发
  • BodyParseConfiguration body-解析
  • MorganLogConfigruation express 的日志配置转接到 spring 日志
  • StaticResourceConfigruation 静态资源配置

ExpressAppEnhanceBeanProcessor:该后置处理器主要用于搜集 ExpressConfiguration,用于 SpringWebStarter 使用

1.3 Controller 后置处理器

ControllerBeanConfiguration:controller 配置类,解析成路由映射信息。 ControllerBeanProcessor: 如果一个 bean 存在@Controller 注解,则被实例化成 ControllerBeanConfiguration (等同于 ExpressConfiguration)。

1.4 SpringParamterBeanPostProcessor 参数后置处理器

ParamEnhanceInterceptor: 一旦发生请求,遍历 action 中的所有参数和注解,然后通过该拦截器返回整理后的参数。

  • QueryParamEnhance: 解析 url 传参
  • PathVariableEnhance:解析 resful 传参
  • ReflectParamEnhance: 解析类型传参 例如 (@Param() req:Request)
  • SessionAttributeEnhance: 解析 session 取值 (@SessionAttribute('user') user:user)

SpringParamterBeanPostProcessor: 用于收集 ParamEnhanceInterceptor

1.5 SpringResultOperatePostProcessor 后置结果处理器

RouterEnhanceInterceptor: 路由提升拦截器,一旦匹配正确,可以更改原先的处理流程。

  • RenderEnhance: 页面渲染
  • ShuttleEnhance:模拟 rpc 远程调用

SpringResultOperatePostProcessor:用于收集 RouterEnhanceInterceptor 路由处理器!

启用流程

代码演示

import { spring, Component } from 'j-spring';
import { SpringMvcModule, Controller, Get, ResponseBody } from 'j-spring-mvc';
import { errorInfo } from 'j-spring-mvc/dist/springMvcExtends';

//控制器
@Controller('/api')
class ApiController {
  @Get()
  @ResponseBody()
  async hello() {
    throw 'requst error';
    return { msg: 'hello' };
  }
}

//控制器集合
const controllerList = [ApiController];

spring.bindModule([SpringMvcModule, controllerList]).invokeStarter();

设计思路

1.底层框架选用

对于 Node 上面的 WEB 框架,我最喜欢的还是 Express。

优点:

  • 简单高效,并且具有函数式的美感。
  • 生态丰富,拥有大量高质量的插件!
  • 框架稳定,几乎没有坑。

缺点:

  • 逼格有点低,划重点。
  • 不支持 IOC 和 AOP
  • 并且模块化不强,写起来散乱。
  • 代码层面有美感,但是对于业务抽象描述能力不够。

2.优化方案

j-spring 提供 IOC 和 AOP 的能力,把 express 进行模块化的封装。

  • 配置方面:定义 ExpressConfiguration 接口,提升模块化配置能力。
  • 路由方面:定义@controller 然后利用后置处理器进行解析,装配进 express 中

代码实现

代码会在过后的几个章节进行描述,其实也不多,毕竟只是加了一层壳。

代码展现

1.启动配置

//1.SpringWeb 配置
const SpringWebModule = [
  SpringWebStarter, //web启动器
  ExpressAppEnhanceBeanProcessor, // express配置后置处理器
  ControllerBeanProcessor, // 控制器后置处理器
  SpringParamterBeanPostProcessor,
]; // 参数反射后置处理器 用于处理@RequestPram之类的

//2.express 配置
const springWebConfig = [
  EjsViewConfigruation, // ejs视图配置
  ExpressMemorySessionConfiguration, // 内存session配置
];

//3.控制器
const controllerClassList = [
  StudentController, //学生路由控制器
  XiaoAiController, //测试
];

spring
  .bindModule([SpringWebModule, springWebConfig, controllerClassList])
  .loadConfig({ indexMsg: 'j-spring', root: __dirname }) //加载配置
  .invokeStarter(); //调用启动器

这里看到配置很多,主要是为了展示整个运行过程。其实 1 和 2 都可以放到 j-spring-web 里面作为默认配置一把到导出的。 例如

const SpringWebBaseModule = [...SpringWebModule,...springWebConfig]

spring.bindModule([SpringWebBaseModule,controllerClassList]).loadConfig({...}).invokeStarter();

如果需要更换其中一个配置,就只需要使用 j-spring 的 repalceClass 方法即可。例如将 session 交由 mysql 存储,更换指定配置即可。

spring
  .bindModule([SpringWebBaseModule, controllerClassList])
  .replaceClass(
    ExpressMemorySessionConfiguration,
    ExpressMysqlSeesionConfiguration
  ); //更换依赖即可

2.如何定义 express 配置

只要继承 ExpressConfiguration 接口即可。这样该配置就可以使用 j-spring 容器的能力,包括自动注入和装配。你可以写无限多个配置类,然后统一在 yaml 里面编写配置参数即可。

/**
 * ejs页面配置
 */
@Component()
export class EjsViewConfigruation implements ExpressConfiguration {
  @Value({ path: 'root', type: String })
  root: string;

  @Value({ path: 'express.viewPath', type: String, force: false })
  viewPath: string = 'view';

  load(app: any): void {
    app.set('views', path.join(this.root, this.viewPath));
    app.set('view engine', 'ejs');
  }

  isExpressConfiguration(): boolean {
    return true;
  }
}
//spring.bind(EjsViewConfigruation) 即可

3.设置路由

是不是熟悉的味道,嘿嘿。最大程度的还原了 springWeb 的编码风格。

  • 页面渲染就是返回一个数组 [页面路径,渲染数据]
  • @ResponseBody 就单纯返回 json 信息。
  • @PathVariable @RequestParam 跟 java 一致
  • @Param(key:string) 拿到 express 控制器原始的 req,res 对象
  • 这里的参数反射是支持异步的,并且可以在请求结束后,执行销毁操作。主要为了后期的事务操作。
//定义控制器
@Controller('/student')
export class StudentController {
  @Autowired({ clazz: StudentServiceImpl })
  service: StudentService;

  //页面渲染
  @Get()
  async index() {
    return ['index.ejs', { msg: 'hello world' }];
  }

  //接口返回
  @Get('/getStudentInfo/:id')
  @ResponseBody()
  async getStudentInfo(
    @PathVariable('id') id: string,
    @RequestParam('name') name: string
  ) {
    return { id, name };
  }

  @Get()
  @ResponseBody()
  async addSessionName(@Param('session') session: any) {
    session['name'] = 'xiaoAi';
    return { msg: 'add success!' };
  }
}

4.如何使用中间件

//定义中间件1
@Component()
class XiaoAiMustBeExist implements ExpressMiddleWare {
    isExpressMidldleWare(): boolean {
        return true;
    }
    invoke(req: any, res: any, next: Function): void {
        if(! req.session?.name){
            throw `xiaoai must be exist!`
        }
        next();
    }

}

//定义中间件2
@Component()
class OtherMiddleWare implements ExpressMiddleWare {...}

@Controller('xiaoai')
@ApiMiddleWare([XiaoAiMustBeExist])
export class XiaoAiController {

    @Get()
    @ResponseBody()
    @MiddleWare([OtherMiddleWare])
    async getXiaoAiName(@SessionAttribute('name') name:string){
        return {name}
    }


}
  • 使用 ExpressMiddleWare 接口创建中间件.
  • 使用@ApiMiddleWare 添加中间件到控制器的类上,可以作用于该控制器所有的方法。(常用如拦截器)
  • 使用@MiddleWare 也可以将中间件单独添加到方法上。
  • @ApiMiddleWare + @MiddleWare 可以混合使用,执行顺序以定义顺序为准。

总结

到这里 j-spring-web 就完成了,因为底层还是 express,所以运行的还是相当稳定的。

j-spring-web 包含了的优点以及优化了不足。

  • 简单高效,并且具有函数式的美感。(express)
  • 生态丰富,拥有大量高质量的插件! (express)
  • 框架稳定,几乎没有坑。(express)
  • 支持 IOC 和 AOP (j-spring)
  • 支持模块化 (j-spring)
  • 代码层面有美感
  • 业务抽象描述能力强