手把手教你使用 Spring Boot 3 开发上线一个前后端分离的生产级系统(一)-介绍

项目简介

novel 是一套基于时下 最新 Java 技术栈 Spring Boot 3 + Vue 3 开发的前后端分离 学习型开源项目,配备详细的项目开发文档手把手教你 从零开始开发上线一个生产级别的 Java 系统,由小说门户系统、作家后台管理系统、平台后台管理系统等多个子系统构成。包括小说推荐、作品检索、小说排行榜、小说阅读、小说评论、会员中心、作家专区、充值订阅、新闻发布等功能。

项目地址

开发环境

  • MySQL 8.0
  • Redis 7.0
  • Elasticsearch 8.2.0(可选)
  • RabbitMQ 3.10.2(可选)
  • XXL-JOB 2.3.1(可选)
  • JDK 17
  • Maven 3.8
  • IntelliJ IDEA 2021.3(可选)
  • Node 16.14

注:Elasticsearch、RabbitMQ 和 XXL-JOB 默认关闭,可通过 application.yml 配置文件中相应的 enable 配置属性开启。

后端技术选型

技术 版本 说明 Spring Boot 3.0.0 容器 + MVC 框架 Mybatis 3.5.9 ORM 框架 MyBatis-Plus 3.5.1 Mybatis 增强工具 JJWT 0.11.5 JWT 登录支持 Lombok 1.18.24 简化对象封装工具 Caffeine 3.1.0 本地缓存支持 Redis 7.0 分布式缓存支持 MySQL 8.0 数据库服务 ShardingSphere-JDBC 5.1.1 数据库分库分表支持 Elasticsearch 8.2.0 搜索引擎服务 RabbitMQ 3.10.2 开源消息中间件 XXL-JOB 2.3.1 分布式任务调度平台 Sentinel 1.8.4 流量控制组件 Undertow 2.2.17.Final Java 开发的高性能 Web 服务器 Docker – 应用容器引擎 Jenkins – 自动化部署工具 Sonarqube – 代码质量控制

注:更多热门新技术待集成。

前端技术选型

技术 版本 说明 Vue.js 3.2.13 渐进式 JavaScript 框架 Vue Router 4.0.15 Vue.js 的官方路由 axios 0.27.2 基于 promise 的网络请求库 element-plus 2.2.0 基于 Vue 3,面向设计师和开发者的组件库

示例代码

代码严格遵守阿里编码规约。

/**
 * 小说搜索
 */
@Override
public RestResp> searchBooks(BookSearchReqDto condition) {

    SearchResponse response = esClient.search(s -> {

        // 搜索构建器
                SearchRequest.Builder searchBuilder = s.index(EsConsts.BookIndex.INDEX_NAME);
                // 构建搜索条件
                buildSearchCondition(condition, searchBuilder);
                // 排序
                if (!StringUtils.isBlank(condition.getSort())) {
                    searchBuilder.sort(o ->
                            o.field(f -> f.field(condition.getSort()).order(SortOrder.Desc))
                    );
                }
                // 分页
                searchBuilder.from((condition.getPageNum() - 1) * condition.getPageSize())
                        .size(condition.getPageSize());

                return searchBuilder;
            },
            EsBookDto.class
    );

    TotalHits total = response.hits().total();

    List list = new ArrayList<>();
    List> hits = response.hits().hits();
    for (Hit hit : hits) {
        EsBookDto book = hit.source();
        list.add(BookInfoRespDto.builder()
                .id(book.getId())
                .bookName(book.getBookName())
                .categoryId(book.getCategoryId())
                .categoryName(book.getCategoryName())
                .authorId(book.getAuthorId())
                .authorName(book.getAuthorName())
                .wordCount(book.getWordCount())
                .lastChapterName(book.getLastChapterName())
                .build());
    }
    return RestResp.ok(PageRespDto.of(condition.getPageNum(), condition.getPageSize(), total.value(), list));

}

/**
 * 构建搜索条件
 */
private void buildSearchCondition(BookSearchReqDto condition, SearchRequest.Builder searchBuilder) {

    BoolQuery boolQuery = BoolQuery.of(b -> {

        if (!StringUtils.isBlank(condition.getKeyword())) {
            // 关键词匹配
            b.must((q -> q.multiMatch(t -> t
                    .fields(EsConsts.BookIndex.FIELD_BOOK_NAME + "^2",
                            EsConsts.BookIndex.FIELD_AUTHOR_NAME + "^1.8",
                            EsConsts.BookIndex.FIELD_BOOK_DESC + "^0.1")
                    .query(condition.getKeyword())
            )
            ));
        }

        if (Objects.nonNull(condition.getWorkDirection())) {
            // 精确查询
            b.must(TermQuery.of(m -> m
                    .field(EsConsts.BookIndex.FIELD_WORK_DIRECTION)
                    .value(condition.getWorkDirection())
            )._toQuery());
        }

        if (Objects.nonNull(condition.getCategoryId())) {
            b.must(TermQuery.of(m -> m
                    .field(EsConsts.BookIndex.FIELD_CATEGORY_ID)
                    .value(condition.getCategoryId())
            )._toQuery());
        }

        if (Objects.nonNull(condition.getWordCountMin())) {
            // 范围查询
            b.must(RangeQuery.of(m -> m
                    .field(EsConsts.BookIndex.FIELD_WORD_COUNT)
                    .gte(JsonData.of(condition.getWordCountMin()))
            )._toQuery());
        }

        if (Objects.nonNull(condition.getWordCountMax())) {
            b.must(RangeQuery.of(m -> m
                    .field(EsConsts.BookIndex.FIELD_WORD_COUNT)
                    .lt(JsonData.of(condition.getWordCountMax()))
            )._toQuery());
        }

        if (Objects.nonNull(condition.getUpdateTimeMin())) {
            b.must(RangeQuery.of(m -> m
                    .field(EsConsts.BookIndex.FIELD_LAST_CHAPTER_UPDATE_TIME)
                    .gte(JsonData.of(condition.getUpdateTimeMin().getTime()))
            )._toQuery());
        }

        return b;

    });

    searchBuilder.query(q -> q.bool(boolQuery));

}

Original: https://www.cnblogs.com/xxyopen/p/16320113.html
Author: xxyopen
Title: 手把手教你使用 Spring Boot 3 开发上线一个前后端分离的生产级系统(一)-介绍

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/588387/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • IDEA Error:java: 无效的源发行版: 11错误

    IDEA Error:java: 无效的源发行版: 11错误 今天在网上下载了一个项目到本地运行报错 Error: Java : 无效的源发行版: 11 ,上网查了很多找到问题所在…

    Java 2023年6月5日
    0106
  • bean标签使用

    Java代码 ​ bean标签中添加scope属性,设置bean对应对象生成规则. 2.1 scope = “singleton” ​ 单例,默认值,适用于…

    Java 2023年6月13日
    069
  • [学习笔记] Java变量和常量

    根据变量指代的数据类型的不同, Java中的变量分为基本类型变量和引用类型变量。变量必须先声明后使用。声明格式: type为数据类型,identifier为变量名。若要同时声明多个…

    Java 2023年6月5日
    066
  • 记一次SQL优化

    昨天(2022-7-22)上线了我的一个功能,测试环境数据量较小,问题不大,但是上生产之后,直接卡死了,然后就开始了这么一次SQL优化,这里记录一下。 不太方便透露公司的表结构,这…

    Java 2023年6月5日
    064
  • spring boot打包成war包的页面该放到哪里?

    背景 经常有朋友问我,平时都是使用spring mvc,打包成war包发布到tomcat上,如何快速到切换到spring boot的war或者jar包上? 先来看看传统的war包样…

    Java 2023年5月30日
    078
  • 【MyBatis】几种批量插入效率的比较

    批处理数据主要有三种方式: 基于 Spring Boot + Mysql,同时为了省略 get/ set,使用了 lombok,详见 pom.xml。 id 使用数据库自增。 DR…

    Java 2023年6月5日
    093
  • 23 种设计模式的通俗解释,虽然有点污,但是很正点

    01 工厂方法 追 MM 少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是 MM 爱吃的东西,虽然口味有所不同,但不管你带 MM 去麦当劳或肯德基,只管向服务员说「来四个鸡翅」就行了…

    Java 2023年6月13日
    064
  • 分布式基础- 拜占庭将军问题

    一 背景 拜占庭将军问题是如何通过通讯方式来达成共识得问题,Leslie Lamport 来借助这个问题说明如何在分布式环境下达成共识。 拜占庭将军问题是这样的:拜占庭帝国的军队在…

    Java 2023年5月30日
    091
  • System.out.printf使用以及注意点

    一、System.out.printf格式化输出 1、常用控制符 控制符 说明 %d 按十进制整型数据的实际长度输出。 %ld 输出长整型数据。 %md m 为指定的输出字段的宽度…

    Java 2023年6月5日
    086
  • SpringBoot中整合knife4j接口文档

    界面欣赏 1.首页 2.接口文档 3.调试 二、整合 knife4j 1、引入 maven 依赖 com.github.xiaoymin knife4j-spring-boot-s…

    Java 2023年6月6日
    067
  • Java基础常识

    1.eclipse Run as application 快捷键 2.关于半角和全角 1.eclipse Run as application 快捷键 记得刚学时两个手并用按住了A…

    Java 2023年5月29日
    080
  • 面试官:说说对称加密、非对称加密、混合加密?懵了。。

    来源:liuchenyang0515.blog.csdn.net/article/details/109263510 对称加密 两边用同一个密钥来加解密。 A把明文通过某一算法加密…

    Java 2023年6月15日
    080
  • TreeMap源码分析

    TreeMap源码分析 数据结构 TreeMap使用红黑树来存储数据,红黑树是一种平衡二叉查找树,它是一种高效的搜索算法,它的算法时间复杂度是O(lgn) 增删改查 增改 publ…

    Java 2023年6月16日
    083
  • 启用Hyper-v后,重启后界面提示 无法完成功能配置,正在撤销更改

    安装docker后,提示需要启用hyper-v,在控制面板中勾选Hyper-v,然后重启,更新快完成就提示无法完成功能配置,正在撤销更改 解决方法 方法1 控制面板一个一个选 方法…

    Java 2023年6月16日
    0109
  • MySQL九:MVCC能否解决幻读问题

    转载~ 幻读【前后多次读取,数据总量不一致】 同一个事务里面连续执行两次同样的sql语句,可能导致不同结果的问题,第二次sql语句可能会返回之前不存在的行。 事务A执行多次读取操作…

    Java 2023年6月8日
    0101
  • 《Apache RocketMQ 深入浅出》系列文章

    Apache RocketMQ是一个纯Java、分布式、队列模型的开源消息中间件,前身是MetaQ,是阿里参考Kafka特点研发的一个队列模型的消息中间件,后开源给apache基金…

    Java 2023年5月29日
    080
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球