前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >TodoBackend展示应用以及ActFramework的实现

TodoBackend展示应用以及ActFramework的实现

作者头像
老码农
发布2018-06-27 10:32:01
7140
发布2018-06-27 10:32:01
举报
文章被收录于专栏:老码农专栏老码农专栏

1. 关于TodoBackend

TodoBackend是一个公认的服务器后端技术展示平台, 现在已有85个不同语言和框架的展示项目(Showcase)加入这个平台上, 供开发人员参考学习.

开发TodoBackend的展示应用需要满足以下需求:

  • 应用必须是RESTful的服务, 所有的服务端点必须通过平台指定的测试
  • 应用必须实现对CORS的支持

更多关于TodoBackend展示应用的信息可以参见贡献指南

2. 框架/技术比较

比较一下常见框架/技术实现TodoBackend展示应用的情况:

Language/Platform

Implementation

Data Persistent

Line of Code

Java/JVM

ActFramework

MongoDB

64

Java/JVM

Spring4 + Boot

Java Set

200

Java/JVM

vertx

MongoDB

241

Java/JVM

Dropwizard

Java Map

115

Java/JVM

Jooby

Java Map

231

Java/JVM

SparkFramework

PostgreSQL

348

Kotlin/JVM

Rapidoid

Java Map

81

Closure/JVM

Closure

PostgreSql

142

Scala/JVM

Scala/Play2.5

PostgreSql

136

Golang

Gin

Map in memory

128

Golang

stdlib

In memory data structure

238

JavaScript/NodeJs

express

PostgreSql

130

JavaScript/NodeJs

Koa

Redis

169

Python

webpy

Array in memory

32

Python

django

sqllite

164

Ruby

rails

PostgreSql

311

PHP

symfony2

sqlite

130 (only count files in src dir)

Haskell

Snap

Sqlite

98

C#/.Net

Asp.Net core

? (Entity Framework)

887

C#/.Net

ASP.NET WebAPI 2

In memory list

215

Swift

Kitura

MongoDB

473

3. ActFramework的实现

第一个ActFramework的实现基于MongoDB. 源代码同时发布在码云github.

2.1 代码分析

1. 域模型

在这个实现中我们使用了MongoDB作为数据存储. Act通过act-morphia插件提供了很好的MongoDB支持. 该插件依赖于官方的Morphia文档对象转换层

Act在Morphia之上提出了一个革新特性: AdaptiveRecord, 这个特性运行后端开发人员在域模型类中只声明参与后端计算逻辑的字段. 而只需呈现在前端不参与后端运算的字段可以不用申明. 下面就是我们基于AdaptiveRecordTodo类:

代码语言:javascript
复制
@Entity(value = "todo", noClassnameStored = true)
public class Todo extends MorphiaAdaptiveRecordWithLongId<Todo> {

    // needs to define this property to make it comply with todobackend spec
    // unless https://github.com/TodoBackend/todo-backend-js-spec/issues/6
    // is accepted
    public boolean completed;

    // url is required as per backend test spec. However it is not required
    // to put into the database. So we mark it as Transient property
    @Transient
    public String url;

    // We will generate the derived property `url` after
    // saving the model and loading the model
    @PostLoad
    @PostPersist
    private void updateUrl() {
        url = Act.app().router().fullUrl(S.concat("/todo/", getIdAsStr()));
    }
}

如上所示, 我们并在Todo类中没有声明前端应用用到的title, order甚至连completed都可以省却. 之所以定义了completed的原因在这个TodoBackend test spec的问题

注意类中声明的url属性并非需要存入数据库的数据, 这是一个派生字段, 由GET TODO Item的URL和当前Todo的id联合产生. 我们使用了Morphia的PostLoadPostPersist生命周期回调方法来填充url的值

2. 服务

在传统的Java Web应用中像这个实现中将服务(也称为控制器)嵌入域模型类的做法非常罕见:

代码语言:javascript
复制
@Entity(value = "todo", noClassnameStored = true)
public class Todo extends MorphiaAdaptiveRecordWithLongId<Todo> {

    // needs to define this property to make it comply with todobackend spec
    // unless https://github.com/TodoBackend/todo-backend-js-spec/issues/6
    // is accepted
    public boolean completed;

    ....

    @Controller("/todo")
    @Produces(H.MediaType.JSON)
    public static class Service extends MorphiaDaoWithLongId<Todo> {

        @PostAction
        public Todo create(Todo todo, Router router) {
            return save(todo);
        }

        @GetAction("{id}")
        public Todo show(long id) {
            return findById(id);
        }
        ...
    }
}

但我们认为在这个TODO应用中这样的安排是可以的, 因为该服务只针对Todo一个域模型. 另一方面我们其实鼓励使用这种方式来组织代码, 原因如下:

  1. 操作(服务)与数据(域模型)封装到一个模块是面向对象提倡的做法, 这样可以让应用的内聚性增强
  2. 同时也提高了代码可读性. 因为不需要在类文件(甚至在不同的包目录)之间来回切换, 就可以在阅读服务控制代码的时候查看被操作的数据细节.

顺便提一下, 代码中的@Produces(H.MediaType.JSON) 其实都可以省去. 前提是TodoBackend接受并修改了这个问题报告

3. CORS

TodoBackend要求展示用例必须支持CORS. 于是我们在其他的实现中就会找到各种各样跟CORS相关的代码, 比如:

来自Java 8 with Spring 4 Boot 实现

代码语言:javascript
复制
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) res;
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PATCH");
    response.setHeader("Access-Control-Max-Age", "3600");
    response.setHeader("Access-Control-Allow-Headers", "x-requested-with, origin, content-type, accept");
    chain.doFilter(req, res);
}

和来自Java with Dropwizard implementation

代码语言:javascript
复制
private void addCorsHeader(Environment environment) {
    FilterRegistration.Dynamic filter = environment.servlets().addFilter("CORS", CrossOriginFilter.class);
    filter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), true, "/*");
    filter.setInitParameter("allowedOrigins", "*");
    filter.setInitParameter("allowedMethods", "GET,PUT,POST,DELETE,OPTIONS,HEAD,PATCH");
}

在Act中我们不需要类似的代码. 在Act中只需在配置文件中加入一行 cors=true即可. 这是另一个Act很酷的地方, 框架已经集成了很多工具帮助处理和Web应用相关的需求, 比如CORS和CSRF等等

总结

ActFramework提供了一个强大而灵活的机制来帮助开发人员迅速而简洁地开发RESTful的服务应用. 使用ActFramework开发人员只需要专注与业务逻辑而不需要去架设各种通用工具.

参考链接

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 关于TodoBackend
  • 2. 框架/技术比较
  • 3. ActFramework的实现
    • 2.1 代码分析
      • 1. 域模型
      • 2. 服务
      • 3. CORS
      • 总结
  • 参考链接
相关产品与服务
云数据库 MongoDB
腾讯云数据库 MongoDB(TencentDB for MongoDB)是腾讯云基于全球广受欢迎的 MongoDB 打造的高性能 NoSQL 数据库,100%完全兼容 MongoDB 协议,支持跨文档事务,提供稳定丰富的监控管理,弹性可扩展、自动容灾,适用于文档型数据库场景,您无需自建灾备体系及控制管理系统。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档