热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何使用MongoDB结合JacksonJSON实现接口快速开发

MongoDB的存储是基于文档的,区别于以往的关系型数据库,它的数据模式可以更加宽松灵活,特别适合日益多变的互联网应用。在最开始接触MongoDB的时候就被它JavaScript式的操作所吸引,更被JSON式的数据存储所震撼。当时就有一种直觉,这将极大简化应用接口的开
MongoDB的存储是基于文档的,区别于以往的关系型数据库,它的数据模式可以更加宽松灵活,特别适合日益多变的互联网应用。在最开始接触MongoDB的时候就被它Javascript式的操作所吸引,更被JSON式的数据存储所震撼。当时就有一种直觉,这将极大简化应用接口的开发工作,使得数据交互变得异常轻松。下面我将以示例代码的方式介绍我的使用方法。
本示例代码使用了如下开发包:
MongoDB的官方Driver包:mongo-2.7.3.jar
基于MongoDB的ORM产品:morphia-0.99.jar
性能与功能都很棒的Jackson JSON:jackson-all-1.9.3.jar
另外还要辅助一些其他的依赖包:
morphia-logging-slf4j-0.99.jar
slf4j-api-1.6.1.jar
slf4j-nop-1.6.1.jar

上面的两篇文章是本人总结的一些经验之谈。作为参考,朋友们可以在遇到问题的时候参阅上面两篇文章。
下面进入正题:
我的思路分为两方面,即数据的输入和数据的输出。
输入源是一个文本文件,其中的数据来自SQL Server中的Northwind示例数据库。具体来说是从其中的订单信息中抽离出相关联的部分,经过加工整理而成。(数据已经上传到CSDN资源频道,下载地址:http://download.csdn.net/detail/chaijunkun/4067684,不要资源分哦!)通过按行读取文件中的内容模拟Web应用各客户端发来的数据,然后将它们存储到MongoDB中;
输出部分将实现一个按条件查询,从MongoDB中得到的查询结果将通过控制台输出。这样就能模拟Web应用服务端响应请求,将数据推送到客户端页面的场景了。
(特别注意:本文中设计到的所有源代码都是UTF-8格式编码的)
先实现一个连接属性的配置
MongoDBConnConfig.java
package net.csdn.blog.chaijunkun;
public class MongoDBConnConfig {
        //MongoDB主机名称或IP
        public static final String SERVER= "localhost";
        //MongoDB端口
        public static final int PORT= 27017;
        //使用的数据库名称
        public static final String ORDERS_DATABASE= "orders";
}
再实现一个Morphia框架与MongoDB的集成方法 MongoDBDataStore.java
package net.csdn.blog.chaijunkun;
import java.net.UnknownHostException;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Morphia;
import com.mongodb.Mongo;
import com.mongodb.MongoException;
/**
 * MongoDB联合Morphia框架生成DataStore的类
 * @author chaijunkun
 *
 */
public class MongoDBDataStore {
        /**
         * 生成Orders数据库Datastore对象
         * @return 返回Datastore对象 发生异常返回为null
         */
        public static Datastore getOrdersInstance(){
                Mongo connection = null;
                try {
                        connection = new Mongo(MongoDBConnConfig.SERVER, MongoDBConnConfig.PORT);
                } catch (UnknownHostException e) {
                        return null;
                } catch (MongoException e) {
                        return null;
                }
                Morphia morphia= new Morphia();
                return morphia.createDatastore(connection, MongoDBConnConfig.ORDERS_DATABASE);
        }
}
我们还需要一个Java对象到MongoDB文档和Java对象到输出JSON对象的POJO实体: OrderInfo.java
package net.csdn.blog.chaijunkun.entities;
import java.util.Date;
import org.bson.types.ObjectId;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.map.annotate.JsonDeserialize;
import org.codehaus.jackson.map.annotate.JsonSerialize;
import com.google.code.morphia.annotations.Entity;
import com.google.code.morphia.annotations.Id;
import com.google.code.morphia.annotations.PostPersist;
import com.google.code.morphia.annotations.PrePersist;
//morphia中的注解 标明该对象存入orderInfo集合中 并且不存储类名
@Entity(value="orderInfo", noClassnameStored= true)
public class OrderInfo {
        //morphia中的注解 标明该key为标识字段(MongoDB中特殊的ObjectId字段)
        @Id
        //Jackson中的注解 标明在序列化与反序列化过程中不使用该key
        @JsonIgnore(value= true)
        private ObjectId id;
        private Long orderId;
        private String productName;
        private Integer quantity;
        private Float unitPrice;
        //Jackson中的注解 标明该字段使用自定义的DateSerializer类实现序列化
        @JsonSerialize(using= DateSerializer.class)
        //Jackson中的注解 标明该字段使用自定义的DateDeserializer类实现反序列化
        @JsonDeserialize(using= DateDeserializer.class)
        private Date orderDate;
        private String contactName;
        private String address;
        private String phone;
        @SuppressWarnings("unused")
        //morphia中的注解 指示在存入MongoDB之前的操作
        @PrePersist
        private void beforeSaving(){
                System.out.println("即将保存对象:"+ this.toString());
        }
        @SuppressWarnings("unused")
        //morphia中的注解 指示在存入MongoDB之后的操作
        @PostPersist
        private void afterSaving(){
                System.out.println("对象保存完毕:"+ this.toString());
        }
        //以下就是Getters和Setters了
        public ObjectId getId() {
                return id;
        }
        public void setId(ObjectId id) {
                this.id = id;
        }
        public Long getOrderId() {
                return orderId;
        }
        public void setOrderId(Long orderId) {
                this.orderId = orderId;
        }
        public String getProductName() {
                return productName;
        }
        public void setProductName(String productName) {
                this.productName = productName;
        }
        public Integer getQuantity() {
                return quantity;
        }
        public void setQuantity(Integer quantity) {
                this.quantity = quantity;
        }
        public Float getUnitPrice() {
                return unitPrice;
        }
        public void setUnitPrice(Float unitPrice) {
                this.unitPrice = unitPrice;
        }
        public Date getOrderDate() {
                return orderDate;
        }
        public void setOrderDate(Date orderDate) {
                this.orderDate = orderDate;
        }
        public String getContactName() {
                return contactName;
        }
        public void setContactName(String contactName) {
                this.contactName = contactName;
        }
        public String getAddress() {
                return address;
        }
        public void setAddress(String address) {
                this.address = address;
        }
        public String getPhone() {
                return phone;
        }
        public void setPhone(String phone) {
                this.phone = phone;
        }
}
我们注意到上面的POJO实体中包含Date(日期)类型的数据。这类数据特别指定了它的序列化与反序列化方法,下面我们来具体看一下: 序列化方法:DateSerializer.java
package net.csdn.blog.chaijunkun.entities;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonSerializer;
import org.codehaus.jackson.map.SerializerProvider;
public class DateSerializer extends JsonSerializer{
        @Override
        public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
                        throws IOException, JsonProcessingException {
                SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                String formatedDate= sdf.format(date);
                jsonGenerator.writeString(formatedDate);
        }
}
这其实是Jackson中的一个很实用的功能,通过自定义序列化器,可以实现Java对象到JSON的数据格式自定义。例如Date的格式我们可以任意改写。上面的泛型类被具象为Date类型。重写了serialize方法。输入的date参数就是将要被序列化的数据,jsonGenerator就是序列化的上下文。当数据内容被整理好后将内容写入序列化的上下文中就完成了自定义过程。 类似地,我们来看一下反序列化方法DateDeserializer.java
package net.csdn.blog.chaijunkun.entities;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.DeserializationContext;
import org.codehaus.jackson.map.JsonDeserializer;
public class DateDeserializer extends JsonDeserializer{
        @Override
        public Date deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
                        throws IOException, JsonProcessingException {
                String unformatedDate= jsonParser.getText();
                SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                Date retVal;
                try {
                        retVal = sdf.parse(unformatedDate);
                } catch (ParseException e) {
                        return null;
                }
                return retVal;
        }
}
泛型的JSON反序列化类被我们具象成了Date类型的,并且重写了deserialize方法。传入的jsonParser是反序列化过程中的上下文,通过它我们可以找到当前处理的JSON字段内容。然后将内容按照特定的要求来生成对应的数据类型(Date),然后作为返回值将其返回。此时POJO中相应的字段就顺利完成了反序列化。另外这样做还能保证类型安全。
2012年12月17日补充:
最近有一个需求,需要在序列化与反序列化对象的时候对数据进行修改,当发现数据源值为空时需要让生成的JSON显示改字段为“游客”。可是我无论如何指定序列化器与反序列化器都无效。程序根本走不到指定的代码中去。后来我得出结论,Jackson JSON在反序列化对象的时候,若JSON数据中对应属性为null,则不会走自定义的反序列化器;同样地,当你设置对象的某个属性值为null时,在将其序列化成JSON时,也不会走自定义的序列化器。因此若有类似的需求,请在序列化与反序列化之前通过硬代码形式判断和修改,千万不要什么事都指望着序列化器与反序列化器。
再来看如何将数据输入MongoDB:
JSONTransformData.java
package net.csdn.blog.chaijunkun;
import java.net.UnknownHostException;
import net.csdn.blog.chaijunkun.entities.OrderInfo;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.Key;
import com.mongodb.MongoException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonParser;
import org.codehaus.jackson.map.ObjectMapper;
public class JSONTransformData {
        public static void main(String[] args) throws UnknownHostException, MongoException{
                //创建Jackson全局的objectMapper 它既可以用于序列化 也可以用于反序列化
                ObjectMapper objectMapper= new ObjectMapper();
                //得到JSON处理的工厂对象
                JsonFactory jsOnFactory= objectMapper.getJsonFactory();
                //得到Morphia框架的Datastore对象用于数据库操作
                Datastore ds= MongoDBDataStore.getOrdersInstance();
                //为保证每次本程序都得到相同结果 需要将之前的过期数据库删除
                ds.getMongo().dropDatabase(MongoDBConnConfig.ORDERS_DATABASE);
                //进入读文件阶段
                File dataFile= new File("jsonData.txt");
                FileReader fr;
                Integer idx=1;
                try {
                        fr = new FileReader(dataFile);
                        BufferedReader br=new BufferedReader(fr);
                        String currentJsOnStr= null;
                        try {
                                //按行读取
                                while((currentJsOnStr= br.readLine())!=null){
                                        currentJsOnStr= new String(currentJsonStr.getBytes(), "UTF-8");
                                        if (currentJsonStr.trim().equals("")){
                                                continue;
                                        }
                                        //进入反序列化阶段
                                        //通过JSON处理工厂对象创建JSON分析器
                                        JsonParser jsOnParser= jsonFactory.createJsonParser(currentJsonStr);
                                        //反序列化的关键
                                        OrderInfo orderInfo= jsonParser.readValueAs(OrderInfo.class);
                                        if (orderInfo!=null){
                                                //将对象存入MongoDB
                                                Key key= ds.save(orderInfo);
                                                if (key!= null){
                                                System.out.println("已存入:"+ key.getId() + ",元素序列:"+ idx);
                                                System.out.println(currentJsonStr);
                                                }else{
                                                        System.out.println("元素序列"+ idx+ "发生错误,JSON:");
                                                        System.out.println(currentJsonStr);
                                                        break;
                                                }
                                        }
                                        idx++;
                                }
                        } catch (UnsupportedEncodingException e) {
                                e.printStackTrace();
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                } catch (FileNotFoundException e) {
                        e.printStackTrace();
                }
        }
}
通过代码中的注释,我们不难理解各行代码的含义。并且整个代码也很简洁。 以下是运行结果片段:
即将保存对象:net.csdn.blog.chaijunkun.entities.OrderInfo@1f8d244
对象保存完毕:net.csdn.blog.chaijunkun.entities.OrderInfo@1f8d244
已存入:4f3ca1785a27520bbb93c4c5,元素序列:2152
{"orderId":11077, "productName":"Louisiana Hot Spiced Okra", "quantity":1, "unitPrice":17.00, "orderDate":"1998-05-06 00:00:00", "contactName":"Paula Wilson", "address":"2817 Milton Dr.", "phone":"(505) 555-5939"}
即将保存对象:net.csdn.blog.chaijunkun.entities.OrderInfo@b48b11
对象保存完毕:net.csdn.blog.chaijunkun.entities.OrderInfo@b48b11
已存入:4f3ca1785a27520bbb93c4c6,元素序列:2153
{"orderId":11077, "productName":"Rd Kaviar", "quantity":2, "unitPrice":15.00, "orderDate":"1998-05-06 00:00:00", "contactName":"Paula Wilson", "address":"2817 Milton Dr.", "phone":"(505) 555-5939"}
最后我们再来看一下查询的结果如何进行反序列化: JSONQueryDemo.java
package net.csdn.blog.chaijunkun;
import java.io.IOException;
import java.io.StringWriter;
import java.net.UnknownHostException;
import java.util.Iterator;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper;
import net.csdn.blog.chaijunkun.entities.OrderInfo;
import com.google.code.morphia.Datastore;
import com.google.code.morphia.query.Query;
import com.mongodb.MongoException;
public class JSONQueryDemo {
        public static void main(String[] args) throws UnknownHostException, MongoException {
                //创建Jackson全局的objectMapper 它既可以用于序列化 也可以用于反序列化
                ObjectMapper objectMapper= new ObjectMapper();
                //得到Morphia框架的Datastore对象用于数据库操作
                Datastore ds= MongoDBDataStore.getOrdersInstance();
                //按条件进行查询 这里的条件是orderId等于10875的所有信息
                //这里特别注意key和条件关系式"="之间要有空格
                Query queryResult= ds.find(OrderInfo.class, "orderId =", 10875);
                //创建查询结果的迭代器
                Iterator it= queryResult.iterator();
                //遍历查询结果
                while(it.hasNext()){
                        OrderInfo orderInfo= it.next();
                        System.out.println("================================================");
                        //由于Jackson写出JSON内容时统一采用流式写出
                        //为了以字符串形式能够展示生成的JSON 这里特别用到了StringWriter
                        StringWriter sw= new StringWriter();
                        JsonGenerator jsOnGenerator= null;
                        try {
                                //从全局的objectMapper建立JSON处理工厂,随即建立JSON生成器
                                jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(sw);
                                //流式向StringWriter中写入JSON
                                jsonGenerator.writeObject(orderInfo);
                                jsonGenerator.flush();
                                jsonGenerator.close();
                                //输出的JSON字符串
                                System.out.println(sw.toString());
                        } catch (IOException e) {
                                e.printStackTrace();
                        }
                }
                System.out.println("查询完成");
        }
}
下面是查询结果: ================================================
{"orderId":10875,"productName":"Teatime Chocolate Biscuits","quantity":25,"unitPrice":9.2,"orderDate":"1998-02-06 12:00:00","contactName":"Christina Berglund","address":"Berguvsvgen  8","phone":"0921-12 34 65"}
================================================
{"orderId":10875,"productName":"Zaanse koeken","quantity":21,"unitPrice":9.5,"orderDate":"1998-02-06 12:00:00","contactName":"Christina Berglund","address":"Berguvsvgen  8","phone":"0921-12 34 65"}
================================================
{"orderId":10875,"productName":"Maxilaku","quantity":15,"unitPrice":20.0,"orderDate":"1998-02-06 12:00:00","contactName":"Christina Berglund","address":"Berguvsvgen  8","phone":"0921-12 34 65"}
查询完成
我们看到,查询出的结果已经按照我们的约定方式进行显示了。 本文总结了一套完整的利用MongoDB与Jackson JSON框架结合实现快速开发应用接口的例子。在实际生产环境中,如果需求有所变动,我们完全可以通过更改POJO实体的方法来随意扩展。希望以上例子能给朋友们一点启发。也欢迎关注此技术的朋友一起探讨。

推荐阅读
  • MongoDB核心概念详解
    本文介绍了NoSQL数据库的概念及其应用场景,重点解析了MongoDB的基本特性、数据结构以及常用操作。MongoDB是一个高性能、高可用且易于扩展的文档数据库系统。 ... [详细]
  • Redis:缓存与内存数据库详解
    本文介绍了数据库的基本分类,重点探讨了关系型与非关系型数据库的区别,并详细解析了Redis作为非关系型数据库的特点、工作模式、优点及持久化机制。 ... [详细]
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • MySQL Decimal 类型的最大值解析及其在数据处理中的应用艺术
    在关系型数据库中,表的设计与SQL语句的编写对性能的影响至关重要,甚至可占到90%以上。本文将重点探讨MySQL中Decimal类型的最大值及其在数据处理中的应用技巧,通过实例分析和优化建议,帮助读者深入理解并掌握这一重要知识点。 ... [详细]
  • 在CentOS 7环境中安装配置Redis及使用Redis Desktop Manager连接时的注意事项与技巧
    在 CentOS 7 环境中安装和配置 Redis 时,需要注意一些关键步骤和最佳实践。本文详细介绍了从安装 Redis 到配置其基本参数的全过程,并提供了使用 Redis Desktop Manager 连接 Redis 服务器的技巧和注意事项。此外,还探讨了如何优化性能和确保数据安全,帮助用户在生产环境中高效地管理和使用 Redis。 ... [详细]
  • ### 优化后的摘要本学习指南旨在帮助读者全面掌握 Bootstrap 前端框架的核心知识点与实战技巧。内容涵盖基础入门、核心功能和高级应用。第一章通过一个简单的“Hello World”示例,介绍 Bootstrap 的基本用法和快速上手方法。第二章深入探讨 Bootstrap 与 JSP 集成的细节,揭示两者结合的优势和应用场景。第三章则进一步讲解 Bootstrap 的高级特性,如响应式设计和组件定制,为开发者提供全方位的技术支持。 ... [详细]
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限
    小王详解:内部网络中最易理解的NAT原理剖析,挑战你的认知极限 ... [详细]
  • MongoDB核心概念与基础知识解析
    MongoDB 是一种基于分布式文件存储的非关系型数据库系统,主要采用 C++ 语言开发。本文将详细介绍 MongoDB 的核心概念和基础知识,包括其与传统 SQL 数据库的区别,数据库及集合的基本操作,如数据的插入、更新、删除和查询等。通过本文,读者可以全面了解 MongoDB 的基本功能及其应用场景。 ... [详细]
  • Uniswap 与 MoonPay 合作,引入法币交易功能。本文探讨这一合作对用户进入加密货币领域的安全性及便利性的影响。 ... [详细]
  • 本文探讨了如何通过优化 DOM 操作来提升 JavaScript 的性能,包括使用 `createElement` 函数、动画元素、理解重绘事件及处理鼠标滚动事件等关键主题。 ... [详细]
  • 本文介绍了SELinux的两种主要工作模式——强制模式和宽容模式,并提供了如何在CentOS 7中正确启用和配置SELinux的方法,以及在遇到登录问题时的解决策略。 ... [详细]
  • 近期尝试从www.hub.sciverse.com网站通过编程手段获取数据时遇到问题,起初尝试使用WebBrowser控件进行数据抓取,但发现使用GET方法翻页时,返回的HTML代码始终相同。进一步探究后了解到,该网站的数据是通过Ajax异步加载的,可通过HTTP查看详细的JSON响应。 ... [详细]
  • Jupyter Notebook多语言环境搭建指南
    本文详细介绍了如何在Linux环境下为Jupyter Notebook配置Python、Python3、R及Go四种编程语言的环境,包括必要的软件安装和配置步骤。 ... [详细]
  • 第一步java代码条件匹配与之对应的mongo数据查询第二步:java代码分组查询与之所对应的mongodb中sheel与所得出的表点击某个_id字段进入,所得出的图表为第三步:在 ... [详细]
author-avatar
诗人不失神
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有