1.老师角色的功能包括课程管理、课件管理和学生管理。课件管理和学生管理都是以课程为基础。需要创建三个数据表以及对应的类,来完成上面功能。
2.在进行后端设计之前,我习惯lombok和mybatis-plus结合实现后端开发。所以先安装lombok依赖。
注意:以后进行开发时,如果我不说明具体哪个模块,前端的根路径默认是ruoyi-ui,后端的根路径默认是ruoyi-admin/src/main。
3.根据若依官网的mybatis-plus插件集成文档,导入mybatis-puls插件。打开ruoyi-common/pom.xml文件,添加mybatis-plus,lombok和hutool工具的依赖。hutool工具如何使用可以查看hutool官网。
<!-- mybatis-plus 增强CRUD -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- Hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
4.点击右上角maven重新加载按钮,等待依赖下载完成。
5.打开后端(ruoyi-admin/src/main,仅第一次使用提醒,以后不提醒了)resources/application.yml文件,将mybatis配置注释掉,为了避免出现错误先不要删除。
6.在此文件中加入mybatis-plus的配置。
7.打开ruoyi-framework/config/MyBatisConfig.java文件,将@Configuration注解注释掉(将配置失效,暂时先不删除此文件,避免报错)。
8.在MyBatisConfig同级下(ruoyi-framework/config文件夹下)创建MybatisPlusConfig类,添加一下配置。可以全选后,用以下配置替换。
package com.ruoyi.framework.config;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.BlockAttackInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Mybatis Plus 配置
*
* @author ruoyi
*/
@EnableTransactionManagement(proxyTargetClass = true)
@Configuration
public class MybatisPlusConfig
{
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor()
{
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(paginationInnerInterceptor());
// 乐观锁插件
interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor());
// 阻断插件
interceptor.addInnerInterceptor(blockAttackInnerInterceptor());
return interceptor;
}
/**
* 分页插件,自动识别数据库类型 https://baomidou.com/guide/interceptor-pagination.html
*/
public PaginationInnerInterceptor paginationInnerInterceptor()
{
PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor();
// 设置数据库类型为mysql
paginationInnerInterceptor.setDbType(DbType.MYSQL);
// 设置最大单页限制数量,默认 500 条,-1 不受限制
paginationInnerInterceptor.setMaxLimit(-1L);
return paginationInnerInterceptor;
}
/**
* 乐观锁插件 https://baomidou.com/guide/interceptor-optimistic-locker.html
*/
public OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor()
{
return new OptimisticLockerInnerInterceptor();
}
/**
* 如果是对全表的删除或更新操作,就会终止该操作 https://baomidou.com/guide/interceptor-block-attack.html
*/
public BlockAttackInnerInterceptor blockAttackInnerInterceptor()
{
return new BlockAttackInnerInterceptor();
}
}
9.重新启动后端,由于使用了lombok,右下角的提示,请选择Enable annotation processing(第一次使用lombok启动会有此提示)。如果成功启动,可以将resources/application.yml文件夹注释掉的mybatis配置内容和ruoyi-framework/config/MyBatisConfig.java文件删除。当然也可以选择不删除,这里我就删除了。如果选择和我一样进行删除,为了安全起见,可以再次重新启动后端,还是没有报错的。
提示:通过截图发现,我新建的MybatisPlusConfig.java是红色,这并不是错误。产生这种情况的原因是,我们通过git拉取了若依框架,当我们在IDEA中创建新文件时,会提示是否Add进git中,我选了不Add,并且让他不再提示才出现这种情况。如果选择add,会是绿色。也可以发现有的文件变成了蓝色,这是因为我们改变了里面的内容。这些颜色只是IDEA对git管理的显示,并不影响我们的使用,我们代码问题一定要根据控制台获取而不是单纯文件的颜色。
10.在进行后面操作之前,我们先打开数据库,查看sys_user,sys_role,sys_dept等多个表,会发现这几个表中有共同的列del_flag,create_by,create_time,update_by和update_time。通过具体信息查看这个五个列明的作用,以及我们创建表时可以学习的地方。
总结:
1.通过表可以看到每个列的作用,无论是通过列名的中文翻译还是最后面的注释,都可以知道作用。列名能够简单明了的体现作用,注释是对列名翻译和补充。我们在创建表时,也要按照这个要求来,能够为以后的维护节省大量时间。
2.这五个列作用很大。del_flag用于表示数据的逻辑删除,一些重要数据一般使用逻辑删除的方式。当然,也不是所有数据都采用逻辑删除的方式,要灵活使用,比如sys_user_role等表。其余四个列作用也非常重要,能够清除记录数据是由谁创建或修改,哪个时间创建,能够有迹可循。
11.由于第一次使用mybatis-plus结合若依框架开发,我会说明从数据库表,到实体类,再到mapper,然后到服务层,最后到controller层创建的全过程。通过数据库表名可以发现,数据库表名的前缀也有一定意义的。由于后面都是个人开发,我会使用py(飘逸简写)作为前缀,具体应用时根据实际情况使用,比如公司简称等等。
12.由于每一次都会使用这5个列,为了简化开发。我们可以先导出一个表,然后将没用的信息去掉,留下共用信息,每次创建时,只需要改下数据库名和表名就可以导入执行,然后再创建不同的列。以SQLYog为例,在sys_role表上右键,选择“备份/导出”,再选择“备份表作为SQL转储”,然后选择位置,并输入名字。最后,点击导出,等待完成后,点击完成。
13.找到保存位置,然后打开,去掉无用信息,并修改部分信息。
USE `数据库名`;
CREATE TABLE `表名` (
`id` varchar(32) NOT NULL COMMENT '主键ID',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='表备注名称';
注意:
1.第一行USE,要填需要创建表的数据库名称字符串。
2.第二行CREATE TABLE 后面要填写创建表名称的字符串。
3.最后一行的COMMENT赋值表名的中文翻译。
4.列明id是我自己填写,由于我喜欢用去掉下划线(“_”)的uuid作为id,所以创建这个列。
14.将数据库名,表名,表备注名称添加。如果不想自己删除,可以创建一个.sql文件,将下面内容赋值进入。
USE `ry_vue`;
CREATE TABLE `py_course` (
`id` varchar(32) NOT NULL COMMENT '主键ID',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='课程信息';
15.以SQLyog为例,点击菜单栏中的“工具”,然后点击“执行SQL脚本...”,选择包含上面sql语句的文件,然后点“执行”,提醒是否,选择”是“,然后点完成。最后选择ry_vue数据库,点击刷新下。
16.以SQLyog为例,选择py_course表,右键,然后选择“改变表”,然后添加对应属性。表py_course的sql如下。
USE `ry_vue`;
/*Table structure for table `py_course` */
DROP TABLE IF EXISTS `py_course`;
CREATE TABLE `py_course` (
`id` varchar(32) NOT NULL COMMENT '主键ID',
`user_id` bigint(20) DEFAULT NULL COMMENT '用户id',
`name` varchar(128) DEFAULT NULL COMMENT '课程名称',
`teacher_name` varchar(128) DEFAULT NULL COMMENT '老师姓名',
`course_class` varchar(128) DEFAULT NULL COMMENT '课程班级',
`introduce` varchar(500) DEFAULT NULL COMMENT '课程介绍',
`del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)',
`create_by` varchar(64) DEFAULT '' COMMENT '创建者',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`update_by` varchar(64) DEFAULT '' COMMENT '更新者',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='课程信息';
17.由于每次都要使用那5个列,为了减少工作量,可以创建一个类包含这个5个属性,其他类如果需要通过继承的方式获取。在java/com.ruoyi包下创建包domain,在此domain包下创建类BasePojo。@Data注解是lombok注解,其他都是mybatis-plus注解,这里就不讲解了。如果想学习,可以去mybatis-plus官网查看官方文档。
package com.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.util.Date;
@Data
public class BasePojo {
//删除标志
@TableField("del_flag")
@TableLogic(value = "0", delval = "2")
private String delFlag;
//创建者
@TableField("create_by")
private String createBy;
//创建时间
@TableField("create_time")
private Date createTime;
//更新者
@TableField("update_by")
private String updateBy;
//更新时间
@TableField("update_time")
private Date updateTime;
}
18.在java/com.ruoyi包下创建包course,在此course包下创建包domain,mapper,service,controller。在domain包下创建类PyCourse。
package com.ruoyi.course.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.ruoyi.common.annotation.Excel;
import com.ruoyi.domain.BasePojo;
import lombok.Data;
@Data
@TableName("py_course")
public class PyCourse extends BasePojo {
//主键id
@TableId(value = "id",type = IdType.ASSIGN_UUID)
@Excel(name = "课程标识")
private String id;
//用户id
@TableField("user_id")
@Excel(name = "用户标识")
private Long userId;
//课程名称
@TableField("name")
@Excel(name = "课程名称")
private String name;
//老师姓名
@TableField("teacher_name")
@Excel(name = "老师姓名")
private String teacherName;
//课程班级
@TableField("course_class")
@Excel(name = "课程班级")
private String courseClass;
//课程介绍
@TableField("introduce")
@Excel(name = "课程介绍")
private String introduce;
}
19.在mapper包下创建接口PyCourseMapper。
package com.ruoyi.course.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.course.domain.PyCourse;
public interface PyCourseMapper extends BaseMapper<PyCourse> {
}
20.在service包下创建j接口PyCourseService。
package com.ruoyi.course.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.course.domain.PyCourse;
public interface PyCourseService extends IService<PyCourse> {
}
21.在service包下创建包impl,在此impl包下创建类PyCourseServiceImpl。
package com.ruoyi.course.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.course.domain.PyCourse;
import com.ruoyi.course.mapper.PyCourseMapper;
import com.ruoyi.course.service.PyCourseService;
import org.springframework.stereotype.Service;
@Service("pyCourseService")
public class PyCourseServiceImpl extends ServiceImpl<PyCourseMapper, PyCourse> implements PyCourseService {
}
22.在controller包下创建类PyCourseController。下面是基础配置,具体写接口和springboot一样。因为使用mybatis-plus会自动生成单表操作,具体如果使用,可以查看mybatis-plus官网。
package com.ruoyi.course.controller;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.course.service.PyCourseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/py/course")
public class PyCourseController extends BaseController {
@Autowired
private PyCourseService pyCourseService;
}
23.打开ruoyi-admiin/pom.xml文件,添加springboot测试依赖。点击右上角按钮,重新下载依赖。
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
24.在ruoyi-admin/src创建文件夹test/java文件夹,用IDEA创建时,会有提示,直接选择后,按Enter就可以了。
在此java文件夹下创建包com.ruoyi.course,最后在course文件下创建类PyCourseTest。通过往课程表中添加10条记录进行测试,测试课程表基础配置是否完成。
package com.ruoyi.course;
import com.ruoyi.course.domain.PyCourse;
import com.ruoyi.course.service.PyCourseService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@SpringBootTest
public class PyCourseTest{
@Autowired
private PyCourseService pyCourseService;
@Test
public void testPyCourse() {
List<PyCourse> courseArrayList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
PyCourse pyCourse = new PyCourse();
pyCourse.setName("测试" + i);
pyCourse.setCreateBy("测试" + i);
pyCourse.setCreateTime(new Date());
courseArrayList.add(pyCourse);
}
pyCourseService.saveBatch(courseArrayList);
}
}
注意:使用IDEA创建测试文件夹下的java时,如果不能和上图一样显示绿色是不能创建类的。一定按照面的步骤进行创建。
25.点击testPyCourse方法左侧的运行按钮,运行程序。控制台没有报错,然后打开数据库ry_vue中的py_course表,发现多了10条记录。使用mybatis-puls插件对单表操作的优势体现出来了,我们根本没有写sql和方法,只是配置了mybatis-plus。具体有哪些方法,如何更好的使用,可以通过mybatis-plus官网查看。
注意:
1.运行了测试方法后,右上角快捷运行项目,已经切换到方法。为了避免下次运行忘记切换,需要切换到若依启动类。
切回若依启动类后
2.记得清空数据库ry_vue中py_course表中的数据。
26.登录管理员用户,点击“系统管理”,选择“菜单管理”,将“系统管理”、“系统监控”和“系统工具”的排序分别设置为98,99和100,保证这三个菜单在最后显示。
点击“新增”,创建目录“信息管理”。按“F5”刷新网页,发现左侧菜单栏多一个“信息管理”。
27.打开src/views下新增文件夹py,在py文件夹下新增文件夹teacher,在teacher新增文件夹course,courseware和student。在这个三个文件夹中都新增index.vue文件,并填写基本代码。
course文件夹下的index.vue
<template>
<div>
课程管理
</div>
</template>
<script>
export default {
name: 'TeacherCourse'
}
</script>
courseware文件夹下的index.vue
<template>
<div>
课件管理
</div>
</template>
<script>
export default {
name: 'TeacherCourseware'
}
</script>
student文件夹下的index.vue
<template>
<div>
学生管理
</div>
</template>
<script>
export default {
name: 'TeacherStudent'
}
</script>
28.登录管理员用户,点击“系统管理”,选择“菜单管理”,在“信息管理”下面新增“课程管理”、“课件管理”和“学生管理”。先修改信息管理的路由,改为py/teacher。
在“信息管理”下新增“课程管理”。
按“F5”刷新下,然后点击“信息管理”,选择“课程管理”,如果显示以下页面,代表配置成功。
和上面操作类似,在“信息管理”下面新增“课件管理”和“学生管理”。
29.登录管理员用户,点击“系统管理”,选择“菜单管理”,在“信息管理”下的“课程管理”点击“新增”,填写查询权限。
同样的,在“信息管理”下点击新增,填写课程新增,课程修改,课程删除和课程导出。
课程新增
课程修改
课程删除
课程导出
课程管理按钮总览
30.将课程管理按钮权限配置到老师角色。登录管理员用户,点击“系统管理”,选择“角色管理”,找到老师角色,然后点击“修改”,配置上信息管理的所有权限。
31.后面大部分内容是关于springboot和vue的,不会过多介绍,但是有关于若依框架使用特点的还会介绍。前端vue开发依赖于element-ui组件,具体组件使用可以查看Element-UI官网。由于内容太多,这里文章只会具体介绍课程管理,课件管理和学生管理会在之后的文章中出现。
32.为了更好的使用查询条件,提高编程效率,我创建了个与mybatis-plus结合的用于查询的工具类QueryWrapperUtil。后端在java/com.ruoyi包下创建包util,然后在util包下创建类QueryWrapperUtil。
package com.ruoyi.util;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.domain.BasePojo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
public class QueryWrapperUtil {
public static <T extends BasePojo> QueryWrapper<T> getWrapper(T entity) {
QueryWrapper<T> wrapper = new QueryWrapper<>();
Class<? extends BasePojo> entityClass = entity.getClass();
Field[] declaredFields = entityClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
String name = declaredField.getName();
String getName = StrUtil.upperFirstAndAddPre(name, "get");
Method method = null;
try {
method = entityClass.getMethod(getName);
Object obj = method.invoke(entity);
String column = StrUtil.toSymbolCase(name, '_');
wrapper.eq(ObjectUtil.isNotEmpty(obj), column, obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return wrapper;
}
public static <T extends BasePojo> QueryWrapper<T> getWrapper(T entity, Map<String, String> map) {
QueryWrapper<T> wrapper = new QueryWrapper<>();
Class<? extends BasePojo> entityClass = entity.getClass();
Field[] declaredFields = entityClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
String name = declaredField.getName();
String getName = StrUtil.upperFirstAndAddPre(name, "get");
Method method = null;
try {
method = entityClass.getMethod(getName);
Object obj = method.invoke(entity);
String column = StrUtil.toSymbolCase(name, '_');
String mybatisValue = map.get(name);
if (StrUtil.isNotEmpty(mybatisValue)) {
switch (mybatisValue) {
case "isNull":
wrapper.isNull(column);
break;
case "isNotNull":
wrapper.isNotNull(column);
break;
case "eq":
wrapper.eq(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "ne":
wrapper.ne(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "like":
wrapper.like(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "notLike":
wrapper.notLike(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "likeRight":
wrapper.likeRight(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "likeLeft":
wrapper.likeLeft(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "lt":
wrapper.lt(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "le":
wrapper.le(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "gt":
wrapper.gt(ObjectUtil.isNotEmpty(obj), column, obj);
break;
case "ge":
wrapper.ge(ObjectUtil.isNotEmpty(obj), column, obj);
break;
default:
break;
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return wrapper;
}
}
注意:
1.工具类使用了泛型,对任何需要查询的类都可以使用。
2.第一个方法,只传一个参数,默认会使用eq进行查询。
3.第二个方法,可以传两个参数,第一个参数用实体类传值,第二个参数用map设置每个类属性对应的限定条件。等具体使用时,就明白什么意思了。
4.此工具类,根据mybatis-plus常用的条件再进行调节,且没有检测每一个条件是否能正常使用,使用时请根据具体情况进行修改。如果我在使用时,遇到什么问题,会进行修改,并告诉大家,如果关注我,也不用太担心。
33.后端打开java/com.ruo.course/controller/PyCourseController.java文件,用下面代码进行替换。
package com.ruoyi.course.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.course.domain.PyCourse;
import com.ruoyi.course.service.PyCourseService;
import com.ruoyi.util.QueryWrapperUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
@RestController
@RequestMapping("/py/teacher/course")
public class PyCourseController extends BaseController {
@Autowired
private PyCourseService pyCourseService;
@GetMapping("/list")
@PreAuthorize("@ss.hasPermi('py:teacher:course:list')")
public TableDataInfo list(PyCourse pyCourse) {
startPage();
pyCourse.setUserId(getUserId());
Map<String, String> map = new HashMap<>();
map.put("name", "like");
map.put("teacherName", "like");
map.put("courseClass", "like");
QueryWrapper<PyCourse> wrapper = QueryWrapperUtil.getWrapper(pyCourse, map);
List<PyCourse> list = pyCourseService.list(wrapper);
return getDataTable(list);
}
@PostMapping("/export")
@Log(title = "课程管理", businessType = BusinessType.EXPORT)
@PreAuthorize("@ss.hasAnyPermi('py:teacher:course:export')")
public void export(HttpServletResponse response, PyCourse pyCourse) {
QueryWrapper<PyCourse> wrapper = QueryWrapperUtil.getWrapper(pyCourse);
List<PyCourse> list = pyCourseService.list(wrapper);
ExcelUtil<PyCourse> util = new ExcelUtil<PyCourse>(PyCourse.class);
util.exportExcel(response, list, "课程信息");
}
/**
* 根据课程编号获取详细信息
*/
@GetMapping(value = "/{courseId}")
@PreAuthorize("@ss.hasPermi('py:teacher:course:query')")
public AjaxResult getInfo(@PathVariable String courseId) {
return AjaxResult.success(pyCourseService.getById(courseId));
}
/**
* 新增课程
*/
@PostMapping
@PreAuthorize("@ss.hasPermi('py:teacher:course:add')")
@Log(title = "课程管理", businessType = BusinessType.INSERT)
public AjaxResult add(@RequestBody PyCourse pyCourse) {
System.out.println("jinrule.....");
System.out.println(pyCourse);
pyCourse.setUserId(getUserId());
pyCourse.setCreateBy(getUsername());
pyCourse.setCreateTime(new Date());
return toAjax(pyCourseService.save(pyCourse));
}
/**
* 修改保存课程
*/
@PutMapping
@PreAuthorize("@ss.hasPermi('py:teacher:course:edit')")
@Log(title = "课程管理", businessType = BusinessType.UPDATE)
public AjaxResult edit(@RequestBody PyCourse pyCourse) {
pyCourse.setUpdateBy(getUsername());
pyCourse.setUpdateTime(new Date());
return toAjax(pyCourseService.updateById(pyCourse));
}
/**
* 删除课程
*/
@DeleteMapping("/{ids}")
@PreAuthorize("@ss.hasPermi('py:teacher:course:remove')")
@Log(title = "课程管理", businessType = BusinessType.DELETE)
public AjaxResult remove(@PathVariable String[] ids) {
return toAjax(pyCourseService.removeByIds(Arrays.asList(ids)));
}
}
注意:
1.上面后端接口是模仿java/com.ruoyi/web/controller/system/SysRoleController.java文件,进行部分内容的添加和修改而完成的。以后写类似功能的,可以模仿若依自带的接口进行设计。
2.上面内容可以根据自己的实际使用进行修改。
34.前端打开src文件夹,在src文件夹下创建py文件夹,然后在py文件夹下创建api文件夹,再然后在api文件夹下创建teacher文件夹,最后在teacher文件夹下创建course.js文件。
import request from "@/utils/request";
let courseUrl = "/py/teacher/course";
//查询课程列表
export function listCourse(query) {
return request({
url: courseUrl + '/list',
method: 'get',
params: query
})
}
//查询课程详细
export function getCourse(courseId) {
return request({
url: courseUrl + '/' + courseId,
method: 'get'
})
}
//新增课程
export function addCourse(data) {
return request({
url: courseUrl,
method: 'post',
data: data
})
}
//修改课程
export function updateCourse(data) {
return request({
url: courseUrl,
method: 'put',
data: data
})
}
//删除课程
export function delCourse(roleId) {
return request({
url: courseUrl + '/' + roleId,
method: 'delete'
})
}
注意:
1.course.js文件是模仿前端src/api/system/role.js文件设计。
2.创建的src/py文件夹用来保存以后新添加的文件(除views文件夹中的页面文件),这样能够快速区分自己创建和若依自带的文件,便于以后管理。
35.前端打开src/views/py/teacher/index.vue文件,用以下代码替换。
<template>
<div class="app-container">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
<el-form-item label="课程名称" prop="name">
<el-input v-model="queryParams.name" placeholder="请输入课程名称" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="老师姓名" prop="teacherName">
<el-input v-model="queryParams.teacherName" placeholder="请输入老师姓名" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="课程班级" prop="courseClass">
<el-input v-model="queryParams.courseClass" placeholder="请输入课程班级" clearable style="width: 240px"
@keyup.enter.native="handleQuery" />
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
<el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['py:teacher:course:add']">新增</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
v-hasPermi="['py:teacher:course:edit']">修改</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete" v-hasPermi="['py:teacher:course:remove']">删除</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['py:teacher:course:export']">导出</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="courseList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="课程标识" prop="id" width="270" :show-overflow-tooltip="true" />
<el-table-column label="名称" prop="name" width="150" :show-overflow-tooltip="true" />
<el-table-column label="老师名称" prop="teacherName" width="150" :show-overflow-tooltip="true" />
<el-table-column label="班级" prop="courseClass" width="150" :show-overflow-tooltip="true" />
<el-table-column label="介绍" prop="introduce" width="200" :show-overflow-tooltip="true" />
<el-table-column label="创建时间" align="center" prop="createTime" width="180">
<template slot-scope="scope">
<span>{{ parseTime(scope.row.createTime) }}</span>
</template>
</el-table-column>
<el-table-column label="操作" align="center" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.roleId !== 1">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['py:teacher:course:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['py:teacher:course:remove']">删除</el-button>
</template>
</el-table-column>
</el-table>
<pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize"
@pagination="getList" />
<!-- 添加或修改课程信息对话框 -->
<el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="100px">
<el-form-item label="课程名称" prop="name">
<el-input v-model="form.name" placeholder="请输入课程名称" />
</el-form-item>
<el-form-item label="老师姓名" prop="teacherName">
<el-input v-model="form.teacherName" placeholder="请输入老师姓名" />
</el-form-item>
<el-form-item label="课程班级" prop="courseClass">
<el-input v-model="form.courseClass" placeholder="请输入课程班级" />
</el-form-item>
<el-form-item label="课程介绍" prop="introduce">
<el-input v-model="form.introduce" placeholder="请输入课程介绍" />
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="submitForm">确 定</el-button>
<el-button @click="cancel">取 消</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { listCourse, getCourse, addCourse, updateCourse, delCourse } from "@/py/api/teacher/course"
export default {
name: "TeacherCourse",
dicts: ['sys_normal_disable'],
data() {
return {
// 遮罩层
loading: true,
// 选中数组
ids: [],
// 非单个禁用
single: true,
// 非多个禁用
multiple: true,
// 显示搜索条件
showSearch: true,
// 总条数
total: 0,
// 课程表格数据
courseList: [],
// 弹出层标题
title: "",
// 是否显示弹出层
open: false,
// 日期范围
dateRange: [],
// 查询参数
queryParams: {
pageNum: 1,
pageSize: 10,
name: undefined,
teacherName: undefined,
courseClass: undefined
},
// 表单参数
form: {},
// 表单校验
rules: {
name: [
{ required: true, message: "课程名称不能为空", trigger: "blur" }
],
teacherName: [
{ required: true, message: "老师姓名不能为空", trigger: "blur" }
]
}
};
},
created() {
this.getList();
},
methods: {
/** 查询课程列表 */
getList() {
this.loading = true;
listCourse(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.courseList = response.rows;
this.total = response.total;
this.loading = false;
})
},
// 取消按钮
cancel() {
this.open = false;
this.reset();
},
// 表单重置
reset() {
this.form = {
name: undefined,
teacherName: undefined,
courseClass: undefined,
introduce: undefined
};
this.resetForm("form");
},
/** 搜索按钮操作 */
handleQuery() {
this.queryParams.pageNum = 1;
this.getList();
},
/** 重置按钮操作 */
resetQuery() {
this.dateRange = [];
this.resetForm("queryForm");
this.handleQuery();
},
// 多选框选中数据
handleSelectionChange(selection) {
this.ids = selection.map(item => item.id);
this.single = selection.length != 1;
this.multiple = !selection.length;
},
/** 新增按钮操作 */
handleAdd() {
this.reset();
// this.getMenuTreeselect();
this.open = true;
this.title = "添加课程";
},
/** 修改按钮操作 */
handleUpdate(row) {
this.reset();
const courseId = row.id || this.ids
// const roleMenu = this.getRoleMenuTreeselect(roleId);
getCourse()
getCourse(courseId).then(response => {
this.form = response.data;
this.open = true;
this.title = "修改课程";
});
},
/** 提交按钮 */
submitForm: function () {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.id != undefined) {
// this.form.menuIds = this.getMenuAllCheckedKeys();
updateCourse(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
this.open = false;
this.getList();
});
} else {
// this.form.menuIds = this.getMenuAllCheckedKeys();
addCourse(this.form).then(response => {
this.$modal.msgSuccess("新增成功");
this.open = false;
this.getList();
});
}
}
});
},
/** 提交按钮 */
submitDataScope: function () {
if (this.form.roleId != undefined) {
this.form.deptIds = this.getDeptAllCheckedKeys();
dataScope(this.form).then(response => {
this.$modal.msgSuccess("修改成功");
// this.openDataScope = false;
this.getList();
});
}
},
/** 删除按钮操作 */
handleDelete(row) {
const courseIds = row.id || this.ids;
this.$modal.confirm('是否确认删除课程标识为"' + courseIds + '"的数据项?').then(function () {
return delCourse(courseIds);
}).then(() => {
this.getList();
this.$modal.msgSuccess("删除成功");
}).catch(() => { });
},
/** 导出按钮操作 */
handleExport() {
this.download('/py/teacher/course/export', {
...this.queryParams
}, `course_${new Date().getTime()}.xlsx`)
}
}
};
</script>
注意:
1.此文件模仿前端src/views/system/role/index.vue文件进行设计。
2.创建的src/view/py文件夹用来保存以后新添加的页面文件,这样能够快速区分自己创建和若依自带的文件,便于以后管理。
36.运行前后端,浏览器登录用户名为ry,密码为admin123的账号(老师角色账号),然后点击“信息管理”,选择“课程管理”。
注意:
1.页面功能进行了大体测试,没有出现问题。如果遇到问题,请自行修改。
2.输入框的规则设置并不精细,可根据实际情况进行设定。
37.登录学生账号test,密码123456。由于我们没配置学生角色的具体功能,只能看见首页。
38.登录管理员账号admin,密码admin123,进行查看。
注意:管理员角色具有最高权限,当然使用学生角色和老师角色的所有功能,首页同时显示“老师登录首页”和“学生登录首页”就可以证明。如果只想显示一个页面,可以进行进一步限定。管理员角色可以使用老师角色的权限查询课程信息也说明了这一点。这也是正常的,管理员就应该有所有权限才能方便调试。