我使用的版本是SpringBoot 2.6.4
可以像Mybaits Plus 一样的功能

<!-- mongodb -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

spring:
  data:
    mongodb:
    # open 自定义 使用aop切面控制开关
      open: true
      host: 127.0.0.1
      port: 27017
      username: test
      password: mongodb
      authentication-database: admin  #认证的库,不加会报错
      database: test_db
      auto-index-creation: true # 自动创建索引

配置类,默认不配置 添加的时候会有一个class字段,_class定义了每一条数据映射的实体类的类型,在使用SpringBoot-MongoDB的api插入数据时,即使引用类型是父类型,_class的值会插入对象的实际类型
在这里插入图片描述

转换器的作用一看就能理解 ,只是查询量比较大的时候,转换器会消耗很大的资源,慎用!

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.data.mongodb.MongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

import java.util.Date;

/**
 * @description: 使用 spring data mongo 时,默认情况下会向您的集合添加一个 _class 键,
 * 以便能够处理继承。但是如果你的领域模型简单而扁平,你可以通过覆盖默认的 MappingMongoConverter 来移除它
 */
@Configuration
public class MongoConfig {

    // 注册转换器
    @Bean
    public MongoCustomConversions customConversions() {
        return MongoCustomConversions.create(i -> {
            i.registerConverter(new DateToLongConverter());
            i.registerConverter(new LongToDateConverter());
        });
    }

    /**
     * mongo映射转换器
     *
     * @param factory           mongo工厂
     * @param context           映射命名空间
     * @param customConversions 自定义转换器
     * @return org.springframework.data.mongodb.core.convert.MappingMongoConverter
     */
    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDatabaseFactory factory, MongoMappingContext context, BeanFactory beanFactory, MongoCustomConversions customConversions) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        //添加自定义的转换器
        mappingConverter.setCustomConversions(customConversions);
        // 去掉默认mapper添加的_class
        mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));
        return mappingConverter;
    }

    /**
     * mongo时间转换器(Long转Date)
     **/
    @ReadingConverter
    private static class LongToDateConverter implements Converter<Long, Date> {
        @Override
        public Date convert(Long source) {
            // 判断是否为毫秒,兼容之前存的毫秒级时间
            if (source.toString().length() < 11) {
                return new Date(source * 1000);
            } else return new Date(source);
        }
    }

    /**
     * mongo时间转换器(Date转Long)
     **/
    @WritingConverter
    private static class DateToLongConverter implements Converter<Date, Long> {
        @Override
        public Long convert(Date source) {
            return source.getTime() / 1000;
        }
    }
}

Mongodb注解含义

注解 含义
@Id 主键,不可重复,自带索引
@Document 标注在实体类上,类似于Mp的TableName注解,标明由mongo来维护该表
@Indexed 声明该字段需要加索引,加索引后以该字段为条件检索将大大提高速度。唯一索引的话是@Indexed(unique = true)。也可以对数组进行索引,如果被索引的列是数组时,MongoDB会索引这个数组中的每一个元素。也可以对整个Document进行索引,排序是预定义的按插入BSON据的先后升序排列。
@CompoundIndex 复合索引,加复合索引后通过复合索引字段查询将大大提高速度。是类注解@Document@CompoundIndexes({@CompoundIndex(name = “age_idx”, def = “{‘lastName’: 1, ‘age’: -1}”)}),写法如上,lastName和age将作为复合索引,数字参数指定索引的方向,1为正序,-1为倒序。方向对单键索引和随机存不要紧,但如果你要执行分组和排序操作的时候,它就非常重要了。
@Field 代表一个字段,可以不加,不加的话默认以参数名为列名。给映射存储到 mongodb 的字段取别名
@Transient 被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。
@DBRef 关联另一个document对象。类似于mysql的表关联,但并不一样,mongo不会做级联的操作。
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import hss.server.handler.DateLongTypeHandler;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

import java.io.Serializable;
import java.util.Date;
@Data
@TableName(value = "hss_history", autoResultMap = true)
@Document(collection = "hss_history")
@CompoundIndexes({@CompoundIndex(name = "age_idx", def = "{‘lastName’: 1, ‘age’: -1}")})
public class HssHistoryEntity implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId
    @Id
    private String id;
    private Long equipmentId;
    private Long typeId;
    // 需要开启自动映射
    @TableField(typeHandler = JacksonTypeHandler.class)
    private JSONObject data;
    @TableField(typeHandler = JacksonTypeHandler.class)
    private JSONObject parseData;
    // 运行正常的数据,为1才返回到前端
    private Integer state;
    private Long parseTime;
    // @Field(targetType = FieldType.INT64)
    //@TableField(typeHandler = DateLongTypeHandler.class)
    private Long createTime;
}

工具类

package com.tecloman.cloud.common.mongodb;

import cn.hutool.core.util.ReflectUtil;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.index.Index;
import org.springframework.data.mongodb.core.index.IndexInfo;
import org.springframework.data.mongodb.core.index.IndexOperations;
import org.springframework.data.mongodb.core.query.*;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

@Component
@Slf4j//不注册bean 无法作为aop切入点
public class MongoDBUtil {

    private static final Query EMPTY_QUERY = new BasicQuery("{}");
    private static MongoTemplate template;

    @Autowired
    public void setTemplate(MongoTemplate template) {
        MongoDBUtil.template = template;
    }

    public MongoDBUtil createCollection(String collectionName, Index... index) {
        template.createCollection(collectionName);
        for (Index item : index) {
            template.indexOps(collectionName).ensureIndex(item);
        }
        return this;
    }

    public MongoDBUtil createIndex(String collectionName, Index... index) {
        IndexOperations indexOperations = template.indexOps(collectionName);
        List<String> indexNames = indexOperations.getIndexInfo().stream().map(IndexInfo::getName).collect(Collectors.toList());
        for (Index item : index) {
            if (!indexNames.contains(ReflectUtil.getFieldValue(item, "name"))) {
                indexOperations.ensureIndex(item);
            }
        }
        return this;
    }

    private static Query idEqQuery(Serializable id) {
        Criteria criteria = Criteria.where("id").is(id);
        return Query.query(criteria);
    }

    private Query idInQuery(Collection<? extends Serializable> idList) {
        Criteria criteria = Criteria.where("id").in(idList);
        return Query.query(criteria);
    }

    private Query eqQuery(Map<String, Object> data) {
        if (CollectionUtils.isEmpty(data)) {
            return EMPTY_QUERY;
        } else {
            Criteria criteria = new Criteria();
            data.forEach((k, v) -> criteria.and(k).is(v));
            return Query.query(criteria);
        }
    }

    private static <T> Serializable getIdValue(T entity) {
        try {
            Field field = entity.getClass().getDeclaredField("id");
            field.setAccessible(true);
            return (Serializable) field.get(entity);
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private <T> Update getUpdate(T entity) {
        Field[] fields = entity.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
        }
        return null;
    }

    public <T> void save(T entity) {
        template.save(entity);
    }

    public <T> void save(T entity, String collectionName) {
        template.save(entity, collectionName);
    }

    public <T> void inset(T entity) {
        template.insert(entity);
    }

    public <T> void insetAll(Collection<? extends T> batchToSave, String collectionName) {
        template.insert(batchToSave, collectionName);
    }

    public <T> void saveBatch(Collection<T> entityList) {
        template.insertAll(entityList);
    }

    public void removeById(Serializable id, Class<?> clazz) {
        template.remove(idEqQuery(id.toString()), clazz);
    }

    public void removeByMap(Map<String, Object> columnMap, Class<?> clazz) {
        template.remove(eqQuery(columnMap), clazz);
    }

    public void removeByIds(Collection<? extends Serializable> idList, Class<?> clazz) {
        template.remove(idInQuery(idList), clazz);
    }

    public void remove(Query query, Class<?> clazz) {
        template.remove(query, clazz);
    }

    public void remove(Query query, Class<?> clazz, String collectionName) {
        template.remove(query, clazz, collectionName);
    }

    public <T> boolean updateById(T entity) {
        Assert.notNull(entity, "entity must not be null!");
        JSONObject obj = (JSONObject) JSONObject.toJSON(entity);
        DBObject update = new BasicDBObject();
        update.put("$set", obj);
        UpdateResult result = template.updateFirst(idEqQuery(getIdValue(entity)), new BasicUpdate(update.toString()), entity.getClass());
        return result.getModifiedCount() == 1L;
    }

    public <T> boolean updateById(T entity, String collectionName) {
        Assert.notNull(entity, "entity must not be null!");
        JSONObject obj = (JSONObject) JSONObject.toJSON(entity);
        DBObject update = new BasicDBObject();
        update.put("$set", obj);
        UpdateResult result = template.updateFirst(idEqQuery(getIdValue(entity)), new BasicUpdate(update.toString()), entity.getClass(), collectionName);
        return result.getModifiedCount() == 1L;
    }

    public <T> void updateBatchById(Collection<T> entityList) {
        entityList.forEach(e -> updateById(e));
    }

    public void update(Query query, Update update, Class<?> clazz) {
        template.updateMulti(query, update, clazz);
    }

    public static <T> void saveOrUpdate(T entity) {
        Assert.notNull(entity, "entity must not be null!");
        String key = JSONObject.toJSONString(entity);
        Update inc = new Update().inc(key, 1);
        template.upsert(idEqQuery(getIdValue(entity)), inc, entity.getClass());
    }

    public <T> void saveOrUpdateBatch(Collection<T> entityList) {
        entityList.forEach(MongoDBUtil::saveOrUpdate);
    }

    public <T> T getById(Serializable id, Class<T> clazz) {
        return template.findById(id.toString(), clazz);
    }

    public <T> T getById(Serializable id, Class<T> clazz, String collectionName) {
        return template.findById(id.toString(), clazz, collectionName);
    }

    public <T> T getOne(Query query, Class<T> clazz) {
        return template.findOne(query, clazz);
    }

    public <T> T getOne(Query query, Class<T> clazz, String collectionName) {
        return template.findOne(query, clazz, collectionName);
    }

    public <T> List<T> listByIds(Collection<? extends Serializable> idList, Class<T> clazz) {
        return template.find(idInQuery(idList), clazz);
    }

    public <T> List<T> listByMap(Map<String, Object> columnMap, Class<T> clazz) {
        return template.find(eqQuery(columnMap), clazz);
    }

    public <T> List<T> list(Class<T> clazz) {
        return template.findAll(clazz);
    }

    public <T> List<T> list(Query query, Class<T> clazz) {
        return template.find(query, clazz);
    }

    public <T> List<T> list(Query query, Class<T> clazz, String collectionName) {
        return template.find(query, clazz, collectionName);
    }

    public <T> long count(Class<T> clazz) {
        return template.count(EMPTY_QUERY, clazz);
    }

    public <T> long count(Query query, Class<T> clazz) {
        return template.count(query, clazz);
    }

    public <T> long count(Query query, Class<T> clazz, String collectionName) {
        return template.count(query, clazz, collectionName);
    }

    // 去重查询 需要传入历史数据实体
    public <T> List<T> findDistinct(Query query, String field, Class<?> entityClass,
                                    Class<T> resultClass) {
        return template.findDistinct(query, field, entityClass, resultClass);
    }

    public <T> List<T> findDistinct(Query query, String field, String collectionName, Class<?> entityClass,
                                    Class<T> resultClass) {
        return template.findDistinct(query, field, collectionName, entityClass, resultClass);
    }

    /**
     * @param params 分页参数
     * @param query  查询条件
     * @param clazz  实体字节码
     * @description 分页查询
     * @date 2022-06-14
     * 不使用skip跳过查询 chenshuang
     */
    public <T> PageUtils page(Map<String, Object> params, Query query, Class<T> clazz) {
        // 设置索引
        //setIndex();
        IPage<T> page = new common.server.utils.Query<T>().getPage(params);
        page.setTotal(count(query, clazz));
        //Sort.Order sidx = new Sort.Order(params.get("order"), params.get("sidx").toString());
        //PageRequest.of((int) (page.getCurrent() + 1), (int) page.getSize(),new Sort(new Sort.Order()))
        // 分页索引从0开始,当前页需要减1,这里打断点可以看出 skip跳出多少条数据,数据量大有点影响性能
        if ((int) page.getCurrent() != 1) {
            // 获取前面的数据,取最后一条数据的createTime作为查询条件
            int number = ((int) page.getCurrent() - 1) * (int) page.getSize();
            query.limit(number);//!!!!!!
            // 数据量大  截取就会很大 上面这两行代码需要改改
            List<T> list = template.find(query, clazz);
            T t = list.get(list.size() - 1);
            Date time = null;
            try {
                Method method = t.getClass().getDeclaredMethod("getCreateTime");
                time = (Date) method.invoke(t);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                log.error("Mongodb查询异常");
            }
            query.addCriteria(Criteria.where("createTime").gt(time.getTime() / 1000));
        }
        query.limit((int) page.getSize());
        //Pageable pageable = PageRequest.of((int) page.getCurrent() - 1, (int) page.getSize());
        //query.with(pageable);
        List<T> records = template.find(query, clazz);
        page.setPages(page.getPages());
        page.setRecords(records);
        return new PageUtils(page);
    }

    /**
     * @param params 分页参数
     * @param query  查询条件
     * @param clazz  实体字节码
     * @description 分页查询
     * @date 2022-06-14
     * 使用skip跳过查询,连续跳页需要测试和上面page方法比较 chenshuang
     */
    public <T> PageUtils page2(Map<String, Object> params, Query query, Class<T> clazz) {
        // 设置索引
        //setIndex();
        IPage<T> page = new common.server.utils.Query<T>().getPage(params);
        page.setTotal(count(query, clazz));
        //Sort.Order sidx = new Sort.Order(params.get("order"), params.get("sidx").toString());
        //PageRequest.of((int) (page.getCurrent() + 1), (int) page.getSize(),new Sort(new Sort.Order()))
        // 分页索引从0开始,当前页需要减1,这里打断点可以看出 skip跳出多少条数据,数据量大有点影响性能
        Pageable pageable = PageRequest.of((int) page.getCurrent() - 1, (int) page.getSize());
        query.with(pageable);
        List<T> records = template.find(query, clazz);
        page.setPages(page.getPages());
        page.setRecords(records);
        return new PageUtils(page);
    }

    /**
     * @param params 查询条件参数 (设备ID必传)
     * @description 获取查询条件 历史数据查询专用
     * @date 2022-06-15
     * 长时间和短时间区分 chenshuang
     */
    public Query getQuery(Map<String, Object> params) {
        Query query = new Query();
        query.addCriteria(Criteria.where("equipmentId").is(Long.parseLong(params.get("equipmentId").toString())));
        if (params.containsKey("typeId")) {
            // 添加版本ID
            query.addCriteria(Criteria.where("typeId").is(params.get("typeId")));
        }
        // 添加时间条件
        Criteria criteria = new Criteria();
        ArrayList<Criteria> criteriaList = new ArrayList<>();
        String regex = "^\\d{4}-\\d{1,2}-\\d{1,2}";
        if (params.containsKey("startTime") && !params.get("startTime").equals("")) {
            String startTime = params.get("startTime").toString();
            Long time;
            // 校验长时间还是短时间
            if (startTime.matches(regex)) {
                time = DateUtils.stringToLongByTimezone(startTime + " 00:00:00", params.get("timezone").toString(), DateUtils.DATE_TIME_PATTERN);
            } else {
                time = DateUtils.stringToLongByTimezone(startTime, params.get("timezone").toString(), DateUtils.DATE_TIME_PATTERN);

            }
            criteriaList.add(Criteria.where("createTime").gte(time));
        }
        if (params.containsKey("endTime") && !params.get("endTime").equals("")) {
            String endTime = params.get("endTime").toString();
            Long time;
            // 校验长时间还是短时间
            if (endTime.matches(regex)) {
                time = DateUtils.stringToLongByTimezone(endTime + " 23:59:59", params.get("timezone").toString(), DateUtils.DATE_TIME_PATTERN);
            } else {
                time = DateUtils.stringToLongByTimezone(endTime, params.get("timezone").toString(), DateUtils.DATE_TIME_PATTERN);
            }
            criteriaList.add(Criteria.where("createTime").lte(time));
        }
        if (criteriaList.size() > 0) {
            criteria.andOperator(criteriaList);
            query.addCriteria(criteria);
        }
        // 创建时间升序
        query.with(Sort.by(Sort.Order.asc("createTime")));
        return query;
    }

    // 电量接口统计使用
    public HssHistoryEntity getHistory(HssEquipmentEntity hssEquipmentEntity, Long begin, Long end) {
        Query query = new Query(Criteria.where("equipmentId").is(hssEquipmentEntity.getId()).and("typeId").is(hssEquipmentEntity.getTypeId()));
        Criteria criteria = new Criteria();
        criteria.andOperator(Criteria.where("createTime").gte(begin / 1000), Criteria.where("createTime").lte(end / 1000));
        query.addCriteria(criteria);
        query.limit(1);
        HssHistoryEntity entity = template.findOne(query, HssHistoryEntity.class);
        return entity;
    }
}

分页工具类

import com.baomidou.mybatisplus.core.metadata.IPage;

import java.io.Serializable;
import java.util.List;

/**
 * 分页工具类
 */
public class PageUtils implements Serializable {
	private static final long serialVersionUID = 1L;
	/**
	 * 总记录数
	 */
	private int totalCount;
	/**
	 * 每页记录数
	 */
	private int pageSize;
	/**
	 * 总页数
	 */
	private int totalPage;
	/**
	 * 当前页数
	 */
	private int currPage;
	/**
	 * 列表数据
	 */
	private List<?> list;
	
	/**
	 * 分页
	 * @param list        列表数据
	 * @param totalCount  总记录数
	 * @param pageSize    每页记录数
	 * @param currPage    当前页数
	 */
	public PageUtils(List<?> list, int totalCount, int pageSize, int currPage) {
		this.list = list;
		this.totalCount = totalCount;
		this.pageSize = pageSize;
		this.currPage = currPage;
		this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
	}

	/**
	 * 分页
	 */
	public PageUtils(IPage<?> page) {
		this.list = page.getRecords();
		this.totalCount = (int)page.getTotal();
		this.pageSize = (int)page.getSize();
		this.currPage = (int)page.getCurrent();
		this.totalPage = (int)page.getPages();
	}

	public int getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(int totalCount) {
		this.totalCount = totalCount;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getTotalPage() {
		return totalPage;
	}

	public void setTotalPage(int totalPage) {
		this.totalPage = totalPage;
	}

	public int getCurrPage() {
		return currPage;
	}

	public void setCurrPage(int currPage) {
		this.currPage = currPage;
	}

	public List<?> getList() {
		return list;
	}

	public void setList(List<?> list) {
		this.list = list;
	}
	
}

// mongodb 查询对象
Query query = new Query();
// 查询条件构造器
Criteria criteria1 = new Criteria();
// 就像MP的wrapper
QueryWrapper<Object> wrapper = new QueryWrapper<>();

Criteria 方法含义

方法名 释义 栗子
where() where Criteria.where(“name”).is(“帅哥”)
andOperator() and Criteria.where(“name”).is(“帅哥”).andOperator(Criteria.where(“age”).is(18)); Criteria.andOperator(Criteria.where(“name”).is(“帅哥”), Criteria.where(“age”).is(25));
orOperator() or Criteria.where(“name”).is(“美女”).orOperator(Criteria.where(“age”).is(18)); Criteria.orOperator(Criteria.where(“name”).is(“美女”), Criteria.where(“age”).is(25));
is() == Criteria.where(“name”).is(“帅哥”)
not() != Criteria.where(“name”).not(“丑男”)
regex() like Criteria.where(“name”).regex(“.**?” +“帅哥”+ “.*”)
in() in Criteria.where(“age”).in(List))
gt() > Criteria.where(“age”).gt(18)
gte() >= Criteria.where(“age”).gte(18)
lt() < Criteria.where(“age”).lt(18)
lte() <= Criteria.where(“age”).lte(18)

mongoDb自动创建索引,实体必须有@Document,指定文档
@Document(collection = “hss_history”)
@CompoundIndexes({@CompoundIndex(name = “k1”,def = “{‘name’,1},‘age’,-1”)})
yml配置类加上 auto-index-creation: true,默认是关闭的
动态文档无法自动添加索引,只能手动添加

        mongoDBUtil.createIndex(sn, new Index("createTime", Sort.Direction.ASC).named("n1"), new Index("typeId", Sort.Direction.ASC).on("createTime", Sort.Direction.ASC).named("n2"));

    public MongoDBUtil createIndex(String collectionName, Index... index) {
        IndexOperations indexOperations = template.indexOps(collectionName);
        List<String> indexNames = indexOperations.getIndexInfo().stream().map(IndexInfo::getName).collect(Collectors.toList());
        for (Index item : index) {
            if (!indexNames.contains(ReflectUtil.getFieldValue(item, "name"))) {
                indexOperations.ensureIndex(item);
            }
        }
        return this;
    }
Logo

一站式虚拟内容创作平台,激发创意,赋能创作,进入R空间,遇见同道,让优质作品闪耀发光。​

更多推荐