Springboot整合Mongodb

文章目录

  • 前言
  • 一 数据准备
  • 二 整合步骤
    • 1.引入Mongodb启动器依赖
    • 2.在全局配置文件中配置Mongodb
      • 2.1测试一下
    • 3.数据层编写
      • 简析MongodbTemplate
      • BlogMapper(数据操作层)
    • 4.服务层的编写
      • Service.interface
      • ServiceImpl.java
    • 5.控制层的编写
    • 6.前端页面编写
      • 博客管理页
      • 新增博客页(发布)
    • 7.运行结果及分析
      • 启动项目并查看原始数据
      • 新增(发布)博客
      • 查看已经发布的博客
      • 修改已经发布的博客
      • 删除已经发布的博客
    • 8.工具类和配置类的补充说明
      • BlogIDUtils
      • MvcConfig
  • 总结


前言

最近学习Mongodb,作为一款最像关系型数据库的非关系型数据库(很绕叭hhh),它的功能强大,能够很好地支持记录数据庞大的文档型数据,例如博客、评论这种内容有可能特别长的的数据。Mysql当然也有支持存储长类型文档的数据类型:Blob和Text,但是这并不是最好的选择,现在项目中多种数据库整合使用也是一种趋势,因此,我尝试使用目前最流行的框架+Mongodb实现一次整合以完成对前段时间学习的一次小复习和检验。
PS:只针对简单的增删改查的实现哦~


一 数据准备

好的内容整合需要贴切实际的数据,我们就拿常见的博客来实现一次整合,将博客的作者、标题、正文内容、评论、点赞数和发布时间作为我们需要存取和读取的数据.

想好想要存取的数据和数据类型,我们也就可以写出相对应的实体类了

package com.hang.pojo;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Blog {
    private String id;
    private String author;
    private String title;
    private String content;
    private String communication;
    private int likeNumbers;
    private Date commitTime;
}

二 整合步骤

1.引入Mongodb启动器依赖

		
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-data-mongodbartifactId>
        dependency>

2.在全局配置文件中配置Mongodb

#所选取的Mongodb数据库,前提是你的数据库必须创建并且存入内存(没有集合只会在缓存中)
spring.data.mongodb.database = users
#由于我是本地,因此连本地机就行了
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
#没有设置密码,因此为空
spring.data.mongodb.password=

2.1测试一下

在测试类中测试一下可不可以成功连接Mongodb

package com.hang;

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class Springboot09MongodbApplicationTests {

    @Test
    void contextLoads() {
        MongoClient mongoClient=null;
        try {
            mongoClient = MongoClients.create("mongodb://127.0.0.1:27017");
            MongoDatabase users = mongoClient.getDatabase("users");
            MongoCollection<Document> test = users.getCollection("test");
            test.insertOne(new Document("name","小红"));
            System.out.println("数据库连接成功,并成功插入数据");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            mongoClient.close();
        }
    }

}

测试结果:(连接成功!)
Springboot整合Mongodb_第1张图片

3.数据层编写

本次虽然是小项目,但是也严格按照dao-service-controller三层逻辑进行编写测试,由于实体层在设计之初就已经编写了,因此这里直接从数据层开始编写.

简析MongodbTemplate

我们可以使用Mongodb.core包下已经编写好的MongoTemplate直接实现对数据层的增删改查,我们可以点进源码具体查看里面的方法:

增的方法有两个,一个是通过集合增加,一个可以通过泛型(对象)增加,我们不如使用save()方法.
Springboot整合Mongodb_第2张图片

删除的方法应该是remove()了,翻遍源码也就找到这一种删除的方法
Springboot整合Mongodb_第3张图片
修改的方法可以分成两种:
①修改第一个符合条件的文档
②修改所有符合条件的文档
Springboot整合Mongodb_第4张图片
查询的方法也有多种,这里只讲解两种;一种是find()方法,找符合条件的值,另一种是findAll()方法,可以查询集合中的所有文档.(还有findById等方法,可以自行读源码进行理解)

Springboot整合Mongodb_第5张图片
在这里插入图片描述

其实这些方法与我们之前接触的JdbcTemplate相类似,都是已经封装好的工具,可以直接进行使用,接下来我们就根据这些方法实现对Mongodb的数据写入和读取.

BlogMapper(数据操作层)

如果你熟悉了上面我所说的方法,那么现在直接"开箱"即用即可.

package com.hang.dao;

import com.hang.pojo.Blog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
public class BlogMapper {
    @Autowired
    private MongoTemplate mongoTemplate;

    public void saveBlog(Blog blog){
        mongoTemplate.save(blog);
    }

    public List<Blog> getAllBlog(){
        return mongoTemplate.findAll(Blog.class);
    }

    public Blog getBlogById(Query query){       //根据查询语句来查询指定内容的博客
        return mongoTemplate.findOne(query,Blog.class);
    }

    public void updateBlog(Query query, Update update){
        mongoTemplate.updateMulti(query,update,Blog.class);
    }

    public void deleteBlog(Query query){
        mongoTemplate.remove(query,Blog.class);
    }
}

4.服务层的编写

我们依旧按照规范,使用实现类去实现接口中的方法来编写Service层的代码

Service.interface

package com.hang.service;

import com.hang.pojo.Blog;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;

import java.util.List;
import java.util.Map;

public interface BlogService {
    //获得所有的博客
    public List<Blog> getAllBlog();
    //获取指定内容的博客
    public Blog getBlogById(String id);
    //新增一篇博客
    public void addBlog(Blog blog);
    //修改一篇博客
    public void updateBlog(String id, Map<String,Object> map);
    //删除一篇博客
    public void deleteBlog(String id);
}

ServiceImpl.java

数据该如何通过前端返回的数据进行查询、修改、增加等,具体的逻辑需要在这一层实现,我们很难从前端返回一个Query类型或者Update类型的数据,因此我们不妨返回需要修改哪条数据(_id)的哪些值(Map),然后在服务层封装Query和Update,再进行数据层的修改,这也是三层模型的优势所在.

package com.hang.service;

import com.hang.dao.BlogMapper;
import com.hang.pojo.Blog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;

@Service("blogService")
public class BlogServiceImpl implements BlogService{
    @Autowired
    BlogMapper mapper;

    @Override
    public List<Blog> getAllBlog() {
        return mapper.getAllBlog();
    }

    @Override
    public Blog getBlogById(String id) {
        //传入ID然后获取指定的博客
        Criteria criteriaId=Criteria.where("id").is(id);
        Query query=new Query(criteriaId);
        return mapper.getBlogById(query);
    }

    @Override
    public void addBlog(Blog blog) {
        mapper.saveBlog(blog);
    }

    @Override
    public void updateBlog(String id, Map<String,Object> map) {
        Criteria criteriaId=Criteria.where("id").is(id);
        Query query=new Query(criteriaId);
        Update update=new Update();
        update.set("title",map.get("title"));
        update.set("author",map.get("author"));
        update.set("content",map.get("content"));
        update.set("commitTime",map.get("commitTime"));
        mapper.updateBlog(query,update);
    }

    @Override
    public void deleteBlog(String id) {
        Criteria criteriaId=Criteria.where("id").is(id);
        Query query=new Query(criteriaId);
        mapper.deleteBlog(query);
    }
}

5.控制层的编写

这一层没有啥特别介绍的,就是接收前端的数据并且实现页面跳转.

package com.hang.controller;

import com.hang.pojo.Blog;
import com.hang.service.BlogService;
import com.hang.util.BlogIDUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Controller
public class BlogController {
    @Autowired
    private BlogService service;

    @RequestMapping("/toBlog")
    public String blogList(Model model){
        List<Blog> blogs = service.getAllBlog();
        model.addAttribute("blogs",blogs);
        return "html/blog";
    }

    @GetMapping("/toAddBlog")
    public String toAddPage(){
        return "html/addBlog";
    }

    @PostMapping("/add")
    public String addBlog(Blog blog){
        /**添加操作
         *
         */
        String randomBlogId = new BlogIDUtils().getRandomBlogId();
        blog.setId(randomBlogId);
        blog.setLikeNumbers(0);     //一开始点赞数为0
        blog.setCommunication("");  //评论也为空
        service.addBlog(blog);
        return "redirect:/toBlog";
    }

    @GetMapping("/toUpdate/{id}")
    public String toUpdatePage(Model model, @PathVariable("id") String id){
        //根据前台传回的id添加到指定的模型
        Blog blog=service.getBlogById(id);
        model.addAttribute("blog",blog);
        return "html/updateBlog";
    }

    @PostMapping("/update")
    public String updateBlog(Map<String,Object> map,Blog blog){
        map.put("author",blog.getAuthor());
        map.put("title",blog.getTitle());
        map.put("content",blog.getContent());
        map.put("commitTime",blog.getCommitTime());
        service.updateBlog(blog.getId(),map);
        return "redirect:/toBlog";
    }

    @GetMapping("/toInfo/{id}")
    public String toInfoPage(Model model,@PathVariable("id") String id){
        Blog blog=service.getBlogById(id);
        model.addAttribute("blog",blog);
        return "html/info";
    }

    @RequestMapping("/delete/{id}")
    public String deleteBlog(@PathVariable("id") String id){
        service.deleteBlog(id);
        return "redirect:/toBlog";
    }
}

6.前端页面编写

这里就只放最重要的两个前端页面,分别是博客管理页,新增博客页,这里的前端模板使用了b站狂神说的前端页面模板,并附上资源,需要的自取.

博客管理页

DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Dashboard Template for Bootstraptitle>
    
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

    
    <link th:href="@{/css/dashboard.css}" rel="stylesheet">
    <style type="text/css">
        /* Chart.js */

        @-webkit-keyframes chartjs-render-animation {
            from {
                opacity: 0.99
            }
            to {
                opacity: 1
            }
        }

        @keyframes chartjs-render-animation {
            from {
                opacity: 0.99
            }
            to {
                opacity: 1
            }
        }

        .chartjs-render-monitor {
            -webkit-animation: chartjs-render-animation 0.001s;
            animation: chartjs-render-animation 0.001s;
        }
    style>
head>

<body>
<div th:insert="~{/common/commons::topbar}">div>

<div class="container-fluid">
    <div class="row">
        
        <div th:insert="~{/common/commons::sidebar(active='blog.html')}">div>

        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <h2>博客信息h2>
            <a class="btn btn-sm btn-success" th:href="@{/toAddBlog}">添加a>
            <div class="table-responsive">
                <table class="table table-striped table-sm">
                    <thead>
                    <tr>
                        <th>博客作者th>
                        <th>博客标题th>
                        <th>博客内容th>
                        <th>点赞数th>
                        <th>发布时间th>
                        <th>操作th>
                    tr>
                    thead>
                    <tbody>
                        <tr th:each="blog:${blogs}">
                            <td th:text="${blog.getAuthor()}">td>
                            <td th:text="${blog.getTitle()}">td>
                            
                            <td th:text="${blog.getContent().substring(0,10)}">td>
                            <td th:text="${blog.getLikeNumbers()}">td>
                            <td th:text="${#dates.format(blog.getCommitTime(),'yyyy-MM-dd HH:mm:ss')}">td>
                            <td>
                                
                                <a class="btn btn-sm btn-success" th:href="@{/toInfo/{id}/(id=${blog.getId()})}">查看a>
                                <a class="btn btn-sm btn-primary" th:href="@{/toUpdate/{id}/(id=${blog.getId()})}">编辑a>
                                <a class="btn btn-sm btn-danger" th:href="@{/delete/{id}/(id=${blog.getId()})}" onclick="return confirm('确认删除');" title="删除">删除a>
                            td>
                        tr>
                    tbody>
                table>
            div>
        main>
    div>
div>



<script type="text/javascript" src="asserts/js/jquery-3.2.1.slim.min.js">script>
<script type="text/javascript" src="asserts/js/popper.min.js">script>
<script type="text/javascript" src="asserts/js/bootstrap.min.js">script>


<script type="text/javascript" src="asserts/js/feather.min.js">script>
<script>
    feather.replace()
script>


<script type="text/javascript" src="asserts/js/Chart.min.js">script>
<script>
    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
            datasets: [{
                data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
                lineTension: 0,
                backgroundColor: 'transparent',
                borderColor: '#007bff',
                borderWidth: 4,
                pointBackgroundColor: '#007bff'
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: false
                    }
                }]
            },
            legend: {
                display: false,
            }
        }
    });
script>

body>

html>

新增博客页(发布)

DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>Dashboard Template for Bootstraptitle>
    
    <link th:href="@{/css/bootstrap.min.css}" rel="stylesheet">

    
    <link th:href="@{/css/dashboard.css}" rel="stylesheet">
    <style type="text/css">
        /* Chart.js */

        @-webkit-keyframes chartjs-render-animation {
            from {
                opacity: 0.99
            }
            to {
                opacity: 1
            }
        }

        @keyframes chartjs-render-animation {
            from {
                opacity: 0.99
            }
            to {
                opacity: 1
            }
        }

        .chartjs-render-monitor {
            -webkit-animation: chartjs-render-animation 0.001s;
            animation: chartjs-render-animation 0.001s;
        }
    style>
head>

<body>
<div th:insert="~{/common/commons::topbar}">div>

<div class="container-fluid">
    <div class="row">
        
        <div th:replace="~{/common/commons::sidebar(active='blog.html')}">div>

        <main role="main" class="col-md-9 ml-sm-auto col-lg-10 pt-3 px-4">
            <form th:action="@{/add}" method="post">
                <div class="form-group">
                    <label>博客作者label>
                    <input type="text" name="author" class="form-control" placeholder="请输入作者名">
                div>
                <div class="form-group">
                    <label>博客标题label>
                    <input type="text" name="title" class="form-control" placeholder="请输入博客标题">
                div>

                <div class="form-group">
                    <label>博客内容label>
                    <textarea name="content" class="form-control"  rows="20">textarea>
                div>

                <div class="form-group">
                    <label>发布时间label>
                    <input type="text" name="commitTime" class="form-control" placeholder="请输入发布日期">
                div>
                <button type="submit" class="btn btn-primary">发布button>
                <button type="reset" class="btn btn-danger">清空button>
            form>
        main>
    div>
div>



<script type="text/javascript" src="asserts/js/jquery-3.2.1.slim.min.js">script>
<script type="text/javascript" src="asserts/js/popper.min.js">script>
<script type="text/javascript" src="asserts/js/bootstrap.min.js">script>


<script type="text/javascript" src="asserts/js/feather.min.js">script>
<script>
    feather.replace()
script>


<script type="text/javascript" src="asserts/js/Chart.min.js">script>
<script>
    var ctx = document.getElementById("myChart");
    var myChart = new Chart(ctx, {
        type: 'line',
        data: {
            labels: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
            datasets: [{
                data: [15339, 21345, 18483, 24003, 23489, 24092, 12034],
                lineTension: 0,
                backgroundColor: 'transparent',
                borderColor: '#007bff',
                borderWidth: 4,
                pointBackgroundColor: '#007bff'
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: false
                    }
                }]
            },
            legend: {
                display: false,
            }
        }
    });
script>
body>
html>

其它页面就不放了,文章最后我会放项目文件链接,需要的可以自取~

7.运行结果及分析

启动项目并查看原始数据

Springboot整合Mongodb_第6张图片
到Mongodb Compass中查看是否有数据:

在全局配置文件中配置指定数据库后,使用其Template创建文档时,会自动判断该集合(对应实体类名字)是否已存在,若不存在会自动创建这个集合~

Springboot整合Mongodb_第7张图片

新增(发布)博客

我们点击添加按钮,模拟发布一篇博客
Springboot整合Mongodb_第8张图片
点击后,信息被成功添加到Mongodb并能读取
Springboot整合Mongodb_第9张图片
Springboot整合Mongodb_第10张图片

查看已经发布的博客

点击查看按钮即可查看已经发布的博客,页面简陋,且点赞功能暂时没有添加hh.
Springboot整合Mongodb_第11张图片

修改已经发布的博客

返回博客管理页面,点击编辑按钮即可实现对博客内容的修改
我们对部分信息进行修改.
Springboot整合Mongodb_第12张图片

博客ID并没有进行改变,其它修改的值修改成功~
Springboot整合Mongodb_第13张图片

删除已经发布的博客

这里就不予演示了,删除无非就是将id传入然后调用deleteBlog方法进行删除,UU们可以自行去尝试~

public void deleteBlog(String id) {
        Criteria criteriaId=Criteria.where("id").is(id);
        Query query=new Query(criteriaId);
        mapper.deleteBlog(query);
    }

8.工具类和配置类的补充说明

BlogIDUtils

细心的朋友注意到,我从来没有编写博客ID,但是实际中又有这个ID存在,这是因为我编写了一个博客ID的自动生成工具类,新增博客时随机生成一个ID赋予它即可~

package com.hang.util;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;

/***实现博客ID的自增,并且保证其不会重复出现
 *
 */
public class BlogIDUtils {
    public String getRandomBlogId(){
        StringBuffer sb=new StringBuffer("lyh");
        LocalDateTime ldt=LocalDateTime.now();      //获取当前的时间
        DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        sb.append(dtf.format(ldt));                 //连接当前时间
        //如果同一时刻同一地点同一用户注册了账号,那么还会有一层随机数
        sb.append("-");
        sb.append(random());
        return sb.toString();
    }

    public String random(){
        Random random=new Random();
        int randomInt = random.nextInt(100008);
        return String.valueOf(randomInt);
    }
}

MvcConfig

项目中我也遇到了进入指定页面难的问题,因此重写视图配置页面的跳转,方便在进入项目根目录时就能跳转到我想要的页面

package com.hang.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/***拓展SpringMVC
 *
 */
@Configuration
public class MvcConfig implements WebMvcConfigurer {
    /***配置页面的基本跳转
     *
     * @param registry
     */
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("dashboard");
        registry.addViewController("/dashboard.html").setViewName("dashboard");
    }
}


总结

本次通过SpringBoot整合Mongodb并对其场景进行一次较为实际的应用,虽然只是实现较为简单的增删改查,却也是充满艰辛,希望能够有新的提升叭~
项目链接:

链接:https://pan.baidu.com/s/1mO4iZLwLeaXsYOwUYqsZkQ
提取码:java

你可能感兴趣的:(学习笔记,java,mongodb,spring,boot)