SpringBoot聚合项目:达内知道(六)-学生发布问题(复用显示标签、富文本编辑器、多选列表、接收表单数据、新增数据库操作)
1.学生发布问题
问答流程介绍:
学生提问功能流程:
1.1 复用显示标签
我们看到问题发布页也显示所有标签信息,如果再次实现这个功能,会造成代码冗余。我们可以使用Vue模板来复用这个效果,减少冗余。
Vue模板的使用大概分为3个步骤:
-
定义模板
-
调用模板
-
添加引用
定义模板:在js文件夹中创建tags_nav_temp.js文件代码如下:
/*定义Vue模板,名称为tags-app*/
Vue.component("tags-app",{
"props":["tags"],
"template":`
<div class="nav font-weight-light"><!--删除id,否则报错-->
<a href="tag/tag_question.html" class="nav-item nav-link text-info"><small>全部</small></a>
<a href="tag/tag_question.html"
class="nav-item nav-link text-info"
v-for="tag in tags">
<small v-text="tag.name">Java基础</small></a><!--绑定内容-->
</div>
`
})
调用模板:在需要显示模板中信息的位置编写代码,如在create.html页面186行附近添加代码如下:
<!--引入标签的导航栏-->
<div class="container-fluid" >
<!-- 调用模板 -->
<!-- tags-app 是模板的名称
id="tagsApp" 是Vue绑定的id
:tags对应模板代码中props:["tags"]
="tags" 对应的是Vue代码中的data中的tags
-->
<tags-app id="tagsApp" :tags="tags"></tags-app>
</div>
添加引用:首页create.html页面的head标签结束前添加axios的引用
<!--引入axios框架-->
<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.21.1/axios.min.js">
</script>
页面末尾添加引用:
</body>
<script src="../js/utils.js"></script><!--..表示返回上一级路径-->
<script src="../js/tags_nav_temp.js"></script><!--必须先添加模板,后加运行的内容-->
<script src="../js/tags_nav.js"></script>
</html>
然后重启服务,就可以看到页面上模板复用的标签列表了。
1.2 富文本编辑器
我们使用的富文本编辑器是summernote。
它的使用很简单,但是功能强大,官方给出的必要依赖如下:
<link rel="stylesheet" href="../bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="../bower_components/font-awesome/css/font-awesome.min.css">
<link rel="stylesheet" href="../bower_components/summernote/dist/summernote-bs4.min.css">
<script src="../bower_components/jquery/dist/jquery.min.js"></script>
<script src="../bower_components/popper.js/dist/umd/popper.min.js"></script>
<script src="../bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="../bower_components/polyfill/dist/polyfill.min.js"></script>
<script src="../bower_components/summernote/dist/summernote-bs4.js"></script>
<script src="../bower_components/summernote/dist/lang/summernote-zh-CN.min.js"></script>
它支持我们添加各种常见的样式,甚至支持图片和视频的插入功能,它是怎么启动的呢?一般会定义一个<textarea>,在这个标签中定义id,然后使用summernote规定的固定代码启动。
$(document).ready(function() {
$('#summernote').summernote({
height: 300,
tabsize: 2,
lang: 'zh-CN',
placeholder: '请输入问题的详细描述...'
});
});
页面效果:
1.3 多选列表
相对于单选的下拉框和复选框,多选列表的用户体验更好,方便用户选择和查看选择结果。我们使用Vue官方提供的一个模板插件来实现多选列表的功能:vue-select(v-select)。
使用该插件要添加必要依赖(前端页面已经配置好):
<link rel="stylesheet" href="../bower_components/vue-select/dist/vue-select.css">
<script src="../bower_components/vue/dist/vue.js"></script>
<script src="../bower_components/vue-select/dist/vue-select.js"></script>
绑定多选列表数据:create.html的203行附近有一个div需要添加id,一定要加,否则出不来多选列表框
<div class="col-8" id="createQuestionApp"><!--添加id-->
create.html的213行附近开始,需要绑定多选列表,代码如下:
<div class="form-group">
<label >请至少选择一个标签:</label>
<!-- multiple支持多选 required必须选
:options为模板中需要的数据赋值,这里是绑定所有选项
tags是数据库中所有标签
selectedTags是用户选择的所有标签
-->
<v-select multiple required :options="tags"
v-model="selectedTags" placeholder="请选择问题相关标签">
</v-select>
</div>
<div class="form-group">
<label >请选择老师:</label>
<!--下面同上-->
<v-select multiple required :options="teachers"
v-model="selectedTeachers" placeholder="请选择回答老师">
</v-select>
</div>
js代码已经准备好,页面尾部添加引用:
</body>
<script src="../js/utils.js"></script><!--..表示返回上一级路径-->
<script src="../js/tags_nav_temp.js"></script><!--必须先添加模板,后加运行的内容-->
<script src="../js/tags_nav.js"></script>
<!-- ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
<script src="../js/createQuestion.js"></script><!--一定要添加,否则没有多选列表-->
</html>
编写绑定所有讲师的代码:从业务逻辑层开始,先在接口IUserService中添加方法:
//查询所有讲师的方法
List<User> getTeachers();
再在实现类UserServiceImpl编写实现代码如下:
控制层UserController添加代码如下,注意之前的两个测试方法可以删除:
package cn.tedu.knows.portal.controller;
import cn.tedu.knows.portal.model.User;
import cn.tedu.knows.portal.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* <p>
* 前端控制器
* </p>
*
* @author tedu.cn
* @since 2021-08-23
*/
最终效果:
讲师业务逻辑层添加list和map的缓存:
在IUserService接口添加方法:
//查询所有讲师的Map
Map<String,User> getTeacherMap();
修改UserServiceImpl实现类最终代码如下:
//创建缓存对象
private List<User> teachers=new CopyOnWriteArrayList<>();//线程安全,存对象
private Map<String,User> teacherMap=new ConcurrentHashMap<>();//线程安全,存名称和对象
//查询所有讲师
最终效果:
1.4 接收表单数据
上次课我们已经完成了表单提交的准备工作,例如:显示所有标签和显示所有讲师。下面我们为了能够接收表单数据,在vo包,定义个QuestionVo类,这个类中的成员变量对应表单中的每个输入框(createQuestion.js),代码如下:
package cn.tedu.knows.portal.vo;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.io.Serializable;
在控制层QuestionController类中编写代码接收表单数据,代码如下:
//用户提问的控制层方法
//路径是localhost:8080/v1/questions
在create.html页面进行页面绑定:206行附近的form标签
<form @submit.prevent="createQuestion" ><!--阻止表单原有效果提交-->
重新启动服务,编写表单数据提交,到Idea控制台上观察接收到的数据是否全面/正确。
(1)浏览器
(2)控制台
1.5 新增问题的数据库操作
新增问题后涉及到的表:
新增问题的业务流程如下:
1.控制器接收用户提交的表单(已完成)
2.控制器调用业务逻辑层方法完成新增
3.业务逻辑层方法中先增问题,再增问题和标签关系、问题和讲师的关系
需要注意的是,一个问题和多个标签、讲师都有关系,所以可能需要用到循环新增
4.业务逻辑层调用数据访问层完成相关操作,最后返回结果
1.5.1 编写新增问题的业务逻辑层
先编写业务逻辑层接口IQuestionService,添加方法如下:
// 新增发布问题的业务逻辑层方法
void saveQuestion(QuestionVo questionVo,String username);
在QuestionServiceImpl实现类中实现方法如下: