简介
ICEREST是一个非常轻量级只有200k左右的RESTful路由框架,通过ICEREST你可以处理url的解析,数据的封装,Json的输出,和传统的方法融合,请求的参数便是方法的参数,方法的返回值便是请求的返回值,同时我们希望ICEREST是一个能让人倍感呵护的框架。
官网地址:http://icerest.cc
MongoDB-Plugin是用于帮助JAVA开发者更容易使用MongoDB而开发的的插件
官方地址:https://github.com/T-baby/Mon...
本文代码已开源在GitHub:https://github.com/T-baby/ICE...
教程目标:教会大家基于ICEREST+MongoDB-Plugin开发一个简单的增删查改应用。
首先我们来看下这个demo的文件结构
相信大家一眼就能看出这是一个maven项目,在component文件夹中包含了两个验证器、一个bean类、一个model类。
首选我们为这个项目添加好依赖,在pom.xml中添加。
junit
junit
4.10
test
ch.qos.logback
logback-classic
1.1.2
com.alibaba
fastjson
1.2.7
javax.servlet
javax.servlet-api
3.1.0
com.cybermkd
ICEREST
1.0.1.2
com.cybermkd
ICEREST-PLUGIN
1.0.0
com.cybermkd
MongodbPlugin
1.0.6.3
添加完以后在config文件夹中创建AppConfig类:
public class AppConfig extends Config {
/**
* Config constant
* 配置常量,目前只能配置render,其他全局配置会自动读取根目录下的application.properties文件,建议用默认
*/
public void configConstant(ConstantLoader constantLoader) {
//通过后缀来返回不同的数据类型 你可以自定义自己的 render,一般无需配置
//如:public class FreemarkerRender extends Render{}
//目前支持json,text,file三种输出
//constantLoader.addRender("ftl", new FreemarkerRender());
constantLoader.setDefaultForward("/"); //单页应用会用到,用来跳过对/的拦截
}
/**
* Config resource
* 配置Resource路由的扫描目录,ICEREST是自动绑定路由的
*/
public void configResource(ResourceLoader resourceLoader) {
resourceLoader.addIncludePackages("com.cybermkd.component");
}
/**
* Config plugin
* 配置插件
*/
public void configPlugin(PluginLoader pluginLoader) {
MongoIceRestPlugin mongoIcePlugin = new MongoIceRestPlugin();
mongoIcePlugin.add("127.0.0.1", 27017);
mongoIcePlugin.setDatabase("item");
pluginLoader.add(mongoIcePlugin);
}
/**
* Config interceptor applied to all actions.
* 全局拦截,会在进入路由后,执行方法前执前
*/
public void configInterceptor(InterceptorLoader interceptorLoader) {
//权限拦截器
//interceptorLoader.add(new SecurityInterceptor(2, new MyAuthenticateService()));
//Resource层事务的拦截器 @Transaction
//interceptorLoader.add(new TransactionInterceptor());
}
/**
* Config handler
* 全局的拦截,会在进入路由前执行
*/
public void configHandler(HandlerLoader handlerLoader) {
//跨域
handlerLoader.add(new CORSHandler("GET,POST,PUT,DELETE"));
}
/**
* Call back after ICEREST start
*/
public void afterStart() {
//ICEREST启动前执行的操作
}
/**
* Call back before ICEREST stop
*/
public void beforeStop() {
//ICEREST停止前执行的操作
}
}
config这里没有什么好说的,基本都已经写在了代码的注释。
我们现在罗列下我们需要开发的功能,我们要开发的是一个记录待办事项的工具要实现以下功能:
增加事项
删除事项
修改事项
获取所有事项
一个事项中包含了id、内容和创建时间。所以我们可以建一个bean类:
public class ItemBean extends MongoValidate {
@NotNull(message = "content can't be empty")
@NotBlank(message = "content can't be empty")
@Length(min = 1, max = 120, message = "content is too long or too short")
private String content;
private String creat_time;
@NotNull(message = "id can't be empty")
@NotBlank(message = "id can't be empty")
private String id;
public String getContent() {
return content;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public void setContent(String content) {
this.content = content;
}
public String getCreat_time() {
return creat_time;
}
public void setCreat_time(String creat_time) {
this.creat_time = creat_time;
}
}
为什么我们使用者mongodb却要要建bean类呢?在实际开发中经常会有同时数个人开发同一个项目,mongodb允许每一行的结构都不一样但这对于协同开发来说缺是噩梦。
所以为了方便协同工作建议使用bean类来约束数据的结构。
相信大家会看到@NotNull这样的注释,有什么用呢?在Mongodb Plugin 1.0.5后已经结合了hibernate的校验功能,遵循JSR 303规范。
具体使用见:http://www.cybermkd.com/mongo...
如果bean继承了MongoValidate这个类,就可以在创建bean对象的后用validation方法校验全部属性或者用validation(String... keys)校验某个属性。通过errorMessage获取错误信息。
之所以没命名为getErrorMessage是因为fastjson在反序列化的时候会自动处理带有getXXX的方法的变量。我们实际使用中又不需要errorMessage。
紧接着我们需要创建一个Model来操作数据库。MongoDB-Plugin的使用文档见:http://www.cybermkd.com/mongo...
public class ItemModel {
private static String collectionName = "storehouse";
public List get() {
return new MongoQuery().use(collectionName).findAll();
}
public List get(String id) {
return new MongoQuery().use(collectionName).byId(id).find();
}
public boolean save(ItemBean bean) {
System.out.println(JSON.toJSONString(bean));
bean.setId(null); //以免万一清空id
return new MongoQuery().use(collectionName).set(bean).save() > 0;
}
public boolean put(ItemBean bean) {
MongoQuery query = new MongoQuery().use(collectionName).byId(bean.getId());
/*因为在controller是直接获取整个对象的(在查询的时候为了大家方便会自动将_id变为id,但是mongodb实际存的还是_id),
/ 为了避免将id插入进去,特意清空。*/
bean.setId(null);
return query.modify(bean).update() > 0;
}
public boolean delete(ItemBean bean) {
return new MongoQuery().use(collectionName).byId(bean.getId()).delete() > 0;
}
}
我们现在能操作数据了,在插入事项的时候我们需要校验内容的长度,当删除、更新的时候我们需要校验这个事项是否存在,所以我们需要分别建两个校验器:
public class ContentValidator extends Validator {
@Override
public ValidResult validate(Params params, RouteMatch routeMatch) {
ItemBean item = params.getObject(ItemBean.class);
return new ValidResult().mongoValid(item, "content");
}
}
在ICEREST 1.0.1以上的版本已经融入了MongoDB-Plugin的校验功能,可以直接在拦截器中用new ValidResult().mongoValid(对象,属性名)校验,如果不加后面的属性名则是校验所有属性。通过params.getObject就可以将获取到的参数直接转为某个对象,这个对象属性中没有的值全部抛弃。
在bean中的message注释的文本,如果在校验器中校验发现传的值是有问题的就会将这个message直接放入ValidResult中,格式如下:
{
"error":"",
"errorMessage":""
}
public class IdValidator extends Validator {
@Override
public ValidResult validate(Params params, RouteMatch routeMatch) {
ItemBean item = params.getObject(ItemBean.class);
ValidResult result = new ValidResult();
result.mongoValid(item, "id");
if (result.isError()) {
return result;
}
ItemModel m = new ItemModel();
try {
if (m.get(params.get("id")).isEmpty()) {
throw new RuntimeException();
}
} catch (RuntimeException e) {
result.addError("error", "100");
result.addError("errorMessage", "id is error.");
}
return result;
}
}
在IdValidator中相信大家会发现一个try catch,在mongodb java driver中如果传来的id是随便乱写的那么会报错,我们利用这一点建个try catch拦截错误,只要mongodb driver 抛出错误就代表id是错的。
@API("/v1/item")
public class ItemController extends Resource {
ItemModel m = new ItemModel();
@GET()
public WebResult get() {
return render(m.get());
}
@POST(valid = {ContentValidator.class})
public WebResult post() {
ItemBean bean = getParams().getObject(ItemBean.class);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
bean.setCreat_time(df.format(new Date()));
return render(m.save(bean));
}
@PUT(valid = {IdValidator.class, ContentValidator.class})
public WebResult put() {
return render(m.put(getParams().getObject(ItemBean.class)));
}
@DELETE(valid = {IdValidator.class})
public WebResult delete() {
return render(m.delete(getParams().getObject(ItemBean.class)));
}
private WebResult render(Object obj) {
JSONObject json = new JSONObject();
json.put("result", obj);
return new WebResult(HttpStatus.OK, JSON.toJSONString(json));
}
}
在controller类中,我们先利用@API声明路径,用@GET等注释声明请求类型。用render封装了下返回的结果。
就这样一个简单的待办事项api就完成了呢~