SpringMVC与Springboot整合mongodb

整天从这里参考朋友们的文章, 今天也整理了一个 SpringMVC与Springboot整合mongodb 的范例给大家参考,省点开发时间

目录

1SpringMVC 整合 mongodb

maven

config

低配版

高配版

service

其他配置类

MongoSupport

FieldName

MapUnderscoreToCamelCase

DemoObj

2. Springboot 整合 mongodb


1SpringMVC 整合 mongodb

在这里值得一说的是

我使用了  MongoSupportNew 这个转换类对 mongo 查询到的文档中的数据进行安全提取到 java对象中

相对于使用 alibaba的 faseJson JSON.parseObject(json, Class) 来说效率快了不少,

具体使用事项可通过下面代码去了解

注意: 如果是 springboot版本,则不需要这么复杂了

maven

  <!-- mongodb -->
  <dependency>
      <groupId>org.mongodb</groupId>
      <artifactId>mongodb-driver</artifactId>
      <version>3.9.0</version>
  </dependency>

config

低配版
package com.example.mongodb.driver.config;

import com.mongodb.MongoClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


@Configuration
public class MongodbConfig {

    @Value("${spring.data.mongodb.host:127.0.0.1}")
    private String host;
    @Value("${spring.data.mongodb.port:27017}")
    private Integer port;

    @Bean
    public MongoClient mongoClient() {
        return new MongoClient(host, port);
    }

}

高配版
package com.thinkgem.jeesite.common.utils;

import com.mongodb.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Configuration
public class MongoManagerCc {

    @Value("${mongodb.cc.authDbName:admin}")
    private String authDbName;
    @Value("${mongodb.cc.userName:mongo}")
    private String userName;
    @Value("${mongodb.cc.password:2607ce8120273ea6}")
    private String password;
    @Value("${mongodb.cc.host:10.208.255.255}")
    private String host;
    @Value("${mongodb.cc.port:37432}")
    private Integer port;
    @Value("${mongodb.cc.mPoolSize:100}")
    private Integer poolSize;
    @Value("${mongodb.cc.mBlockSize:100}")
    private Integer blockSize;

    @Bean("mongoManagerCcClient")
    public MongoClient initMongoClient() {
        MongoClient mongoCc = null;
        ServerAddress serverAddress = new ServerAddress(host, port);
        List<ServerAddress> seeds = new ArrayList<>();
        seeds.add(serverAddress);
        MongoCredential credentials = MongoCredential.createCredential(userName, authDbName, password.toCharArray());
        List<MongoCredential> credentialsList = new ArrayList<>();
        credentialsList.add(credentials);
        mongoCc = new MongoClient(seeds, credentialsList);

        MongoClientOptions.Builder options = new MongoClientOptions.Builder();
        options.connectionsPerHost(poolSize);
        options.threadsAllowedToBlockForConnectionMultiplier(blockSize);
        options.build();
        return mongoCc;
    }

}

service

查询
package com.example.mongodb.driver.service;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.example.mongodb.driver.config.MongoSupportNew;
import com.example.mongodb.driver.entity.DemoObj;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.model.Filters;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.conversions.Bson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;


@Slf4j
@Service
public class DemoService2 extends MongoSupportNew<DemoObj> {

    @Autowired
    private MongoClient mongoClient;

    public List<DemoObj> queryTest1() {

        MongoDatabase database = mongoClient.getDatabase("demo");
        MongoCollection<Document> collection = database.getCollection("test1");
        // 如果mongo存的是时间类型, 则查询也需要穿时间类型的参数,  如果存的字符串, 那么可以直接通过字符串查询
        Bson bson = Filters.and(
                Filters.eq("STATUS", "dealing"),
                Filters.gte("INSERT_DATE", DateUtil.parse("2023-01-30 00:57:27", DatePattern.NORM_DATETIME_PATTERN)),
                Filters.lte("INSERT_DATE", DateUtil.parse("2023-07-30 23:57:27", DatePattern.NORM_DATETIME_PATTERN)));

        BasicDBObject sortCondition = new BasicDBObject();
        // 1 正序 ASC  -1:倒序 DESC
        sortCondition.put("INSERT_DATE", -1);
        MongoCursor<Document> iterator = collection.find(bson).skip(0).limit(10).sort(sortCondition).iterator();
        return getEntityList(iterator);
    }
}


删除
public void delete() {
        MongoDatabase database = mongoClient.getDatabase("demo");
        MongoCollection<Document> collection = database.getCollection("test1");
        DeleteResult deleteResult = collection.deleteOne(Filters.eq("STATUS", "normal2"));
        System.out.println("deleteResult.getDeletedCount() = " + deleteResult.getDeletedCount());
    }

修改
    public void update() {
        MongoDatabase database = mongoClient.getDatabase("demo");
        MongoCollection<Document> collection = database.getCollection("test1");
        Document doc = new Document();
        doc.put("$set", new Document("STATUS", "normal2"));
        UpdateResult updateOne = collection.updateOne(Filters.eq("STATUS", "normal"), doc);
        long modifiedCount = updateOne.getModifiedCount();
        System.out.println("modifiedCount = " + modifiedCount);
    }


增加
  /**
   * 新增
   */
  public void insert() {
      MongoDatabase database = mongoClient.getDatabase("demo");
      MongoCollection<Document> collection = database.getCollection("test1");
      DemoObj demoObj = new DemoObj()
              .setStatus("normal").setEndTime("2023-01-30 00:57:27")
              .setCalledNo("138777999").setDoubleNum(99.99)
              .setInsertDate(new Date()).setNumArr(Arrays.asList(1, 2, 3, 4))
              .setStrArr(Arrays.asList("a", "c"));

      Document doc = new Document();
      doc.put("STATUS", demoObj.getStatus());
      doc.put("END_TIME", demoObj.getEndTime());
      doc.put("CALLED_NO", demoObj.getCalledNo());
      doc.put("ERROR_MEMO", demoObj.getErrorMemo());
      doc.put("DOUBLE_NUM", demoObj.getDoubleNum());
      doc.put("INSERT_DATE", demoObj.getInsertDate());
      doc.put("NUM_ARR", demoObj.getNumArr());
      doc.put("STR_ARR", demoObj.getStrArr());
      collection.insertOne(doc);

  }

其他配置类

MongoSupportNew
package com.example.mongodb.driver.config;

import cn.hutool.core.util.ArrayUtil;
import com.mongodb.client.MongoCursor;
import lombok.extern.slf4j.Slf4j;
import org.bson.Document;
import org.bson.types.ObjectId;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.*;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @description 对 mongodb 查询后的实体进行转换
 * 如果返回的结果集较少, 可用   alibaba.fastJson 的 JSON.parseObject(json, Class);  (效率相对此方法较差) 可能更安全? 哈哈
 * T 泛型的实体类  可以配合@FieldName 指定mongo 中的属性名 (默认情况以实体的属性名的大写 + _ 形式作为 Mongo 中的属性名)
 * 支持的属性转换类型 基本类型 字符串 时间 带泛型的集合
 * <p>
 * 主要工作关注以下几个方法
 * getEntity(T t) 通过mongo文档 获取 对象
 * getEntityList(MongoCursor<Document> cursor) 通过mongo文档集合 获取 对象集合
 * getDocument(T t) 通过 对象 获取 mongo文档
 * getDocumentList(List<T> list) 通过 对象集合 获取 mongo文档集合
 */
@Slf4j
public class MongoSupportNew<T> {

    /**
     * mongodb 中的属性名集合, 其顺序与fields 数组中 一一对应
     */
    private List<String> filedNameList;

    /**
     * 具体实体类的成员属性数组   set方法名
     */
    private List<String> methodNameList;

    /**
     * 具体 set 方法形参的类型
     */
    private List<Class<?>> fieldTypeList;

    /**
     * 用在效验List<> 中泛型是否正确
     */
    private List<Type> typeList;

    /**
     * 类的记录泛型类型
     */
    private Class<T> genericClass;

    private static final char SEPARATOR = '_';

    public MongoSupportNew() {
        Class<T> clazz = getGenericClass();
        Optional.ofNullable(clazz).orElseThrow(() -> new RuntimeException("当前MongoSupportNew类的使用有误, 子类继承时 需要声明父类中的泛型类型!"));
        init(clazz);
    }

    private void init(Class<T> clazz) {
        this.genericClass = clazz;
        Field[] declaredFields = clazz.getDeclaredFields();
        filedNameList = new ArrayList<>(declaredFields.length);
        methodNameList = new ArrayList<>(declaredFields.length);
        fieldTypeList = new ArrayList<>(declaredFields.length);
        typeList = new ArrayList<>(declaredFields.length);
        MapUnderscoreToCamelCase mapType = AnnotationUtils.getAnnotation(clazz, MapUnderscoreToCamelCase.class);
        boolean underScoreToCameCase = true;
        boolean upperCase = true;
        if (mapType != null) {
            underScoreToCameCase = mapType.value();
            upperCase = mapType.upperCase();
        }
        for (Field field : declaredFields) {
            String capitalize = StringUtils.capitalize(field.getName());
            FieldName annotation = field.getAnnotation(FieldName.class);

            if (annotation != null && !annotation.ignore()) {
                filedNameList.add(annotation.value());
                methodNameList.add("set" + capitalize);
                fieldTypeList.add(field.getType());
                typeList.add(field.getGenericType());
            } else if (annotation == null) {
                String fieldName = field.getName();
                if (underScoreToCameCase) {
                    fieldName = toUnderScoreCase(fieldName);
                }
                if (upperCase) {
                    fieldName = fieldName.toUpperCase();
                }
                filedNameList.add(fieldName);
                methodNameList.add("set" + capitalize);
                fieldTypeList.add(field.getType());
                typeList.add(field.getGenericType());
            }
        }
    }


    /**
     * 对返回结果的情况进行结果集映射,取得封装后的实体对象
     * 如果返回的结果集较少, 也可用   alibaba.fastJson 的 JSON.parseObject(json, Class);  (效率相对此方法较差), 但故障率相对较低
     *
     * @param document 原始的Document类型实体
     * @return list
     */
    public T getEntity(Document document) {
        T t = getGenericInstance();
        fillFields(document, t);
        return t;
    }

    /**
     * 对返回多个结果的情况进行结果集映射,取得封装后的实体list
     * 如果返回的结果集较少, 也可用   alibaba.fastJson 的 JSON.parseObject(json, Class);  (效率相对此方法较差), 但故障率相对较低
     *
     * @param cursor 原始的Document类型实体
     * @return list
     */
    public List<T> getEntityList(MongoCursor<Document> cursor) {
        if (cursor == null) {
            return new ArrayList<>();
        }
        List<T> resList = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        while (cursor.hasNext()) {
            Document document = cursor.next();
            T t = getGenericInstance();
            fillFields(document, t);
            resList.add(t);
        }
        log.info("PRO MongoSupportNew.getEntityList 封装耗时:{}ms", Duration.between(now, LocalDateTime.now()).toMillis());
        return resList;
    }

    /**
     * 把 obj的数据转成 document
     * 需关系下面两个注解
     *
     * @param t t
     * @return document
     * @see MapUnderscoreToCamelCase 驼峰命名的字段 转成 mongo的字段名
     * @see FieldName 字段别名, 是否忽略转换
     */
    public Document getDocument(T t) {
        return processDocumentData(t);
    }

    /**
     * 把 obj的数据转成 document
     * 需关系下面两个注解
     *
     * @param list list
     * @return documentList
     * @see MapUnderscoreToCamelCase 驼峰命名的字段 转成 mongo的字段名
     * @see FieldName 字段别名, 是否忽略转换
     */
    public List<Document> getDocumentList(List<T> list) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        List<Document> voList = new ArrayList<>();

        for (T t : list) {
            Document document = processDocumentData(t);
            voList.add(document);
        }
        return voList;
    }

    private Document processDocumentData(T t) {
        Class<?> clazz = t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        Document document = new Document();
        for (Field field : fields) {

            field.setAccessible(true);
            String fieldName = field.getName();
            Object invokeValue = null;
            try {
                Method method = t.getClass().getDeclaredMethod("get" + StringUtils.capitalize(fieldName));
                method.setAccessible(true);
                invokeValue = method.invoke(t);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                log.error("PRO MongoSupportNew.toDocumentList error fieldName:{}原因:", fieldName, e);
            }
            if (invokeValue == null) {
                continue;
            }

            boolean upperCase = true;
            boolean value = true;
            MapUnderscoreToCamelCase toCamelCase = clazz.getAnnotation(MapUnderscoreToCamelCase.class);
            if (toCamelCase != null) {
                // 是否开启驼峰转下划线映射,默认开启
                upperCase = toCamelCase.upperCase();
                // 是否开启驼峰转下划线映射
                value = toCamelCase.value();
            }

            FieldName annotation = field.getAnnotation(FieldName.class);
            if (annotation != null && !annotation.ignore()) {
                document.put(annotation.value(), invokeValue);
            } else if (annotation == null) {
                if (upperCase) {
                    fieldName = toUnderScoreCase(fieldName);
                }
                if (value) {
                    fieldName = fieldName.toUpperCase();
                }
                document.put(fieldName, invokeValue);
            }
        }
        return document;
    }


    /**
     * 填充实例类
     *
     * @param document mongoDB 查询到的原始 document 类型属性, 原始的封装实体类
     * @param instance T 的实例
     */
    private void fillFields(Document document, T instance) {
        if (document == null) {
            return;
        }
        int index = 0;
        for (String methodName : methodNameList) {
            String mongoFieldName = filedNameList.get(index);
            Object mongoFieldValue = document.get(mongoFieldName);
            Class<?> fieldTypeClazz = fieldTypeList.get(index);
            Type type = typeList.get(index);
            if (mongoFieldValue == null) {
                index++;
                continue;
            } else if (mongoFieldValue instanceof String) {
                invokeSet(instance, methodName, mongoFieldValue, fieldTypeClazz);
            } else if (mongoFieldValue instanceof ObjectId) {
                mongoFieldValue = ((ObjectId) mongoFieldValue).toHexString();
                invokeSet(instance, methodName, mongoFieldValue, fieldTypeClazz);
            } else if (mongoFieldValue instanceof List) {
                invokeListSet(index, methodName, mongoFieldValue, fieldTypeClazz, (ParameterizedType) type, instance);
            } else {
                invokeSet(instance, methodName, mongoFieldValue, fieldTypeClazz);
            }
            index++;
        }
    }

    private void invokeSet(T instance, String methodName, Object mongoFieldValue, Class<?> aClass) {
        Method method = null;
        try {
            method = instance.getClass().getDeclaredMethod(methodName, aClass);
        } catch (NoSuchMethodException e) {
            log.error("PRO MongoSupportNew.invokeSet getDeclaredMethod error methodName:{},mongoFieldValue:{} 原因:", methodName, mongoFieldValue, e);
        }


        Optional.ofNullable(method).ifPresent(m -> {
            try {
                m.invoke(instance, mongoFieldValue);
            } catch (Exception e) {
                log.error("PRO MongoSupportNew.invokeSet invoke error methodName:{},mongoFieldValue:{} 原因:", methodName, mongoFieldValue, e);
            }
        });
    }


    /**
     * 对数组进行转化
     * 如果数组中参数的类型 与对象泛型中的类型不一致, 则 return
     *
     * @param index             index
     * @param methodName        methodName
     * @param list              仅支持 参数类型是 List 的子类
     * @param clazz             参数的clazz
     * @param parameterizedType 参数的parameterizedType
     * @param instance          对象实例
     */
    private void invokeListSet(int index, String methodName, Object list, Class<?> clazz, ParameterizedType parameterizedType, T instance) {
        try {
            if (List.class.isAssignableFrom(clazz)) {
                for (Object obj : (List) list) {
                    if (!parameterizedType.getActualTypeArguments()[0].equals(obj.getClass())) {
                        return;
                    }
                }
            }
        } catch (Exception e) {
            log.error("PRO MongoSupportNew.tryTransArray error 原因:", e);
        }
        invokeSet(instance, methodName, list, fieldTypeList.get(index));
    }


    /**
     * 用于获取类中的泛型类型实例, 类中的泛型类型需要具有无参构造器
     *
     * @return T 的实例
     * @throws RuntimeException 方法执行时 genericClass 属性为空时, 尝试从类中获取, 对于继承 MongoSupportNew 而不声明其泛型的, 将会扔出异常
     * @throws Exception        其他异常可能是 获取实例时 没有无参构造 或者未声明为 public
     */
    private T getGenericInstance() {
        T instance = null;
        if (this.genericClass == null) {
            this.genericClass = getGenericClass();
        }
        Optional.ofNullable(this.genericClass).orElseThrow(() -> new RuntimeException("当前MongoSupportNew类的使用有误, 子类继承时 需要声明父类中的泛型类型!"));
        try {
            instance = genericClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            log.error("PRO MongoSupportNew.getGenericInstance error 原因:", e);
        }
        return instance;
    }


    /**
     * 驼峰命名法工具
     *
     * @return toCamelCase(" hello_world ") == "helloWorld"
     * toCapitalizeCamelCase("hello_world") == "HelloWorld"
     * toUnderScoreCase("helloWorld") = "hello_world"
     */
    public static String toUnderScoreCase(String s) {
        if (s == null) {
            return null;
        }

        StringBuilder sb = new StringBuilder();
        boolean upperCase = false;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            boolean nextUpperCase = true;

            if (i < (s.length() - 1)) {
                nextUpperCase = Character.isUpperCase(s.charAt(i + 1));
            }

            if ((i > 0) && Character.isUpperCase(c)) {
                if (!upperCase || !nextUpperCase) {
                    sb.append(SEPARATOR);
                }
                upperCase = true;
            } else {
                upperCase = false;
            }

            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    private Class<T> getGenericClass() {
        if (this.genericClass == null) {
            ParameterizedType parameterizedType = (ParameterizedType) this.getClass().getGenericSuperclass();
            Type[] types = parameterizedType.getActualTypeArguments();
            if (ArrayUtil.isNotEmpty(types)) {
                Type type = types[0];
                try {
                    return (Class<T>) Class.forName(type.getTypeName());
                } catch (ClassNotFoundException e) {
                    log.info("PRO MongoSupportNew.getGenericClass error 原因:", e);
                }
            }
        }
        return this.genericClass;
    }
}
FieldName
package com.example.mongodb.driver.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @description 用于指定实体类中 成员属性所对应的 数据源的属性名
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {

    /**
     * 指定所对应数据源的属性名
     * @return
     */
    String value() default "";

    /**
     * 是否忽略标注属性的填充,默认false,选true表示标注属性将不参与查询实体的转化,即不对标注属性赋值
     * (所以自然就不会尝试获取标注属性)
     * @return
     */
    boolean ignore() default false;
}


MapUnderscoreToCamelCase
package com.example.mongodb.driver.config;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @description 对orm映射时的下划线转驼峰进行设置,对@FieldName映射,无需该注解,默认开启驼峰转下划线 和 转大写
 * 如需关闭比映射转换可通过该注解进行操作
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MapUnderscoreToCamelCase {

    /**
     * 是否开启驼峰转下划线映射,默认开启
     * @return
     */
    boolean value() default true;

    /**
     * 是否转大写映射,默认开启
     * @return
     */
    boolean upperCase() default true;
}

DemoObj
package com.example.mongodb.driver.entity;

import com.example.mongodb.driver.config.FieldName;
import lombok.Data;
import lombok.experimental.Accessors;

import java.util.Date;
import java.util.List;


@Data
@Accessors(chain = true)
public class DemoObj {
    @FieldName(value = "_id")
    private String id;


    private String status;

    private String endTime;

    private String calledNo;

    private String errorMemo;

    private Double doubleNum;

    private Date insertDate;

    private List<Integer> numArr;

    private List<String> strArr;

}

2. Springboot 整合 mongodb

这里已经有成熟的文章案例了, 请大家去参考这里

https://so.csdn.net/so/search?q=mongo&t=blog&u=leilei1366615

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值