springboot实战之课程推荐系统
最近在二次开发一个springboot小项目,在已有的功能基础上新增功能,其中涉及前端到后端,体会到了全栈工程师的辛苦.
【系统介绍】
本系统基于amaze ui前端框架开发的springboot项目,用于评价,展示,编辑课程,学生,教师等信息.
【课程评价功能】
1.需求分析
在课程管理下新增一个菜单“课程评价”,点击课程评价后是一个课程问卷,课程问卷答案用A,B,C等等来标识,最后有一个提交按钮,用户点击提交,把问卷答案存到数据库
问卷的最上面有一个下拉选项,用来选择评价哪门课程
2.系统设计
选择课程的下拉选项从课程表中取数。学生id从当前登录用户中取id字段,session中有用户信息。
问卷编号和问题编号自己编.
一个学生针对一门课程,填完问卷是10条记录。
和本功能有关的数据库表名:
1.course表,课程信息表
- 实体属性图
- 数据表信息:
表名 |
course(课程信息) |
|||||
主键 |
id 唯一标识 |
|||||
其他排序字段 |
N/A |
|||||
序号 |
字段名称 |
类型 |
长度 |
主外键 |
为空? |
约束条件/说明 |
1 |
id |
Varchar |
50 |
Y |
N |
唯一标识 |
2 |
name |
Varchar |
255 |
N |
N |
课程名称 |
3 |
credit |
Integer |
|
N |
Y |
课程学分 |
4 |
description |
Text |
|
N |
Y |
课程简介 |
5 |
image |
Varchar |
255 |
N |
N |
课程图片路径 |
6 |
createdate |
DateTime |
|
N |
N |
创建时间(默认记录插入时间) |
2.kcpj表,课程评价信息
- 实体属性图
- 数据表信息:
表名 |
kcpj(课程评价信息) |
|||||
主键 |
id 唯一标识 |
|||||
其他排序字段 |
N/A |
|||||
序号 |
字段名称 |
类型 |
长度 |
主外键 |
为空? |
约束条件/说明 |
1 |
id |
Varchar |
50 |
Y |
N |
唯一标识 |
2 |
cid |
Varchar |
50 |
Y |
N |
所属课程ID |
3 |
studentid |
Varchar |
50 |
Y |
N |
学生ID |
4 |
wjbh |
Varchar |
50 |
N |
N |
问卷编号 |
5 |
wtbh |
Varchar |
50 |
N |
N |
问题编号 |
6 |
result |
Varchar |
50 |
N |
N |
评价结果 |
7 |
createdate |
DateTime |
|
N |
N |
创建时间(默认记录插入时间) |
数据库表采用的是弱关联,不用外键约束,从业务上来控制数据的一致性。
如果是强关联,虽然数据比较规范,统一,但是也麻烦.
3.编码阶段
首先左侧的ftl文件中,在课程管理下新增1个菜单项
<ul class="tpl-left-nav-sub-menu">
<li>
<a href="#" id="open-estimate-list">
<i class="am-icon-angle-right"></i>
<span>课程评价</span>
</a>
</li>
</ul>
添加点击事件,首先去控制层获取课程对象列表,返回到课程评价对象,填充到课程选择下拉框
$(function () {
//从center.js移植过来的jq对象
var open_content = $("#open-content");//中心内容
//课程评价按钮绑定事件
$(document).on('click', '#open-estimate-list', function () {
$.ajax({
url: "/estimate/list",
success: function (data) {
//返回的data是视图模型对象,指定了视图和模型
//把中心内容清空,填充数据和模型对象
open_content.empty().html(data);
},
error: function () {
console.log("加载课程评价出问题了!");
}
});
});
})
控制层:
插入一条概念:restcontroller注解和controller注解的区别
@Controller注解
在对应的方法上,视图解析器可以解析return 的jsp,html页面,并且跳转到相应页面
若返回json等内容到页面,则需要加@ResponseBody注解
@RestController注解
相当于@Controller+@ResponseBody两个注解的结合,返回json数据不需要在方法前面加@ResponseBody注解了,但使用@RestController这个注解,就不能返回jsp,html页面,视图解析器无法解析jsp,html页面
list方法:
用于获取课程对象,课程对象是list<Map>类型,mybatis的映射配置文件里是这么配置的,相比直接获取pojo类,如果出现了数据库表字段修改的情况,那么不需要去改java代码,只需要修改xml映射文件即可.
注意:这里返回的是视图模型对象(ajax接收)
@RestController
@EnableAutoConfiguration
@RequestMapping(value = "/estimate")
public class EstimateController {
@Autowired
private EstimateService estimateService;
/**显示课程列表
* @param modelAndView
* @return
*/
@RequestMapping(value = "/list")
public ModelAndView list(ModelAndView modelAndView) {
System.out.println("进了getsectionList");
List<Map> resultList = new ArrayList<>();
try {
resultList = estimateService.selectAllCourse();
System.out.println("显示所有的课程");
System.out.println(resultList.toString());
} catch (Exception e) {
e.printStackTrace();
}
modelAndView.addObject("sectionList", resultList);
modelAndView.setViewName("estimate");
return modelAndView;
}
estimatemapper.xml(查询课程信息部分)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.ebpm.mapper.EstimateMapper">
<!-- map映射,映射实体类和数据表字段 -->
<!-- 课程信息表-->
<resultMap id="BaseResultMap_Course" type="com.ebpm.model.Course">
<id column="id" property="id" jdbcType="VARCHAR"/>
<id column="name" property="name" jdbcType="VARCHAR"/>
<result column="credit" property="credit" jdbcType="VARCHAR"/>
<result column="description" property="description" jdbcType="VARCHAR"/>
<result column="image" property="image" jdbcType="VARCHAR"/>
<result column="createdate" property="createdate" jdbcType="DATE"/>
</resultMap>
<!-- sql片段复用 -->
<sql id="Course_Column_List">
id,name,credit,image,description,createdate
</sql>
<!-- 查询课程列表 -->
<!-- 返回是多个map-->
<select id="selectAllCourse" resultMap="BaseResultMap_Course">
select
<include refid="Course_Column_List"/>
from course
order by createdate desc
</select>
</mapper>
控制层返回模型视图对象,直接填充在中心内容上,
视图对象:estimate.ftl
(题目只展示部分)
<div class="tpl-content-page-title">
课程评价
</div>
<ol class="am-breadcrumb">
<li><a href="/center/index" class="am-icon-home">首页</a></li>
<li><a href="#" onclick="$('#open-course-list').click()"">课程管理</a></li>
<li class="am-active">课程评价</li>
</ol>
<div class="tpl-portlet-components">
<div class="tpl-block ">
<div class="am-g tpl-amazeui-form">
<form class="am-form am-form-horizontal filter" id="sectionForm">
<div class="forestimate">
<h1>学生课程满意度调查问卷</h1></div>
<p class="am-serif">同学您好: 本问卷的目的在于了解同学们对此门课程的教学建议,以更好地满足同学们的学习需求。请您认真填好以下问卷,您真实的回答将为我们的课程建设提供宝贵的信息。我们将对所填内容保密,请您放心填写!
谢谢您对我们工作的支持与配合!</p>
<hr/>
<div class="am-form-group">
<label for="user-major" class="am-u-sm-3 am-form-label">请选择你的专业:</label>
<div class="am-u-sm-9">
<!-- 下拉框填充 -->
<select id="cid">
<#list sectionList as course>
<option value="${course.id}">${course.name}</option>
</#list>
</select>
</div>
</div>
<div class="am-form-group">
<label for="user-no" class="am-u-sm-3 am-form-label">Q1:</label>
<div class="am-u-sm-9">
<label> 本课程有学习目标与考核要求的详细介绍。</label>
</div>
</div>
<div class="am-form-group">
<label for="user-sex" class="am-form-label am-u-sm-3 ">选项:</label>
<div class="am-u-sm-9">
<label class="am-radio-inline">
<input type="radio" value="A" name="NO1"> A.同意
</label>
<label class="am-radio-inline">
<input type="radio" value="B" name="NO1">B.基本同意
</label>
<label class="am-radio-inline">
<input type="radio" value="C" name="NO1">C.不同意
</label>
</div>
</div>
</form>
<div class="forestimate">
<input type="button" id="submit_estimate" value="提交" class="am-btn am-btn-primary am-radius"/>
</div>
</div>
</div>
</div>
问卷页面已经生成,可以开始做问卷了
做完问卷,点击提交按钮,触发点击事件
ajax方法:
//提交评价按钮绑定事件
$(document).on('click', '#submit_estimate', function () {
//获取表单的参数,并转化成json字符串
var para = $('#sectionForm').serializeObject();
//获取课程id
var cid = $('#cid').val();
var estimateArray = [];
//i就是name属性,题号
for (var i in para) {
//每一个题目就是一个estimate对象,循环创建对象放到数组里
var estimate = {};
//课程id
estimate.cid = cid;
//问题编号,这里的i就是name
estimate.wtbh = i;
//填写的答案,value属性
estimate.result = para[i];
//把对象放到数组里
estimateArray.push(estimate);
}
//判断数组长度,也就是单选按钮选中的数量
if (estimateArray.length < 10) {
alert("还有题目没做呢!");
return false;
}
//把对象数组变成字符串
para = JSON.stringify(estimateArray);
console.log(JSON.stringify(estimateArray));
$.ajax({
url: "/estimate/add",
data: para,
//发送方式,这里用了post那么控制层那边就不能用请求对象拿了
type: 'POST',
//发送的数据类型
contentType: 'application/json; charset=UTF-8',
//返回的数据类型
dataType: 'json',
success: function (data) {
if (data.success == 'success') {
alert(data.msg);
//提交成功后跳转到课程列表
$('#open-course-list').click();
}
},
error: function () {
alert("提交课程评价失败!");
// console.log("提交课程评价失败!");
}
});
controller
发送请求到服务器,控制层的接收方式如下
/**
* 插入课程评价
*
* @param estimateList
* @param session
* @return
*/
@RequestMapping(value = "/add", method = {RequestMethod.POST}, produces = {"application/json;charset=UTF-8"})
@ResponseBody()
//方法的参数这里采用的@RequestBody注解获取问卷list,session用于获取用户id
//至于类注解@restcontroller为什么不生效,还是得加 @ResponseBody(),我也不知道
public Object add(@RequestBody List<Estimate> estimateList, HttpSession session) {
User user = (User) session.getAttribute("user");
if (user == null || user.getId() == null) {
return null;
}
for (Estimate estimate : estimateList) {
estimate.setStudentid(user.getId());
// 问卷编号暂时写死
estimate.setWjbh("1");
System.out.println(estimate);
}
//定义插入的数据数量
int result = 0;
try {
result = estimateService.insert(estimateList);
} catch (Exception e) {
e.printStackTrace();
}
if (result > 0)
return "{\"msg\":\"评价信息提交成功\",\"success\":\"success\"}";
else
return null;
}
业务逻辑层没有复杂逻辑,直接调dao接口插入数据
estimatemapper.xml文件
批量插入数据
<sql id="Estimate_Column_List">
id,cid,studentid,wjbh,wtbh,result
</sql>
<insert id="insertEstimate" parameterType="java.util.List">
insert into
kcpj (
<include refid="Estimate_Column_List"/>
)
values
<foreach item="estimate" collection="list" separator=",">
(UUID(),#{estimate.cid,jdbcType=VARCHAR},#{estimate.studentid,jdbcType=VARCHAR}
,#{estimate.wjbh,jdbcType=VARCHAR},#{estimate.wtbh,jdbcType=VARCHAR}
,#{estimate.result,jdbcType=VARCHAR})
</foreach>
</insert>