实际上这个项目更像一个脚手架,是我多次开发HTTP API应用的经验总结。其中包含了常用的模块(如账户相关,版本更新等),以及本人认为比较好的开发方式和规范。
-
version.xml: 存放版本更新信息。entry节点代表一个版本,可设置一到多个,可自由切换。android和iphone节点的default属性表示当前的版本号, 对应entry的version节点值;
-
jdbc.properties: 这个都懂的,存放数据库连接信息;
-
configure.xml: root下的子节点可以随便写,但不能包含属性。在服务器运行过程中,一旦此文件内容发生了变化,会实时生效,无需重启。
举例,从下面的文件中获取prefix节点的值可使用AppProperty.me().getProperty("resource.prefix");
读取.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<resource>
<!--文件下载的地址前缀-->
<prefix>http://mlongbo.com/upload</prefix>
</resource>
</root>
AppConstant类存放诸如resource.prefix
的配置常量, AppProperty类用于读取配置,因此建议使用如:
//AppContant类的伪代码
public static final String RES_PREFIX = "resource.prefix";
//AppProperty类的伪代码
public String resourcePrefix() {
return getProperty(AppConstant.RES_PREFIX);
}
//业务模块中调用。获取配置
String str = AppProperty.me().resourcePrefix();
- 检查账号是否被注册:
GET
/api/account/checkUser
- 发送注册验证码:
POST
/api/account/sendCode
- 注册:
POST
/api/account/register
- 登录:
POST
/api/account/login
- 查询用户资料:
GET
/api/account/profile
- 修改用户资料:
PUT
/api/account/profile
- 修改密码:
PUT
/api/account/password
- 修改头像:
PUT
/api/account/avatar
- 意见反馈:
POST
/api/feedback
- 版本更新检查:
GET
/api/version/check
- 文件上传:
POST
/api/fs/upload
避免手拼json导致的错误,而使用将Java Bean序列化为JSON的方式。
json数据的根节点使用code字段标识本次响应的状态,如成功、失败、参数缺少或参数值有误,以及服务器错误等;message节点包含服务器响应回来的一些提示信息,主要是方便客户端开发人员在对接接口时定位错误出现的原因。
一般的,响应数据会分为两种,第一种为列表数据,如一组用户信息,另外一种是实体信息,如一条用户信息。data字段值为数组,携带列表数据,datum字段值为json对象,携带实体数据。
如:
//实体数据, 此结构对应DatumResponse类
{
"code": 1,
"message": "成功查询到该用户信息",
"datum": {
"name": "jack",
"lover": "rose",
"sex": 1,
"email": "jack@gmail.com"
}
}
//列表数据, 此结构对应DataResponse类
{
"code": 1,
"message": "成功查询到两条用户信息",
"data": [{
"name": "jack",
"lover": "rose",
"sex": 1,
"email": "jack@gmail.com"
},{
"name": "rose",
"lover": "jack",
"sex": 0,
"email": "rose@gmail.com"
}]
}
//登录成功, 此结构对应LoginResponse类
{
"code": 1,
"message": "登录成功",
"constant": {
"resourceServer": "http://fs.mlongbo.com" //文件地址前缀
}
"info": {
"name": "jack",
"lover": "rose",
"sex": 1,
"email": "jack@gmail.com"
}
}
//多文件上传, 部分成功,部分失败. 此结构对应FileResponse类
{
"code": 0, //只要有一个文件上传失败,code就会是0
"failed": ["file3"]
"datum": {
"file1": "/upload/images/file1.jpg",
"file2": "/upload/images/file2.jpg"
}
}
//缺少参数
{
"code": 2,
"message": "缺少name参数"
}
//参数值有误
{
"code": 2,
"message": "sex参数值只能为0或1"
}
//token无效
{
"code": 422,
"message": "token值是无效的,请重新登录获取"
}
附上本人常用的几种code值:
- 1 ok - 成功状态。查询成功,操作成功等;
- 0 faild - 失败状态
- 2 argument error - 表示请求参数值有误, 或未携带必需的参数值
- 3 帐号已存在
- 4 注册验证码错误
- 500 error - 服务器错误
- 404 not found - 请求的资源或接口不存在
- 422 token error - 未传递token参数,或token值非法
最多的还是非空检查, 这里重点说一下。因此,我写了一个工具。使用方法如下:
String name = getPara("name");
String lover = getPara("lover");
//使用此方式的前提是当前controller类要继承自BaseAPIController类
if (!notNull(Require.me().put(name, "name参数不能为空").put(lover,"lover参数不能为空"))) {
return;
}
//效果等同于如下代码:
if (StringUtils.isEmpty(name)) {
renderJson(new BaseResponse(2, "name参数不能为空"));
return;
}
if (StringUtils.isEmpty(lover)) {
renderJson(new BaseResponse(2, "lover参数不能为空"));
return;
}
//如果没有传递name参数,将会得到如下响应:
{
"code": 2,
"message": "name参数不能为空"
}
公共模块实现了基本功能,你可以根据自己的业务需求自由调整数据字段。
token, 顾名思义, 表示令牌,用于标识当前用户,同时增加接口的安全性。目前不支持过期策略,也仅支持一个用户一个终端的方式,即用户在一处登录后,再在另一处登录会使之前登录的token失效。
要启用token功能只需要配置TokenInterceptor拦截器类即可。
在使用时,客户端必须在配置了拦截器的接口请求中携带名为"token"的请求参数。
服务端在继承了BaseAPIController类后可以直接调用getUser();
函数获取当前用户对象. **注意: ** 为了正常地使用getUser函数,必须在登录接口中查出用户对象后,使用类似如下代码建立token与用户对象的映射:
User nowUser = User.user.findFirst(sql, loginName, StringUtils.encodePassword(password, "md5"));
//之后要将token值响应给客户端
String token = TokenManager.getMe().generateToken(nowUser));
在以往的接口开发过程中,我们都是使用一个统一的文件上传接口上传文件后,服务器响应上传成功后的文件地址,客户端再使用业务接口将文件地址作为参数值发送到服务器。这样做的好处之一是便于服务端将文件统一管理,比如做缓存或CDN;另一方面是为了减小耦合度,比如此时要换成七牛CDN存放静态文件,客户端只需要改写文件上传部分的代码即可。
目前的文件上传接口已实现一或多个文件同时上传,客户端在上传时,必须要为每个文件指定一个请求参数名, 参数名用于在上传结束后,根据服务器的响应数据判断哪些文件是上传失败的,哪些是上传成功的,以及成功后的文件地址是什么。
服务器响应实例如下:
//全部上传成功
{
"code": 1,
"message": "success",
"datum": {
"file1": "/upload/images/file1.jpg",
"file2": "/upload/images/file2.jpg"
}
}
//全部上传失败
{
"code": 0,
"message": "failed",
"failed": ["file1", "file2"]
}
//部分成功,部分失败
{
"code": 0, //只要有一个文件上传失败,code就会是0
"failed": ["file3"]
"datum": {
"file1": "/upload/images/file1.jpg",
"file2": "/upload/images/file2.jpg"
}
}
关于版本更新的说明,请查看第一章节中的项目配置,以及API文档;
意见反馈模块比较简单,你可以根据你的业务需求改动数据库字段,以及接口参数。
这个模块目前实现的接口有:
- 检查账号是否已注册
- 发送手机验证码
- 注册
- 登录
- 查询用户资料
- 修改用户资料
- 修改密码
如果使用手机验证码功能,你需要改写SMSUtils类的sendCode函数以实现短信发送功能;如果不使用手机验证码功能,可以在注册的接口代码中将验证码检查的功能去掉。在开发调试的过程中,可以访问code.html查询手机验证码。
如果用户表中的字段不能满足你的业务需求,你可以自由增删修改,但同时也需要修改注册和修改用户资料接口。
- Jetty插件: 无需使用tomcat,直接使用maven的jetty插件启动项目;
- ant工具: 一般情况下,我们的项目是在服务端使用maven自动构建的,但在开发过程中,代码经常改变需要重新部署,如果重新打包更新又比较麻烦,因此在服务端使用maven命令重新构建后,可直接执行ant命令将已改动的文件copy到tomcat应用目录。所以,若想正常使用该工具,你需要修改build.xml,将tomapp值修改为你的tomcat应用路径。
Copyright (c) 2015 Released under the MIT license.