一个六年经验的python后端是怎么学习用java写API的(4) RestAPI,dropwizard 的第一组API

描述

上一篇(一个六年经验的python后端是怎么学习用java写API的(3)Java 开发环境搭建)开发环境准备完成后,就可以开始看java语法和框架了。

代码

parrot tag: first_api

dropwizard 与 django 的简单对比

dropwizard

java
└── com
    └── reworkplan
        ├── ParrotApplication.java
        ├── bundles                                                                                                    
        │   ├── CorsBundle.java
        │   └── MysqlBundle.java
        ├── common
        │   ├── Constants.java
        │   └── response
        │       ├── MetaListResponse.java
        │       └── MetaMapperResponse.java
        ├── config
        │   └── ParrotConfiguration.java
        ├── mappers
        │   ├── ArticleMapper.java
        │   └── handlers
        │       └── DateTimeTypeHandler.java
        ├── models
        │   └── Article.java
        ├── modules
        │   ├── ApplicationModule.java
        │   └── InjectorFactory.java
        └── resources
            ├── ArticlesResource.java
            └── BasePath.java

django

├── common
│   ├── __init__.py
│   ├── constants.py
│   ├── data_structure.py
│   ├── db.py
│   ├── exceptions.py
│   ├── oauth_utils.py
│   ├── permissions.py
│   ├── rest.py
│   ├── sms.py
│   ├── tools.py
│   ├── upload.py
│   └── weixin.py
├── config
│   ├── __init__.py
│   ├── settings
│   │   ├── __init__.py
│   │   ├── common.py
│   │   ├── development.py
│   │   ├── private.example.py
│   │   └── production.py
│   ├── urls.py
│   └── wsgi.py
├── extracter
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
├── manage.py  

web 框架的设计都是大同小异的,概念映射如下:

  • 主程序入口: django wsgi.py;dropwizard ParrotApplication.java
  • 环境变量等常量配置:django settings目录;dropwizard Config 目录 ParrotConfiguration.java,另外还有个配置文件config/environment.yml
  • 普通常量配置:django没有这个概念,我一般放在common.constants下;dropwizard我创建了个common Constants.java
  • 路由定义:django 的 urls.py;dropwizard 他是放在Resource类上通过Path注解实现,然后在ParrotApplication.java中注册Path类
  • 具体API实现:django 的 views.py 中继承自 APIView 的类,配置在urls.py中;dropwizard 的 Resource目录下的类,需要在然后在ParrotApplication.java中注册
  • 数据库的ORM:django 中 的 models.py;dropwizard 使用 mybatis,对应 mappers目录下的类,每个mappers还要在还需resources的xml目录下添加mybatis格式的xml去写具体的sql,并且需要写一个jdbc的sqlsession,需要在ParrotApplication中注册mapper和sqlsession,要自己做很多的基础工作(返回db的datetime需要自己写时间格式的handler等等)
  • 处理逻辑:django是直接在models上实现一些逻辑,这对应于dropwizard的service目录(代码写到这暂时没有逻辑需要处理所以没创建service),具体api接口需要柔和多个逻辑,django直接调用各个model上的逻辑+api内在写一部分;dropwizard则在resource.java里面调用各个service的Impl类组合逻辑
  • middleware:django 实现 middleware.py,在settings中配置,可以放在任何模块下;java放在一个叫做bundles的目录下,在ParrotApplication中注册

大概就是这样,另外java还有叫做注入的东西,所以我创建了modules目录 希望通过InjectorFactory做一些事情,暂时没调通

实现第一个 API Get /articles/{id}

实现 resource

  • 通过Path注解定义api的路由
  • Produces注解说返回一个json
  • GET注解说明的restful的get方法
  • 方法内的 PathParam注解是接受路由参数id
  • 方法内则需要一个mapper去执行数据库的操作
  • 定义一个自定义的reponse对象(或者不定义直接返回model对象),我习惯返回这两种格式: 列表 {"meta":{}, "data": []}, 单个元素或者普通数据 {"meta":{}, "data": {}}
@Path(BasePath.ARTICLE_API)
@Produces(APPLICATION_JSON)
public class ArticlesResource {
    private final SqlSessionFactory sessionFactory;

    public ArticlesResource(SqlSessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    @Path("/{id}")
    @GET
    @Timed
    public MetaMapperResponse get(@NotNull @PathParam("id") Integer articleId) {
        MetaMapperResponse response = new MetaMapperResponse();
        try (SqlSession session = sessionFactory.openSession()) {
            ArticleMapper articleMapper = session.getMapper(ArticleMapper.class);
            Boolean isActive = true;
            Article article = articleMapper.select(articleId, isActive);
            response.setData(article);
        }
        return response;
    }
}

实现mapper

  • 实现一个interface,定义mapper的方法
  • 然后需要在 resources的xml目录下实现这个mapper定义方法的sql,例如 java中定义了个Article select(@Param("id") Integer id, @Param("isActive") Boolean isActive), 那么xml里面就需要有这个东西的定义 SELECT id, title, cover, description, is_active, created FROM extracter_wxarticle WHERE id = #{id} and is_active=#{isActive} and is_delete=0

    ParrotApplication

    • 主入口在main,而run时候执行的命令是 server config/environment.yml,推测Enviroments读的是config/environment.yml
    • initialize和run的先后顺序目前我不清楚,可以看到initiallize里面注册的是middleware,run里面注册的是mapper和resource
    public class ParrotApplication extends Application {
        private final InjectorFactory injectorFactory;
        private final MysqlBundle mysqlBundle;
    
        public ParrotApplication() {
            this.injectorFactory = new InjectorFactory();
            this.mysqlBundle = new MysqlBundle();
        }
    
        public ParrotApplication(InjectorFactory injectorFactory) {
            this.injectorFactory = injectorFactory;
            this.mysqlBundle = new MysqlBundle();
        }
        @Override
        public void initialize(Bootstrap bootstrap) {
            bootstrap.addBundle(new TemplateConfigBundle());
            bootstrap.addBundle(new Java8Bundle());
            bootstrap.addBundle(new MultiPartBundle());
            bootstrap.addBundle(new CorsBundle());
            bootstrap.addBundle(mysqlBundle);
            super.initialize(bootstrap);
        }
    
        @Override
        public void run(ParrotConfiguration configuration, Environment environment) throws Exception {
            SqlSessionFactory sessionFactory = mysqlBundle.getSqlSessionFactory();
            sessionFactory.getConfiguration().addMapper(ArticleMapper.class);
    
            environment.jersey().register(JodaTimeParamConverterProvider.class);
            environment.jersey().register(new ArticlesResource(sessionFactory));
        }
        public static void main(String[] args) throws Exception {
            new ParrotApplication(new InjectorFactory()).run(args);
        }
    }

    接下来

    一个六年经验的python后端是怎么学习用java写API的(5) Service 和 google 依赖注入

你可能感兴趣的:(dropwizard,java,django)