从零开始学若依框架-老师角色功能设计

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,进行查看。

注意:管理员角色具有最高权限,当然使用学生角色和老师角色的所有功能,首页同时显示“老师登录首页”和“学生登录首页”就可以证明。如果只想显示一个页面,可以进行进一步限定。管理员角色可以使用老师角色的权限查询课程信息也说明了这一点。这也是正常的,管理员就应该有所有权限才能方便调试。

使用若依框架进行老师功能的基础设计和课程管理详细设计到此结束。上面内容很多都是模仿若依原有代码进行设计,相信有很多小伙伴也可以自行完成。除若依自带功能外,还进行查询工具类的设计,此工具类可能并不完善,希望多多包涵!!!

通过上面内容的学习,有些小伙伴可以自己完成后续功能,甚至完成整个在线学习考核系统的所有功能。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飘逸飘逸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值