描述

廖雪峰java语法教程, 半天时间过一遍语法,看到集合那里即可

dropwizard文档 半天时间过一遍 Getting Started 部分

代码

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里面就需要有这个东西的定义

xml中定义resultMap是指将sql返回的内容格式化到这个resultMap里面,类似django的serializer,但是并不智能,例如datetime他就不知道怎么处理,然后会报错,需要实现一个mappers.handlers.DateTimeTypeHandler, 然后在 bundles.MysqlBundle 里面注册这个handler,才能正确处理datetime格式的字段

xml中的parameterType="hashmap",对应于interface里面的Param注解,如果没有会报找不到参数

回调resource里面发现,ArticleMapper articleMapper = session.getMapper(ArticleMapper.class); mapper需要通过session.getMapper的形式,而session是在ParrotApplication中注册并且添加了ArticleMapper这个类, SqlSessionFactory sessionFactory = mysqlBundle.getSqlSessionFactory(); sessionFactory.getConfiguration().addMapper(ArticleMapper.class);。

public interface ArticleMapper {
Article select(@Param("id") Integer id, @Param("isActive") Boolean isActive);
List selectAll(@Param("isActive") Boolean isActive,
@Param("offset") Integer offset,
@Param("limit") Integer limit);
Integer countAll (@Param("isActive") Boolean isActive);
}
/p>
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
SELECT id, title, cover, description, is_active, created
FROM extracter_wxarticle WHERE id = #{id}
and is_active=#{isActive} and is_delete=0
SELECT count(*)
FROM extracter_wxarticle
WHERE
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);
}
}

接下来