前言

Spring Boot是一个用于构建独立的、生产级别的Java应用程序的框架,而MongoDB是一个流行的NoSQL数据库,具有灵活的数据模型和可扩展性。通过将它们结合起来,您可以轻松地开发出高效、可靠的应用程序,并且能够处理大量的数据。

MongoDB特点

Springboot MongoDb uri 配置时区 springboot整合mongodb_mongodb

非结构化数据存储

MongoDB使用文档模型来存储数据,文档是一种类似于JSON的数据结构,可以存储各种类型的数据,而不需要事先定义数据模式。

高度可扩展性

MongoDB支持水平扩展,可以通过添加更多的服务器来处理大量的数据和高并发请求。它还支持自动分片,可以将数据分布在多个服务器上,以提高性能和可用性。

强大的查询功能

MongoDB提供了丰富的查询功能,包括支持复杂的查询条件、索引和聚合操作。它还支持全文搜索和地理空间查询,可以满足各种查询需求。

高性能

MongoDB使用内存映射文件的方式来存储数据,可以利用操作系统的缓存机制来提高读取性能。此外,它还支持异步写入和复制,可以提高写入性能和数据的可靠性。

灵活的数据模型

MongoDB的文档模型非常灵活,可以存储不同结构的文档,而不需要事先定义数据模式。这使得数据模型的变更变得更加容易和灵活。

支持多种数据类型

MongoDB支持各种数据类型,包括字符串、整数、浮点数、日期、数组、嵌套文档等。它还支持二进制数据和大型文件的存储。

可靠性和可用性

MongoDB支持数据的自动复制和故障恢复,可以提供高可用性和数据的持久性。它还支持数据的备份和恢复,以及数据的安全性和权限控制。

版本依赖

模块

版本

JDK

17

SpringBoot

3.1.0

Mongo

6.0.8

mybatis-plus

2.0.2


环境准备

MongoDB安装

安装教程请查看:一文搞定(linux+windows+docker)安装MongoDB

导入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.1.0</version>
</parent>

<groupId>com.example</groupId>
<artifactId>springboot-mongo-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-mongo-demo</name>
<description>springboot-mongo-demo</description>
<properties>
    <java.version>17</java.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

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

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>2.0.32</version>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus</artifactId>
        <version>2.0.2</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.15.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
    </dependency>
</dependencies>
application.yml配置
server:
  port: 8080  # 设置访问端口

spring:
  data:
    mongodb:
      uri: mongodb://47.98.123.147:27017/mongo_db
      # 上方为明确指定某个数据的用户进行连接
      # 也可以使用admin 数据库中的用户进行连接  统一到admin 数据库进行认证
      # admin 用户认证 url 写法: mongodb://账户:密码%40@ip:端口/数据库名?authSource=admin&authMechanism=SCRAM-SHA-1

使用实例

mongo 封装顶级service
public abstract class MongoServiceImpl<T> implements MongoService<T> {


    protected abstract Class<T> getEntityClass();

    @Autowired
    protected MongoTemplate mgt;
    @Override
    public void save(T entity) {
        mgt.save(entity);
    }

    @Override
    public void update(T entity) {

        // 反向解析对象
        Map<String, Object> map = null;
        try {
            map = parseEntity(entity);
        } catch (Exception e) {
            e.printStackTrace();
        }

        // ID字段
        String idName = null;
        Object idValue = null;

        // 生成参数
        Update update = new Update();
        if (EmptyUtil.isNotEmpty(map)) {
            for (String key : map.keySet()) {
                if (key.indexOf("{") != -1) {
                    // 设置ID
                    idName = key.substring(key.indexOf("{") + 1, key.indexOf("}"));
                    idValue = map.get(key);
                } else {
                    update.set(key, map.get(key));
                }
            }
        }
        mgt.updateFirst(new Query().addCriteria(where(idName).is(idValue)), update, getEntityClass());
    }

    @Override
    public void delete(Serializable... ids) {
        if (EmptyUtil.isNotEmpty(ids)) {
            for (Serializable id : ids) {
                mgt.remove(mgt.findById(id, getEntityClass()));
            }
        }

    }

    @Override
    public T find(Serializable id) {
        return mgt.findById(id, getEntityClass());
    }

    @Override
    public List<T> findAll() {
        return mgt.findAll(getEntityClass());
    }

    @Override
    public List<T> findAll(String order) {
        List<Order> orderList = parseOrder(order);
        if (EmptyUtil.isEmpty(orderList)) {
            return findAll();
        }
        return mgt.find(new Query().with(Sort.by((orderList))), getEntityClass());
    }

    @Override
    public List<T> findByProp(String propName, Object propValue) {
        return findByProp(propName, propValue, null);
    }

    @Override
    public List<T> findByProp(String propName, Object propValue, String order) {
        Query query = new Query();
        // 参数
        query.addCriteria(where(propName).is(propValue));
        // 排序
        List<Order> orderList = parseOrder(order);
        if (EmptyUtil.isNotEmpty(orderList)) {
            query.with(Sort.by(orderList));
        }
        return mgt.find(query, getEntityClass());
    }

    @Override
    public List<T> findByProps(String[] propName, Object[] propValue) {
        return findByProps(propName, propValue, null);
    }

    @Override
    public List<T> findByProps(String[] propName, Object[] propValue, String order) {
        Query query = createQuery(propName, propValue, order);
        return mgt.find(query, getEntityClass());
    }

    @Override
    public T uniqueByProp(String propName, Object propValue) {
        return mgt.findOne(new Query(where(propName).is(propValue)), getEntityClass());
    }

    @Override
    public T uniqueByProps(String[] propName, Object[] propValue) {
        Query query = createQuery(propName, propValue, null);
        return mgt.findOne(query, getEntityClass());
    }

    @Override
    public Page<T> pageAll(int pageNo, int pageSize) {
        return pageAll(pageNo, pageSize, null);
    }

    @Override
    public Page<T> pageAll(int pageNo, int pageSize, String order) {
        return pageByProp(pageNo, pageSize, null, null, order);
    }

    @Override
    public Page<T> pageByProp(int pageNo, int pageSize, String param, Object value) {
        return pageByProp(pageNo, pageSize, param, value, "sendTime");
    }

    @Override
    public Page<T> pageByProp(int pageNo, int pageSize, String param, Object value, String order) {
        String[] params = null;
        Object[] values = null;
        if (EmptyUtil.isNotEmpty(param)) {
            params = new String[] { param };
            values = new Object[] { value };
        }
        return pageByProps(pageNo, pageSize, params, values, order);
    }

    @Override
    public Page<T> pageByProps(int pageNo, int pageSize, String[] params, Object[] values) {
        return pageByProps(pageNo, pageSize, params, values, null);
    }

    @Override
    public Page<T> pageByProps(int pageNo, int pageSize, String[] params, Object[] values, String order) {
        // 创建分页模型对象
        Page<T> page = new Page<>(pageNo, pageSize);

        // 查询总记录数
        int count = countByCondition(params, values);
        page.setTotal(count);

        // 查询数据列表
        Query query = createQuery(params, values, order);

        // 设置分页信息
        query.skip((page.getCurrent()-1)*page.getSize());
        query.limit(page.getSize());
        query.with(Sort.by(Direction.DESC,"sendTime"));
        // 封装结果数据
        page.setRecords(mgt.find(query, getEntityClass()));

        return page;
    }

    @Override
    public int countByCondition(String[] params, Object[] values) {
        Query query = createQuery(params, values, null);
        Long count = mgt.count(query, getEntityClass());
        return count.intValue();
    }

    /**
     * 创建带有where条件(只支持等值)和排序的Query对象
     *
     * @param params
     *            参数数组
     * @param values
     *            参数值数组
     * @param order
     *            排序
     * @return Query对象
     */
    protected Query createQuery(String[] params, Object[] values, String order) {
        Query query = new Query();

        // where 条件
        if (EmptyUtil.isNotEmpty(params) && EmptyUtil.isNotEmpty(values)) {
            for (int i = 0; i < params.length; i++) {
                query.addCriteria(where(params[i]).is(values[i]));
            }
        }

        // 排序
        List<Order> orderList = parseOrder(order);
        if (EmptyUtil.isNotEmpty(orderList)) {
            query.with(Sort.by(orderList));
        }

        return query;
    }

    /**
     * 解析Order字符串为所需参数
     *
     * @param order
     *            排序参数,如[id]、[id asc]、[id asc,name desc]
     * @return Order对象集合
     */
    protected List<Order> parseOrder(String order) {
        List<Order> list = null;
        if (EmptyUtil.isNotEmpty(order)) {
            list = new ArrayList<Order>();
            // 共有几组排序字段
            String[] fields = order.split(",");
            Order o = null;
            String[] item = null;
            for (int i = 0; i < fields.length; i++) {
                if (EmptyUtil.isEmpty(fields[i])) {
                    continue;
                }
                item = fields[i].split(" ");
                if (item.length == 1) {
                    o = new Order(Direction.ASC, item[0]);
                } else if (item.length == 2) {
                    o = new Order("desc".equalsIgnoreCase(item[1]) ? Direction.DESC : Direction.ASC, item[0]);
                } else {
                    throw new RuntimeException("排序字段参数解析出错");
                }
                list.add(o);
            }
        }
        return list;
    }

    /**
     * 将对象的字段及值反射解析为Map对象<br>
     * 这里使用Java反射机制手动解析,并且可以识别注解为主键的字段,以达到根据id进行更新实体的目的<br>
     * key:字段名称,value:字段对应的值
     *
     * @param t
     *            要修改的对象
     * @return Map对象,注意:id字段的key封装为“{id字段名称}”,以供后续识别
     * @throws Exception
     */
    protected Map<String, Object> parseEntity(T t) throws Exception {
        Map<String, Object> map = new HashMap<String, Object>();
		/*
		 * 解析ID
		 */
        String idName = "";
        Field[] declaredFields = getEntityClass().getDeclaredFields();
        for (Field field : declaredFields) {
            if (field.isAnnotationPresent(Id.class)) {
                field.setAccessible(true);
                map.put("{" + field.getName() + "}", field.get(t));
                idName = field.getName();
                break;
            }
        }
		/*
		 * 解析其他属性
		 */
        Method[] methods = getEntityClass().getDeclaredMethods();
        if (EmptyUtil.isNotEmpty(methods)) {
            for (Method method : methods) {
                if (method.getName().startsWith("get") && method.getModifiers() == Modifier.PUBLIC) {
                    String fieldName = parse2FieldName(method.getName());
                    if (!fieldName.equals(idName)) {
                        map.put(fieldName, method.invoke(t));
                    }
                }
            }
        }

        return map;
    }

    /**
     * 将get方法名转换为对应的字段名称
     *
     * @param methodName
     *            如:getName
     * @return 如:name
     */
    private String parse2FieldName(String methodName) {
        String name = methodName.replace("get", "");
        name = name.substring(0, 1).toLowerCase() + name.substring(1);
        return name;
    }
}
EmptyUtil
public class EmptyUtil {

    /**
     * 私有构造
     */
    private EmptyUtil() {
    }

    /**
     * 判断字符串是否为空
     *
     * @param str
     * @return true or false
     */
    public static boolean isEmpty(String str) {
        return str == null || str == "" || str.trim() == "" || str.length() <= 0;
    }

    /**
     * 判断List是否为空
     *
     * @param list
     * @return true or false
     */
    public static <T> boolean isEmpty(List<T> list) {
        return list == null || list.isEmpty();
    }

    /**
     * 判断Map是否为空
     *
     * @param map
     * @return true or false
     */
    public static <K, V> boolean isEmpty(Map<K, V> map) {
        return map == null || map.isEmpty();
    }

    /**
     * 判断数组是否为空
     *
     * @param array
     * @return true or false
     */
    public static <T> boolean isEmpty(T[] array) {
        return array == null || array.length == 0;
    }

    /**
     * 判断字符串是否不为空
     *
     * @param str
     * @return true or false
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * 判断List是否不为空
     *
     * @param list
     * @return true or false
     */
    public static <T> boolean isNotEmpty(List<T> list) {
        return !isEmpty(list);
    }

    /**
     * 判断Map是否不为空
     *
     * @param map
     * @return true or false
     */
    public static <K, V> boolean isNotEmpty(Map<K, V> map) {
        return !isEmpty(map);
    }

    /**
     * 判断数组是否不为空
     *
     * @param array
     * @return true or false
     */
    public static <T> boolean isNotEmpty(T[] array) {
        return !isEmpty(array);
    }
}
User
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = -4328989516223829865L;
    /**
     * 用户ID
     */
    private String id;
    /**
     * 用户账号
     */
    private String userName;
    /**
     * 密码
     */
    private String password;

}
UserMServiceImpl
public class UserMServiceImpl extends MongoServiceImpl<User> implements UserMService {
    @Override
    protected Class<User> getEntityClass() {
        return User.class;
    }

    @Override
    public void insert(User user) {
         save(user);
    }

    @Override
    public User selectById(String id) {
        return find(id);
    }
}
MongoController
@RestController
@RequestMapping("/mongo")
public class MongoController {

    @Autowired
    private UserMService userMService;

    @ResponseBody
    @GetMapping("/add")
    public User add(){

        String id = UUID.randomUUID().toString();
        User user = User.builder().id(id).userName("aa").password("111111").build();
        userMService.insert(user);

        User userMb= userMService.selectById(id);
        return userMb;
    }
}
测试结果

Springboot MongoDb uri 配置时区 springboot整合mongodb_ide_02


总结

希望通过本文,Spring Boot和MongoDB的整合有了更深入的了解。Spring Boot提供了简化开发流程的特性,使得构建应用程序变得更加容易和高效。而MongoDB作为一种NoSQL数据库,具有灵活的数据模型和可扩展性,能够满足各种应用程序的需求。

通过将Spring Boot和MongoDB结合起来,可以轻松地构建出高效、可靠的应用程序,并且能够处理大量的数据。无论是开发Web应用程序、移动应用程序还是企业级应用程序,Spring Boot和MongoDB的整合都能够为您提供强大的支持。