智能表单之mongoDB的使用

   在去年工作中遇见一个较为复杂的模块:智能表单。智能表单其实就问卷星一样的东西,由客户来根据需求设计表单内容样式,然后发布出去收集大家所填写的数据,最后进行统计分析,生成图表。

   智能表单一开始遇见的困扰时数据库的设计。表单字段的不确定,对数据库要求的灵活性很大,所思之后解决方案主要有三:

   1.根据用户设计的表单内容动态生成数据库表

   2.使用一张非常多字段的,来容得下客户可能要求的最大字段个数。

   3.内存数据库。

   首先由于客户量不太小,第一种动态生成表的方式被否决了,怕数据库负担太大。第二种感觉有点太蠢了哈哈,然后就选择了第三种,由于需要进行统计分析,所有选择了mongDB来作为最终的解决方案。

   接下来就总结工作中如何把mongoDB整合到spring mvc,因为这个模块其实做起来很多,只对与mongDB沾边的进行一些简单举例:

   1.毋庸置疑,引坐标进pom.xml中,自行选择版本

        <!-- mongoDB依赖包 -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-mongodb</artifactId>
            <version>1.10.1.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongo-java-driver</artifactId>
            <version>3.2.2</version>
        </dependency>

   2.配置mongoDB数据源

        1.在applicationContext.xml中配置<context:property-placeholder  location="classpath:application.properties" ignore-unresolvable="true"/> 设置读取外部资源方便配置数据库信息  ignore-unresolvable="true"如果已经存在配置外部资源的则需要设置此属性,否则默认只读取一个。

        2.引入mongoBD配置在applicationContext中引入<import resource="spring-mongo.xml"/>单独拿到一个文件中来。

        3.编写spring-mongo.xml内容

    <!-- 加载mongodb的属性配置文件 -->
    <context:property-placeholder location="classpath:mongo.properties" ignore-unresolvable="true"/>
    <!-- spring连接mongodb数据库的配置 -->
    <mongo:mongo-client replica-set="${mongo.hostport}"  credentials="${mongo.username}:${mongo.password}@${mongo.dbname}" id="mongo">
        <mongo:client-options connections-per-host="${mongo.connectionsPerHost}"
                              threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
                              connect-timeout="${mongo.connectTimeout}" max-wait-time="${mongo.maxWaitTime}"
                              socket-timeout="${mongo.socketTimeout}"/>
    </mongo:mongo-client>
    <!-- mongo的工厂,通过它来取得mongo实例,dbname为mongodb的数据库名,没有的话会自动创建 -->
    <mongo:db-factory id="mongoDbFactory" dbname="${mongo.dbname}" mongo-ref="mongo"/>

    <!-- 只要使用这个调用相应的方法操作 -->
    <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    </bean>
    
    <!-- mongodb bean的仓库目录,会自动扫描扩展了MongoRepository接口的接口进行注入 -->
    <mongo:repositories base-package="com.dg.ptm.model.mongo"/>//其实在智能表单中并不需要数据库字段的映射,所以这边引入只是为了当时学习一下,没有真正用到。

   3.书写dao层,以方便使用,因为比较多,只简单列举几个,以便日后想起

   列举一:

    接口方法:

    /**
     * 根据某一字段条件进行模糊查询
     * @param field 字段名
     * @param param 参数值
     * @param cls 类型
     * @return
     */
    public List fuzzySearchByOneParam(String field, String param, Class cls);

   实现方法:

    @Override
    public List fuzzySearchByOneParam(String field, String param, Class cls) {
        return getMongoTemplate().find(new Query(Criteria.where(
                field).regex(".*?\\" +param+ ".*")), cls);
    }

   列举二:

    接口方法:

    /**
     * 向集合众插入json格式文档
     * @param jsonStr 要插入的json
     * @param collectionName 集合名称
     */
    public void insertJSONObject(String jsonStr, String collectionName) throws Exception; 

   实现方法:

   @Override
    public void insertJSONObject(String jsonStr, String  collectionName) throws Exception{
        DBCollection collection = getMongoTemplate().getCollection(collectionName);
        BasicDBObject document = (BasicDBObject) JSON.parse(jsonStr);
        collection.insert(document);
    }

 还有一个较为复杂的分组统计的方法,但是我个人的方法有点愚钝,希望有更好方式的大神能给予教导,提供更好的方法,在mongo管道这一块还有很多的欠缺。

  列举三

   接口方法:

    /**
     * 通过输入的检索条件分组并查询匹配数据
     * @param query 查询条件
     * @param groupKey 分组字段
     * @param operate 操作名称
     * @param selectName 显示字段
     * @param collectionName 文档名称
     * @return
     * @throws Exception
     */
    public String findJsonObjectAndGroupByQuery(BasicDBObject query, String groupKey, String                  operate, String selectName, String collectionName) throws Exception;

   

实现方法:

    public String findJsonObjectAndGroupByQuery(BasicDBObject query, String groupKey, String operate, String selectName, String collectionName)
            throws Exception {
        DBCollection collection = getMongoTemplate().getCollection(collectionName);
        DBObject keys = new BasicDBObject(groupKey, 1);
        DBObject initial = new BasicDBObject("count", 0);
        initial.put("result", 0);
        String reduce = "";
        String finalize = "";
        if("avg".equals(operate)) {  // 求平均数
            reduce = "function(doc,out){out.count++; out.result = out.result  + Number(doc." + selectName + ");}";
            finalize = "function(out){out.result = out.result / out.count;  return out;}";
        } else if("sum".equals(operate)) { // 求总和
            reduce = "function(doc,out){out.count++; out.result = out.result  + Number(doc." + selectName + ");}";
            finalize = "function(out){return out;}";
        } else if("max".equals(operate)) { // 求最大
            reduce = "function(doc,out){out.count++; if(out.result < Number(doc." + selectName + "))out.result = Number(doc." + selectName + ");}";
            finalize = "function(out){return out;}";
        } else if("min".equals(operate)) { // 求最小
            initial.put("result", Long.MAX_VALUE);
            reduce = "function(doc,out){out.count++; if(out.result > Number(doc." + selectName + "))out.result = Number(doc." + selectName + ");}";
            finalize = "function(out){if(out.result==" + Long.MAX_VALUE + ") {out.result = 0} return out;}";
        } else if("count".equals(operate)) { // 求总数
            reduce = "function(doc,out){out.count++;}";
            finalize = "function(out){out.result = out.count; return out;}";
        } else {
            throw new Exception();
        }
        
        BasicDBList dbList = (BasicDBList) collection.group(keys, query, initial, reduce, finalize);
        ListIterator<Object> listIterator = dbList.listIterator();
        Gson gson = new Gson();
        
        List<Map> resultList = new ArrayList<>();
        while(listIterator.hasNext()) {
            Map resultMap = gson.fromJson(String.valueOf(listIterator.next()), new TypeToken<Map>() {}.getType());
            resultList.add(resultMap);
        }
        return gson.toJson(resultList);
    }

   mongDB很多命令行实现方式与js极为相似,所以我在实现分组的时候其实采用的是类似于js语言的实现方式。现在已记不清为什么不使用Aggregation管道操作来实现了。。。也记不太清遇到了什么难题,让我转而用这种方式,好像当时是因为数据类型的问题,无法进行正确的统计。

   补充:最后瞎扯一下,如果使用mongoDB需要进行映射的操作,需要在pojo上声明注解@Document,这样你类中id就会与mongoDB中默认主键_id对应上,否则会被认为是一个新的字段,就这样啦啦。

猜你喜欢

转载自my.oschina.net/huaizhe/blog/1626573
今日推荐