6.3 Spring Boot集成mongodb开发

本章我们通过SpringBoot集成mongodb,Java,Kotlin开发一个极简社区文章博客系统。

0 mongodb简介

Mongo 的主要目标是在键/值存储方式(提供了高性能和高度伸缩性)和传统的RDBMS 系统(具有丰富的功能)之间架起一座桥梁,它集两者的优势于一身。Mongo 的BSON 数据格式非常适合文档化格式的存储及查询。[1]

关于nosql和rdbms的对比以及选择,我参考了不少资料,关键一点在于:nosql可以轻易扩展表的列,对于业务快速变化的应用场景非常适合;rdbms则需要安装关系型数据库模式对业务进行建模,适合业务场景已经成熟的系统。我目前的这个项目——dailyReport,我暂时没法确定的是,对于一个report,它的属性应该有哪些:date、title、content、address、images等等,基于此我选择mongodb作为该项目的持久化存储。

1 系统基本功能

1.支持markdown编辑器
2.写文章,编辑文章,阅读文章基础博客功能
3.文章列表排序,搜索

2 系统技术框架

开发环境:

MacOS Sierra
IDEA 2017.1
JDK 1.8.0_40
mongod-3.2.4
Gradle 3.5-rc-2

后端:

开发语言:Java 混合Kotlin语言开发

开发框架:

kotlin,Version = '1.1.0'
SpringBoot,Version = '1.5.2.RELEASE'
Spring-data-mongodb

前端:

JavaScript、html、css
requirejs
jquery
bootstrap
dataTables
meditor

3 系统架构设计

领域模型

Blog

前后端分层

后端Controller

jsp

js

4 数据库环境配置

1.build.gradle配置

添加mongodb starter

compile('org.springframework.boot:spring-boot-starter-data-jpa')
compile('org.springframework.boot:spring-boot-starter-data-mongodb')

添加mongo-java-driver

compile('org.mongodb:mongo-java-driver:3.4.2')

完整配置如下:

group = 'com.restfeel'
version = '0.0.1-SNAPSHOT'
description = ""apply {plugin "kotlin"plugin "kotlin-spring"plugin "kotlin-jpa"plugin "org.springframework.boot"plugin 'java'plugin 'eclipse'plugin 'idea'plugin 'war'plugin 'maven'
}sourceCompatibility = 1.8
targetCompatibility = 1.8sourceSets {main {kotlin { srcDir "src/main/kotlin" }java { srcDir "src/main/java" }}test {kotlin { srcDir "src/test/kotlin" }java { srcDir "src/test/java" }}
}jar {baseName = 'restfeel'version = '0.0.1'
}buildscript {ext {kotlinVersion = '1.1.0'springBootVersion = '1.5.2.RELEASE'}dependencies {classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion"classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlinVersion"classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"}repositories {mavenLocal()mavenCentral()maven { url "http://oss.jfrog.org/artifactory/oss-release-local" }maven { url "http://jaspersoft.artifactoryonline.com/jaspersoft/jaspersoft-repo/" }maven { url "https://oss.sonatype.org/content/repositories/snapshots" }}
}dependencies {compile("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")compile("org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion")compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.8.4")compile('org.springframework.boot:spring-boot-starter')compile('org.springframework.boot:spring-boot-starter-data-jpa')compile('org.springframework.boot:spring-boot-starter-data-mongodb')compile('org.springframework.boot:spring-boot-starter-actuator')compile('org.springframework.boot:spring-boot-starter-web')compile('org.springframework.boot:spring-boot-starter-security')compile('org.springframework.boot:spring-boot-starter-remote-shell')compile('org.springframework.boot:spring-boot-starter-aop')providedCompile('org.springframework.boot:spring-boot-starter-tomcat')compile('javax.servlet:jstl')providedCompile('org.apache.tomcat.embed:tomcat-embed-jasper')//thymeleaf
//    compile("org.springframework.boot:spring-boot-starter-thymeleaf")compile('org.hibernate:hibernate-validator:5.1.3.Final')compile('org.mongodb:mongo-java-driver:3.4.2')compile('org.hsqldb:hsqldb:2.3.2')compile('org.apache.httpcomponents:httpclient:4.5.1')compile('org.apache.httpcomponents:httpmime:4.5.1')compile('org.apache.commons:commons-lang3:3.3.2')compile('com.sendgrid:sendgrid-java:2.1.0')compile('com.ryantenney.metrics:metrics-spring:3.0.0')compile('net.sf.jasperreports:jasperreports:6.0.0') {exclude module: 'jdtcore'exclude module: 'jackson-annotations'}compile('com.mangofactory:swagger-springmvc:0.9.4')compile('org.ajar:swagger-spring-mvc-ui:0.4')compile('com.google.oauth-client:google-oauth-client:1.19.0')compile('com.jayway.jsonpath:json-path:2.0.0')compile('io.swagger:swagger-compat-spec-parser:1.0.12')compile('org.raml:raml-parser:0.8.12') {exclude module: 'slf4j-log4j12'exclude module: 'log4j'}testCompile('org.springframework.boot:spring-boot-starter-test')// https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtoolscompile group: 'org.springframework.boot', name: 'spring-boot-devtools'}compileJava {//options.fork = trueoptions.incremental = true
}repositories {mavenLocal()mavenCentral()maven { url "http://oss.jfrog.org/artifactory/oss-release-local" }maven { url "http://jaspersoft.artifactoryonline.com/jaspersoft/jaspersoft-repo/" }maven { url "https://oss.sonatype.org/content/repositories/snapshots" }}
2.实现AbstractMongoConfiguration类
package com.restfeel.configimport com.mongodb.Mongo
import com.mongodb.MongoClient
import com.mongodb.MongoCredential
import com.mongodb.ServerAddress
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.env.Environment
import org.springframework.data.mongodb.config.AbstractMongoConfiguration
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories/*** Created by jack on 2017/3/29.*/@Configuration
@EnableMongoRepositories(*arrayOf("com.restfeel.dao", "com.restfeel.service"))
class PersistenceConfig : AbstractMongoConfiguration() {@Autowiredprivate val env: Environment? = nulloverride fun getDatabaseName(): String {return env!!.getProperty("mongodb.name")}@Bean@Throws(Exception::class)override fun mongo(): Mongo {return MongoClient(listOf(ServerAddress(env!!.getProperty("mongodb.host"), env!!.getProperty("mongodb.port", Int::class.java))),listOf(MongoCredential.createCredential(env!!.getProperty("mongodb.username"), env!!.getProperty("mongodb.name"),env!!.getProperty("mongodb.password").toCharArray())))}//    override fun getMappingBasePackage(): String {
//        return "com.restfiddle.dao"
//    }/*** 这地方是配置扫描继承Repository类的所有接口类的路径的,路径配置错误,bean就不会创建了。* 东海陈光剑 Jason Chen @蒋村花园如意苑 2017.3.30 01:41:35*/override fun getMappingBasePackages(): Collection<String> {return setOf("com.restfeel.dao", "com.restfeel.service")}
}

5 定义领域对象

领域模型类
package com.restfeel.entityimport org.bson.types.ObjectId
import org.springframework.data.mongodb.core.mapping.Document
import java.util.*
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.persistence.Version@Document(collection = "blog") // 如果不指定collection,默认遵从命名规则
class Blog {@Id@GeneratedValue(strategy = GenerationType.AUTO)var id: String = ObjectId.get().toString()@Versionvar version: Long = 0var title: String = ""var content: String = ""var author: String = ""var gmtCreated: Date = Date()var gmtModified: Date = Date()var isDeleted: Int = 0 //1 Yes 0 Novar deletedDate: Date = Date()override fun toString(): String {return "Blog(id='$id', version=$version, title='$title', content='$content', author='$author', gmtCreated=$gmtCreated, gmtModified=$gmtModified, isDeleted=$isDeleted, deletedDate=$deletedDate)"}}

6 核心业务逻辑实现

BlogService代码:
package com.restfeel.serviceimport com.restfeel.entity.Blog
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.Query
import org.springframework.data.repository.query.Paraminterface BlogService : MongoRepository<Blog, String> {@Query("{ 'title' : ?0 }")fun findByTitle(@Param("title") title: String): Iterable<Blog>}

这里是精确匹配查询。我们一般在实际应用场景中会使用模糊查询。我们简单讲讲mongo的模糊查询。

LIKE模糊查询title包含A字母的数据(%A%)

SQL:

SELECT * FROM Blog WHERE title LIKE "%A%"

MongoDB:

db.Blog.find({title :/A/})

这是mongo里面的正则表达式。等同于

db.Blog.find({title :{$regex:"A"}})

LIKE模糊查询title以字母A开头的数据(A%)

SQL:

SELECT * FROM Blog WHERE title LIKE "A%"

MongoDB:

db.Blog.find({title :/^A/})

如果我们使用org.springframework.data.mongodb.repository.Query,不能直接这么写:{title :/^A/}。我们需要使用regex表达式来写。代码示例如下:

package com.restfeel.serviceimport com.restfeel.entity.Blog
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.data.mongodb.repository.Query
import org.springframework.data.repository.query.Paraminterface BlogService : MongoRepository<Blog, String> {//    @Query(value = "{ 'title' : ?0}")@Query(value = "{ 'title' : {\$regex: ?0, \$options: 'i'}}")fun findByTitle(@Param("title") title: String): Iterable<Blog>}

我们这里设置 $options 为 $i,意思是检索不区分大小写。

BlogController代码:
package com.restfeel.controllerimport com.restfeel.entity.Blog
import com.restfeel.service.BlogService
import org.springframework.boot.autoconfigure.EnableAutoConfiguration
import org.springframework.context.annotation.ComponentScan
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.stereotype.Controller
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.ResponseBody
import java.util.*
import javax.servlet.http.HttpServletRequest/*** 文章列表,写文章的Controller* @author Jason Chen  2017/3/31 01:10:16*/@Controller
@EnableAutoConfiguration
@ComponentScan
@Transactional(propagation = Propagation.REQUIRES_NEW)
class BlogController(val blogService: BlogService) {@GetMapping("/blogs.do")fun listAll(model: Model): String {val authentication = SecurityContextHolder.getContext().authenticationmodel.addAttribute("currentUser", if (authentication == null) null else authentication.principal as UserDetails)val allblogs = blogService.findAll()model.addAttribute("blogs", allblogs)return "jsp/blog/list"}@PostMapping("/saveBlog")@ResponseBodyfun saveBlog(blog: Blog, request: HttpServletRequest):Blog {blog.author = (request.getSession().getAttribute("currentUser") as UserDetails).usernamereturn blogService.save(blog)}@GetMapping("/goEditBlog")fun goEditBlog(@RequestParam(value = "id") id: String, model: Model): String {model.addAttribute("blog", blogService.findOne(id))return "jsp/blog/edit"}@PostMapping("/editBlog")@ResponseBodyfun editBlog(blog: Blog, request: HttpServletRequest) :Blog{blog.author = (request.getSession().getAttribute("currentUser") as UserDetails).usernameblog.gmtModified = Date()blog.version = blog.version + 1return blogService.save(blog)}@GetMapping("/blog")fun blogDetail(@RequestParam(value = "id") id: String, model: Model): String {model.addAttribute("blog", blogService.findOne(id))return "jsp/blog/detail"}@GetMapping("/listblogs")@ResponseBodyfun listblogs(model: Model) = blogService.findAll()@GetMapping("/findBlogByTitle")@ResponseBodyfun findBlogByTitle(@RequestParam(value = "title") title: String) = blogService.findByTitle(title)}

7 前端jsp设计

list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html lang="en">
<head><jsp:include page="../header.jsp"></jsp:include>
</head>
<body>
<jsp:include page="../top-nav.jsp"></jsp:include><div class="col-sm-12"><h2>文章列表</h2><div class="pull-right"><a href="addBlog" class="btn btn-primary write-btn" target="_blank">写文章</a></div><table id="blogsTable" class="table table-hover"><thead><tr><th>No</th><th>Title</th><th>Author</th><%--<th>Content</th>--%><th>CreateTime</th></tr></thead><tbody><c:forEach items="${blogs}" var="blog" varStatus="status"><tr><td>${status.index+1}</td><td><a href="blog?id=${blog.id}" target="_blank">${blog.title}</a></td><td>${blog.author}</td><%--<td>${fn: substring(blog.content,0,100)}</td>--%><td>${blog.gmtCreated}</td></tr></c:forEach></tbody></table>
</div>
<jsp:include page="../copyright.jsp"></jsp:include>
<script data-main="js/views/blog/config" src="js/libs/require/require.js"></script>
<script type="text/javascript">require(['blog-list-view']);
</script>
</body>
</html>

add.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="en">
<head><jsp:include page="../header.jsp"></jsp:include>
</head>
<body>
<jsp:include page="../top-nav.jsp"></jsp:include>
<div class="col-sm-10 blog"><h2>写文章</h2><form id="addBlogForm" class="form-horizontal"><div class="form-group-lg"><label></label><input type="text" name="title" class="form-control" placeholder="文章标题"></div><div class="form-group-lg"><label></label><textarea id="blogContentEditor" type="text" name="content" class="form-control" rows="100"placeholder=""></textarea></div><div class="form-group-lg"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-primary rest-blog-submit-btn" id="addBlogBtn">保存并发表</button></div></div></form>
</div>
<jsp:include page="../copyright.jsp"></jsp:include>
<script data-main="js/views/blog/config" src="js/libs/require/require.js"></script>
<script type="text/javascript">require(['blog-add-view']);
</script>
</body>
</html>

detail.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="en">
<head><jsp:include page="../header.jsp"></jsp:include>
</head>
<body>
<jsp:include page="../top-nav.jsp"></jsp:include>
<div class="container-fluid"><div class="col-sm-10 blog"><h1 class="center">${blog.title}</h1><input type="hidden" id="blogId" value="${blog.id}"><div id="goEditBlog" class="btn-link pull-right">编辑</div><div class="rest-center">作者: ${blog.author}日期: <fmt:formatDate pattern="yyyy/MM/dd HH:mm:ss" value="${blog.gmtModified}"/></div><textarea id="blogContent" style="display: none"><c:out value="${blog.content}"escapeXml='false'></c:out></textarea><%--<textarea id="blogContent" rows="50" cols="150"><c:out value="${blog.content}" escapeXml='false'></c:out></textarea>--%><div class="markdown-body rest-blog-body"></div></div></div><jsp:include page="../copyright.jsp"></jsp:include><script data-main="js/views/blog/config" src="js/libs/require/require.js"></script>
<script type="text/javascript">require(['blog-detail-view']);
</script>
</body>
</html>

edit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html lang="en">
<head><jsp:include page="../header.jsp"></jsp:include>
</head>
<body>
<jsp:include page="../top-nav.jsp"></jsp:include>
<div class="col-sm-10 blog"><h2>写文章</h2><form id="editBlogForm" class="form-horizontal"><input type="hidden" name="id" value="${blog.id}"><div class="form-group-lg"><label></label><input type="text" name="title" class="form-control" placeholder="文章标题" value="${blog.title}"></div><div class="form-group-lg"><label></label><textarea id="blogContentEditor" type="text" name="content" class="form-control" rows="100"placeholder=""><c:out value="${blog.content}" escapeXml='false'></c:out></textarea></div><div class="form-group-lg"><div class="col-sm-offset-2 col-sm-10"><button type="submit" class="btn btn-primary rest-blog-submit-btn" id="editBlogBtn">保存并发表</button></div></div></form>
</div>
<jsp:include page="../copyright.jsp"></jsp:include>
<script data-main="js/views/blog/config" src="js/libs/require/require.js"></script>
<script type="text/javascript">require(['blog-edit-view']);
</script>
</body>
</html>

8 前端js代码

我们采用requirejs管理js。js代码跟html代码隔离。
config.js

/*** 入口文件config.js。它一般用来对requirejs进行配置,并且载入真正的程序模块。*/require.config({baseUrl: '/js',paths: {jquery: 'libs/jquery-2.1.4.min',jqueryUi: 'libs/jquery-ui.min',bootstarp: 'libs/bootstrap.min',datatables: 'plugin/datatables/jquery.dataTables',jsonview: 'plugin/jsonview/jquery.jsonview',bootstrapDialog: 'plugin/bootstrap-dialog/bootstrap-dialog',meditor: 'plugin/mditor-master/dist/js/mditor.min',},shim: {'jqueryUi': {deps: ['jquery']},'bootstarp': {deps: ['jquery', 'jqueryUi']},'datatables': {deps: ['jquery']},'jsonview': {deps: ['jquery']},'bootstrapDialog': {deps: ['jquery']},'meditor': {deps: ['jquery']}}
});

blog-add-view.js

/*** Created by jack on 2017/3/29.*/define(function (require) {"use strict";require('meditor');jQuery(function () {//meditorvar mditor = Mditor.fromTextarea(document.getElementById('blogContentEditor'));//是否打开分屏mditor.split = true;    //打开//是否打开预览mditor.preivew = true;  //打开//是否全屏mditor.fullscreen = false;  //关闭//获取或设置编辑器的值mditor.on('ready', function () {mditor.value = '#Restfeel';});//写文章jQuery("#addBlogBtn").on("click", function () {jQuery.ajax({url: 'saveBlog',type: 'POST',data: $('#addBlogForm').serialize(),async: false,success: function (data) {if (data) {alert('保存成功');// location.href = 'blogs.do';window.opener = null;window.open('', '_self');window.close();} else {alert(data);}},error: function (data) {alert(data);}});});});});

blog-detail-view.js

/*** Created by jack on 2017/3/29.*/define(function (require) {"use strict";require('meditor');$(function () {var parser = new Mditor.Parser();// var blogContent = document.getElementById('blogContent').innerHTML;//这个遇到<>等特殊字符会被转译var blogContent = document.getElementById('blogContent').value; //直接取原本的字符串。不会被转译var html = parser.parse(blogContent);$('.markdown-body').append(html);//编辑文章$('#goEditBlog').on('click',function () {var blogId = $('#blogId').val();location.href = 'goEditBlog?id=' + blogId;});//源码高亮hljs.initHighlightingOnLoad();});});

blog-edit-view.js

/*** Created by jack on 2017/3/29.*/define(function (require) {"use strict";require('meditor');jQuery(function () {//meditorvar mditor = Mditor.fromTextarea(document.getElementById('blogContentEditor'));//是否打开分屏mditor.split = true;    //打开//是否打开预览mditor.preivew = true;  //打开//是否全屏mditor.fullscreen = false;  //关闭//写文章jQuery("#editBlogBtn").on("click", function () {jQuery.ajax({type: 'POST',url: 'editBlog',data: jQuery('#editBlogForm').serialize(),//dataType: 'json',async: false,//在请求之前调用的函数beforeSend: function () {},success: function (data) {if (data) {alert('保存成功');history.go(-1);} else {alert(data);}},//调用执行后调用的函数complete: function (XMLHttpRequest, textStatus) {},error: function (data) {alert(data);}});});});});

blog-list-view.js

/*** Created by jack on 2017/3/29.*/define(function (require) {"use strict";require('datatables');$(function () {// 文章列表var aLengthMenu = [10, 20, 50, 100, 200];var dataTableOptions = {bDestroy: true,paging: true,lengthChange: true,searching: true,ordering: true,order: [3, "desc"],autoWidth: true,processing: true,stateSave: true,responsive: true,fixedHeader: false,aLengthMenu: aLengthMenu,language: {search: "<div style='border-radius:10px;margin-left:auto;margin-right:2px;width:760px;'>_INPUT_ &nbsp;<span class='btn btn-primary'>搜索</span></div>",paginate: {//分页的样式内容previous: "上一页",next: "下一页",first: "第一页",last: "最后"}},zeroRecords: "没有内容",//table tbody内容为空时,tbody的内容。//下面三者构成了总体的左下角的内容。info: "总计 _TOTAL_ 条,共 _PAGES_ 页,_START_ - _END_ ",//左下角的信息显示,大写的词为关键字。infoEmpty: "0条记录",//筛选为空时左下角的显示。infoFiltered: ""//筛选之后的左下角筛选提示}$('#blogsTable').dataTable(dataTableOptions)});});

9 运行效果

直接使用IDEA gradle插件,点击bootRun

我们先在Swagger里面测试一下模糊查询接口findBlogByTitle

http://127.0.0.1:5678/findBlogByTitle?title=Spring

分别测试写文章,文章列表,阅读文章页面:

写文章

阅读文章

文章列表

系统源代码

详见工程:
https://github.com/Jason-Chen-2017/restfeel

小结

我们采用SpringBoot集成mongodb,Java,Kotlin,jsp,jquery,bootstrap,requirejs等技术框架,架构层次分明,快速开发出了一个极简的社区文章博客系统。

参考资料:
1.http://baike.baidu.com/item/mongodb

6.3 Spring Boot集成mongodb开发相关推荐

  1. Spring boot集成axis2开发webservice 服务

    Spring boot集成axis2开发webservice 服务 1.新建Spring boot 项目 此处省略... 项目结构如下: 2.添加Axis2依赖 <!--axis2版本信息--& ...

  2. spring boot 集成 mongodb 通过id查询问题

    spring boot 集成 mongodb 通过id查询问题 java 连接 mongodb 查询时通过id 查询不到数据,但其他字段是可以的,现在请各位大佬看看会是什么原因 通过id为参数查询 具 ...

  3. Spring Boot 集成 WebFlux 开发 Reactive Web 应用

    Spring Boot 集成 WebFlux 开发 Reactive Web 应用 <Spring Boot 实战开发>-- 基于 Gradle + Kotlin的企业级应用开发最佳实践 ...

  4. Spring boot集成mongodb

    文章目录 准备数据库 切换/创建数据库 创建一个集合(table) 得到指定名称的集合(table ) 插入 准备环境 一.基于MongoTemplate 开发CRUD 添加.查询所有 其他查询 修改 ...

  5. 从零搭建开发脚手架 Spring Boot集成Mybatis-plus之一

    文章目录 简介 特性 框架结构 依赖集成 依赖 配置 编码 开始使用 核心功能 代码生成器 添加依赖 编码 编写配置 自定义模板引擎 自定义代码模板 自定义属性注入 字段其他信息查询注入 实战总结 常 ...

  6. 《Spring Boot极简教程》第8章 Spring Boot集成Groovy,Grails开发

    第8章 Spring Boot集成Groovy,Grails开发 本章介绍Spring Boot集成Groovy,Grails开发.我们将开发一个极简版的pms(项目管理系统). Groovy和Gra ...

  7. Spring Boot集成Swagger导入YApi@无界编程

    接口APi开发现状 现在开发接口都要在类似YApi上写文档,这样方便不同的团队之间协作,同步更新接口,提高效率. 但是如果接口很多,你一个个手工在YApi去录入无疑效率很低. 如果是使用Spring ...

  8. Spring Boot集成Hazelcast实现集群与分布式内存缓存

    2019独角兽企业重金招聘Python工程师标准>>> Hazelcast是Hazelcast公司开源的一款分布式内存数据库产品,提供弹性可扩展.高性能的分布式内存计算.并通过提供诸 ...

  9. Spring Boot 集成 Swagger 生成 RESTful API 文档

    原文链接: Spring Boot 集成 Swagger 生成 RESTful API 文档 简介 Swagger 官网是这么描述它的:The Best APIs are Built with Swa ...

最新文章

  1. idea中项目失去svn控制
  2. 微信小程序模板消息(服务通知消息)原始post工具封装(不使用jar包--坑比较多),解决47001(JSON格式)和中文乱码问题
  3. PHP下的浮点运算不准的解决办法
  4. 实用ISA Server 2006之一: 简介
  5. Python 十六进制转Base64_python基础day03笔记
  6. python 项目自动生成requirements.txt文件
  7. 关于Eclipse中复制粘贴一个项目后的操作
  8. linux命令学习记录一
  9. MySQL数据库的数据类型decimal详解
  10. 优达学城深度学习之五——卷积神经网络
  11. printf 函数实现的深入剖析
  12. 论坛中的验证码的作用
  13. Docker入门之常用命令
  14. 本地组策略编辑器计算机配置,如何打开本地组策略编辑器_打开组策略编辑器方法-win7之家...
  15. SPI协议(一):读SPI_Flash(M25P16)设备ID
  16. 戴尔linux系统改win7,戴尔一体机win10改win7系统及bios设置教程(支持8代cpu)
  17. C#MessageBox 自动关闭窗口
  18. 志愿者招募| WasmEdge 邀你参加第七届中国开源年会 COSCon 2022
  19. 用CSS3制作一个风车
  20. 锤子科技 锤子便签APP产品使用用户体验报告

热门文章

  1. IP地址的三种表示格式及在Socket编程中的应用
  2. Vue混入mixins
  3. 具有absolute、relative、fixed的div设置宽度和高度的效果
  4. 我们在开源项目中是怎样埋彩蛋的
  5. 创建并运行HelloWorld Java项目和类
  6. 外媒:英特尔移动业务正分崩离析,收购联发科或能自救
  7. weblogic管理1——创建 和 删除一个domain
  8. redmine3.3.1安装与常用插件安装
  9. 1.7-bzip2和bunzip2
  10. ubuntu下man帮助文档不全怎么办?如何解决?