当前位置: 首页 > news >正文

【学生管理系统】学生管理(重点)

目录

4. 学生管理

4.1 需求

4.1.1 查询所有

4.1.2 添加:基本信息

4.1.3 添加:级联城市

4.1.4 添加:选课

4.2 环境搭建

4.2.1 前端环境

4.2.2 学生后端环境(9020)

4.2.3 课程后端环境(9030)

4.3 查询所有

4.3.1 基本功能:后端实现

4.3.2 基本功能:前端实现

4.3.3 班级:后端实现

4.3.4 班级:前端实现

4.3.5 选课详情:后端实现

4.3.6 选课详情:前端实现

4.5 添加

4.5.0 分析

4.5.1 基本操作

4.5.2 级联城市

4.5.2 选课

4. 6 修改

4.6.1 分析

4.5.2 查询详情

4.5.3 更新添加功能

4. 学生管理

4.1 需求

4.1.1 查询所有

 

4.1.2 添加:基本信息

 

4.1.3 添加:级联城市

 

 

4.1.4 添加:选课

 

4.2 环境搭建

4.2.1 前端环境

4.2.2 学生后端环境(9020)

  • 项目名:nacos-nuxt-student-service-student

  • pom文件

  • yml文件

  • 启动类

  • 拷贝配置类

  • 基本结构

  • pom文件

    ​
        <dependencies>
            <!--web起步依赖-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!-- nacos 客户端 -->
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
            </dependency>
    ​
            <!-- nacos 服务发现 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            </dependency>
    ​
            <!--swagger2-->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
            </dependency>
    ​
            <!-- feign 远程调用 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-openfeign</artifactId>
            </dependency>
    ​
            <!--测试-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
    ​
            <!-- mybatis plus-->
            <dependency>
                <groupId>com.baomidou</groupId>
                <artifactId>mybatis-plus-boot-starter</artifactId>
            </dependency>
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
            <!--自定义项目-->
            <dependency>
                <groupId>com.czxy</groupId>
                <artifactId>nacos-nuxt-student-domain</artifactId>
            </dependency>
    ​
            <!-- redis 启动器 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <!-- JavaMail 启动器 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-mail</artifactId>
            </dependency>
            <!-- MQ 启动器 -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-amqp</artifactId>
            </dependency>
    ​
            <!-- fastjson -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
            </dependency>
    ​
            <!--开发者工具-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-devtools</artifactId>
                <optional>true</optional>
            </dependency>
    ​
            <!--jwt工具-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
            </dependency>
            <!--joda 时间工具类 -->
            <dependency>
                <groupId>joda-time</groupId>
                <artifactId>joda-time</artifactId>
            </dependency>
            <!--JavaBean工具类,用于JavaBean数据封装-->
            <dependency>
                <groupId>commons-beanutils</groupId>
                <artifactId>commons-beanutils</artifactId>
            </dependency>
    ​
        </dependencies>
    ​
  • yml文件

    # 服务端口号
    server:
      port: 9020
    # 服务名
    spring:
      application:
        name: student-service
      datasource:
        driverClassName: com.mysql.jdbc.Driver
        url: jdbc:mysql://127.0.0.1:3306/cloud_es_student?useUnicode=true&characterEncoding=utf8
        username: root
        password: 1234
        druid:    #druid 连接池配置
          initial-size: 1       #初始化连接池大小
          min-idle: 1           #最小连接数
          max-active: 20        #最大连接数
          test-on-borrow: true  #获取连接时候验证,会影响性能
      cloud:
        nacos:
          discovery:
            server-addr: 127.0.0.1:8848   #nacos服务地址
    ​
    #开启log4j打印SQL语句
    logging:
      level:
        com:
          czxy:
            student:
              mapper: debug
    ​
    # mp日志打印
    mybatis-plus:
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
      global-config:
        db-config:
          logic-delete-value: 1
          logic-not-delete-value: 0
    ​
    sc:
      jwt:
        secret: sc@Login(Auth}*^31)&czxy% # 登录校验的密钥
        pubKeyPath: D:/rsa/rsa.pub # 公钥地址
        priKeyPath: D:/rsa/rsa.pri # 私钥地址
        expire: 360 # 过期时间,单位分钟

  • 启动类

    package com.czxy;
    ​
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
    import org.springframework.cloud.openfeign.EnableFeignClients;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @description
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    @EnableFeignClients
    public class StudentServiceApplication {
        public static void main(String[] args) {
            SpringApplication.run(StudentServiceApplication.class, args);
        }
    }
    ​

  • 配置类

     

  • 基本结构

     

4.2.3 课程后端环境(9030)

  • 项目名:nacos-nuxt-student-service-course

 

4.3 查询所有

4.3.1 基本功能:后端实现

  • 编写Vo

  • 编写controller

  • 编写service

  • 编写Vo

    package com.czxy.student.vo;
    ​
    import lombok.Data;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @description
     */
    @Data
    public class StudentVo {
        private String classesId;           //班级
        private String sname;               //姓名
        private String startAge;            //开始年龄
        private String endAge;              //结束年龄
    }
    ​

  • 编写controller

     

        @PostMapping("/condition/{size}/{current}")
        public BaseResult condition(
                @RequestBody StudentVo studentVo,
                @PathVariable("size") Integer size,
                @PathVariable("current") Integer current
                ) {
            // 查询
            Page<TbStudent> page = tbStudentService.condition(studentVo, size, current);
    ​
            // 返回
            return BaseResult.ok("查询成功", page);
        }

  • 编写service

    • 接口

      Page<TbStudent> condition(StudentVo studentVo, Integer size, Integer current);

    • 实现类

      @Override
          public Page<TbStudent> condition(StudentVo studentVo, Integer size, Integer current) {
              //1 条件
              QueryWrapper<TbStudent> queryWrapper = new QueryWrapper<>();
              if(StringUtils.isNotBlank(studentVo.getClassesId())) {
                  queryWrapper.eq("c_id", studentVo.getClassesId());
              }
              if(StringUtils.isNotBlank(studentVo.getSname())) {
                  queryWrapper.like("sname", studentVo.getSname());
              }
              if(StringUtils.isNotBlank(studentVo.getStartAge())) {
                  queryWrapper.ge("age", studentVo.getStartAge());
              }
              if(StringUtils.isNotBlank(studentVo.getEndAge())) {
                  queryWrapper.le("age", studentVo.getEndAge());
              }
      ​
              //2 分页
              Page<TbStudent> page = new Page<>(current, size);
      ​
              //3 查询
              baseMapper.selectPage(page, queryWrapper);
      ​
              //4 关联
      ​
              //5 返回
              return page;
          }

4.3.2 基本功能:前端实现

  • 列表

  • 条件

  • 分页

  • 列表

    <template>
      <div>
        <!-- 添加按钮 -->
        <el-button type="primary" @click="openStudentDialog">添加</el-button>
    ​
        <!-- 列表start -->
        <el-table
          :data="studentPage.records"
          stripe
          style="width: 100%">
          <el-table-column
            type="selection"
            width="55">
          </el-table-column>
          <el-table-column
            prop="sid"
            label="学生ID"
            fixed
            width="180">
          </el-table-column>
          <el-table-column
            prop="cid"
            label="班级名称"
            fixed
            width="180">
          </el-table-column>
          <el-table-column
            prop="sname"
            label="学生姓名"
            width="180">
          </el-table-column>
          <el-table-column
            prop="age"
            label="年龄"
            width="180">
          </el-table-column>
          <el-table-column
            prop="birthday"
            label="生日"
            width="180">
          </el-table-column>
          <el-table-column
            prop="gender"
            label="性别"
            width="180">
            <template slot-scope="scope">
              {{scope.row.gender == 1 ? '男': '女'}}
            </template>
          </el-table-column>
          <el-table-column
            prop="courseCount"
            label="选课数"
            width="180">
          </el-table-column>
          <el-table-column
            prop="courseList"
            label="选课详情"
            width="180">
          </el-table-column>
          <el-table-column
            label="操作" 
            fixed="right"
            width="180">
            <template slot-scope="scope">
              <el-button size="mini">编辑</el-button>
              <el-button size="mini" type="danger">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
        <!-- 列表end -->
    ​
    ​
        <!-- 弹出框 start -->
        <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
          <el-form :model="student" label-width="80px">
            <el-form-item label="班级名称">
              <el-select v-model="student.cid" placeholder="请选择班级">
                <el-option v-for="(classes,index) in classesList" :key="index" :label="classes.cname" :value="classes.cid"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="选择城市">
              <el-cascader v-model="student.cids" :props="cityProps"></el-cascader>
            </el-form-item>
            <el-form-item label="姓名">
              <el-input v-model="student.sname"></el-input>
            </el-form-item>
            <el-form-item label="年龄">
              <el-input v-model="student.age"></el-input>
            </el-form-item>
            <el-form-item label="生日">
              <el-date-picker
                v-model="student.birthday"
                value-format="yyyy-MM-dd"
                type="date"
                placeholder="请选择学生生日">
              </el-date-picker>
            </el-form-item>
            <el-form-item label="性别">
              <el-radio-group v-model="student.gender">
                <el-radio :label="1">男</el-radio>
                <el-radio :label="0">女</el-radio>
              </el-radio-group>
            </el-form-item>
            <el-form-item label="选课">
              <el-checkbox-group v-model="student.courseIds">
                <el-checkbox v-for="(course,index) in courseList" :key="index" :label="course.cid">{{course.cname}}</el-checkbox>
              </el-checkbox-group>
            </el-form-item>
          </el-form>
          {{student}}
          <div slot="footer" class="dialog-footer">
            <el-button @click="dialogStudentVisible = false">取 消</el-button>
            <el-button type="primary" @click="addStudent">确 定</el-button>
          </div>
        </el-dialog>
        <!-- 弹出框 end -->
      </div>
    </template>
    ​
    <script>
    let _vue = null
    export default {
      data() {
        _vue = this                             //缓存vue对象
        return {
          dialogStudentVisible: false,          //学生弹出框控制变量
          student: {
            cids: [],
            courseIds: []
          },
          classesList: [],                      //班级列表
          cityProps: {                          //城市级联菜单的属性设置
            lazy: true,                         //开启
            async lazyLoad (node, resolve) {          //加载数据
              // 1. 如果 node.root == true 表示第一次加载,也就是省
              let parentId = null
              if(node.root == true) {
                parentId = "0"
              } else {
                // 其他 - node.value可以获得当前节点的id的值,例如:省的id
                parentId = node.value
              }
              console.info(node)
    ​
              // 2. ajax 查询所有的城市
              let { data:baseResult } = await _vue.$axios.get(`/student-service/city/${parentId}`)
    ​
              // 处理查询结果,如果是县,表示是叶子
              baseResult.data.forEach(city=>{
                city.leaf = node.level >=2
              })
              // 通过调用resolve将子节点数据返回,通知组件数据加载完成
              resolve(baseResult.data);
            },
            label: 'cityName',
            value: 'cid'
          },
          courseList: [],                       //课程列表
          studentVo: {                          //条件
            "classesId": "",
            "endAge": "",
            "sname": "",
            "startAge": ""
          },
          studentPage: {                        //结果 + 分页
            size: 3,
            current: 1,
            total: 0
          }
        }
      },  
      methods: {
        openStudentDialog() {
          // 查询所有的班级
          this.findAllClasses()
          // 查询所有的选课
          this.findAllCourse()
    ​
          // 控制变量
          this.dialogStudentVisible = true
        },
        async findAllClasses() {
          // ajax
          let { data: baseResult } = await this.$axios.get('/classes-service/classes')
          // 处理
          if(baseResult.code == 20000) {
            this.classesList = baseResult.data
          } else {
            this.$message.error(baseResult.message)
          }
        },
        async addStudent() {
          // 处理所选城市数据  数组转字符串, [1,2,3] --> 1,2,3
          this.student.cityIds = this.student.cids.join(',')
          // 发送ajax
          let {data:baseResult} = await this.$axios.post('/student-service/student', this.student)
          if(baseResult.code == 20000) {
            //成功
            this.$message.success(baseResult.message)
            //刷新列表
            this.conditionStudent()
            //关闭弹出框
            this.dialogStudentVisible = false
          } else {
            // 失败
            this.$message.error(baseResult.message)
          }
        },
        async findAllCourse() {
          let {data:baseResult} = await this.$axios.get('/course-service/course')
          this.courseList = baseResult.data
        },
        async conditionStudent() {
          // 查询
          let url = `/student-service/student/condition/${this.studentPage.size}/${this.studentPage.current}`
          let { data: baseResult} = await this.$axios.post(url, this.studentVo)
          // 处理结果
          this.studentPage = baseResult.data
        }
      },
      mounted() {
        // 查询所有的学生
        this.conditionStudent()
      },
    }
    </script>
    ​
    <style>
    ​
    </style>

  • 条件

     

        <el-row>
          <el-col :span="2">
            <!-- 添加按钮 -->
            <el-button type="primary" size="mini" @click="openStudentDialog">添加</el-button>
          </el-col>
          <el-col :span="22">
            <!-- 条件查询start -->
            <el-form :inline="true" :model="studentVo" size="mini" class="demo-form-inline">
              <el-form-item label="班级">
                <el-select v-model="studentVo.classesId" placeholder="请选择班级">
                  <el-option v-for="(classes,index) in classesList" :key="index" :label="classes.cname" :value="classes.cid"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item label="姓名">
                <el-input v-model="studentVo.sname" placeholder="请输入姓名"></el-input>
              </el-form-item>
              <el-form-item label="姓名">
                <el-row>
                  <el-col :span="11">
                    <el-input v-model="studentVo.startAge" placeholder="请输入开始年龄"></el-input>
                  </el-col>
                  <el-col :span="2" style="text-align: center;">-</el-col>
                  <el-col :span="11">
                    <el-input v-model="studentVo.endAge" placeholder="请输入结束年龄"></el-input>
                  </el-col>
                </el-row>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="conditionStudent(1)">查询</el-button>
              </el-form-item>
            </el-form>
            <!-- 条件查询end -->
          </el-col>
        </el-row>

  • 分页

     

        <!-- 分页 start -->
        <el-pagination
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
          :current-page="studentPage.current"
          :page-sizes="[1, 2, 3, 5, 10]"
          :page-size="studentPage.size"
          layout="total, sizes, prev, pager, next, jumper"
          :total="studentPage.total">
        </el-pagination>
        <!-- 分页 end -->
    ​
    <script>
    ​
    export default {
        methods: {
            handleSizeChange(val) {
                console.log(`每页 ${val} 条`);
                this.studentPage.size = val
                this.studentPage.current = 1
                this.conditionStudent()
            },
            handleCurrentChange(val) {
                console.log(`当前页: ${val}`);
                this.studentPage.current = val
                this.conditionStudent()
            }
        }
    }
    </script>

4.3.3 班级:后端实现

  • 班级服务:查询详情

  • 学生服务:

    • 检查student对象,是否有班级对象

    • 编写feign调用查询详情

    • 修改service,给student填充班级信息

  • 班级服务:查询详情

     

        @GetMapping("/{cid}")
        public BaseResult<TbClass> findById(@PathVariable("cid") Integer cid) {
            // 查询详情
            TbClass tbClass = tbClassesService.getById(cid);
            // 返回
            return BaseResult.ok("查询成功", tbClass);
        }

  • 学生服务:

    • 检查student对象,是否有班级对象

       

    • 编写feign调用查询详情

       

      package com.czxy.student.feign;
      ​
      import com.czxy.domain.TbClass;
      import com.czxy.vo.BaseResult;
      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       * @description
       */
      @FeignClient(value = "classes-service", path = "/classes")
      public interface ClassesFeign {
          // 必须有泛型,否则获得的数据不是TbClass而是Map
          @GetMapping("/{cid}")
          public BaseResult<TbClass> findById(@PathVariable("cid") Integer cid) ;
      }
      ​

    • 修改service,给student填充班级信息

          @Override
          public Page<TbStudent> condition(StudentVo studentVo, Integer size, Integer current) {
              //1 条件
              QueryWrapper<TbStudent> queryWrapper = new QueryWrapper<>();
              if(StringUtils.isNotBlank(studentVo.getClassesId())) {
                  queryWrapper.eq("c_id", studentVo.getClassesId());
              }
              if(StringUtils.isNotBlank(studentVo.getSname())) {
                  queryWrapper.like("sname", studentVo.getSname());
              }
              if(StringUtils.isNotBlank(studentVo.getStartAge())) {
                  queryWrapper.ge("age", studentVo.getStartAge());
              }
              if(StringUtils.isNotBlank(studentVo.getEndAge())) {
                  queryWrapper.le("age", studentVo.getEndAge());
              }
      ​
              //2 分页
              Page<TbStudent> page = new Page<>(current, size);
      ​
              //3 查询
              baseMapper.selectPage(page, queryWrapper);
      ​
              //4 关联
              page.getRecords().forEach(student -> {
                  // 4.1 处理对应班级信息
                  BaseResult<TbClass> classesBaseResult = classesFeign.findById(student.getCid());
                  TbClass tbClass = classesBaseResult.getData();
                  student.setTbClass(tbClass);
      ​
              });
      ​
              //5 返回
              return page;
          }

4.3.4 班级:前端实现

 

      <el-table-column
        label="班级名称"
        fixed
        width="180">
        <template slot-scope="scope">
          {{scope.row.tbClass  ? scope.row.tbClass.cname : ''}}
        </template>
      </el-table-column>

4.3.5 选课详情:后端实现

  • 课程服务:查找指定学生的选课

    • mapper:sql语句多表查询

    • service

    • controller

  • 学生服务

    • 编写CourseFeign

    • 修改学生service,完善级联操作

  • ==异常==:先完成添加,再完成查询时,会存在一个服务,编写2个feign情况,启动时会有异常。

     

  • 课程服务:查找指定学生的选课

    • mapper:sql语句多表查询

      package com.czxy.course.mapper;
      ​
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.czxy.domain.TbCourse;
      import com.czxy.domain.TbStudent;
      import org.apache.ibatis.annotations.Mapper;
      import org.apache.ibatis.annotations.Param;
      import org.apache.ibatis.annotations.Select;
      ​
      import java.util.List;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       * @description
       */
      @Mapper
      public interface TbCourseMapper extends BaseMapper<TbCourse> {
      ​
          /**
           * 查询指定学生的选课
           * @author 桐叔
           * @email liangtong@itcast.cn
           * @return
           */
          @Select("SELECT c.* FROM tb_course c, tb_student_course sc WHERE c.c_id = sc.c_id AND sc.s_id = #{sid}")
          public List<TbCourse> findAllByStudentId(@Param("sid") Integer sid);
      }
      ​

    • service

      • 接口

        package com.czxy.course.service;
        ​
        import com.baomidou.mybatisplus.extension.service.IService;
        import com.czxy.domain.TbCourse;
        import org.apache.ibatis.annotations.Param;
        ​
        import java.util.List;
        ​
        /**
         * @author 桐叔
         * @email liangtong@itcast.cn
         * @description
         */
        public interface TbCourseService extends IService<TbCourse> {
        ​
            public List<TbCourse> findAllByStudentId(Integer sid);
        }
        ​

      • 实现类

        package com.czxy.course.service.impl;
        ​
        import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
        import com.czxy.course.mapper.TbCourseMapper;
        import com.czxy.course.service.TbCourseService;
        import com.czxy.domain.TbCourse;
        import org.springframework.stereotype.Service;
        import org.springframework.transaction.annotation.Transactional;
        ​
        import java.util.List;
        ​
        /**
         * @author 桐叔
         * @email liangtong@itcast.cn
         * @description
         */
        @Service
        @Transactional
        public class TbCourseServiceImpl extends ServiceImpl<TbCourseMapper, TbCourse> implements TbCourseService {
            @Override
            public List<TbCourse> findAllByStudentId(Integer sid) {
                return baseMapper.findAllByStudentId(sid);
            }
        }
        ​

    • controller

      package com.czxy.course.controller;
      ​
      import com.czxy.course.service.TbCourseService;
      import com.czxy.domain.TbCourse;
      import com.czxy.vo.BaseResult;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      ​
      import javax.annotation.Resource;
      import java.util.List;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       * @description
       */
      @RestController
      @RequestMapping("/course")
      public class TbCourseController {
      ​
          @Resource
          private TbCourseService tbCourseService;
      ​
          @GetMapping("/student/{sid}")
          public BaseResult<List<TbCourse>> findAllByStudentId(@PathVariable("sid") Integer sid) {
              // 查询
              List<TbCourse> courseList = tbCourseService.findAllByStudentId(sid);
              // 返回
              return BaseResult.ok("查询成功", courseList);
          }
      ​
      }
      ​

  • 学生服务

    • 编写CourseFeign

       

      package com.czxy.student.feign;
      ​
      import com.czxy.domain.TbStudentCourse;
      import com.czxy.vo.BaseResult;
      import org.springframework.cloud.openfeign.FeignClient;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.RequestBody;
      ​
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       * @description
       */
      //@FeignClient(value = "服务名", path = "controller类路径")
      @FeignClient(value = "course-service", path = "/course")
      public interface CourseFeign {
      ​
          @GetMapping("/student/{sid}")
          public BaseResult<List<TbCourse>> findAllByStudentId(@PathVariable("sid") Integer sid);
      }
      ​

    • 修改学生service,完善级联操作

          @Override
          public Page<TbStudent> condition(StudentVo studentVo, Integer size, Integer current) {
              //1 条件
              QueryWrapper<TbStudent> queryWrapper = new QueryWrapper<>();
              if(StringUtils.isNotBlank(studentVo.getClassesId())) {
                  queryWrapper.eq("c_id", studentVo.getClassesId());
              }
              if(StringUtils.isNotBlank(studentVo.getSname())) {
                  queryWrapper.like("sname", studentVo.getSname());
              }
              if(StringUtils.isNotBlank(studentVo.getStartAge())) {
                  queryWrapper.ge("age", studentVo.getStartAge());
              }
              if(StringUtils.isNotBlank(studentVo.getEndAge())) {
                  queryWrapper.le("age", studentVo.getEndAge());
              }
      ​
              //2 分页
              Page<TbStudent> page = new Page<>(current, size);
      ​
              //3 查询
              baseMapper.selectPage(page, queryWrapper);
      ​
              //4 关联
              page.getRecords().forEach(student -> {
                  // 4.1 处理对应班级信息
                  BaseResult<TbClass> classesBaseResult = classesFeign.findById(student.getCid());
                  TbClass tbClass = classesBaseResult.getData();
                  student.setTbClass(tbClass);
      ​
                  // 4.2 课程详情
                  BaseResult<List<TbCourse>> courseListBaseResult = courseFeign.findAllByStudentId(student.getSid());
                  List<TbCourse> courseList = courseListBaseResult.getData();
                  student.setCourseList(courseList);
                  student.setCourseCount(courseList.size());
      ​
              });
      ​
              //5 返回
              return page;
          }

 

4.3.6 选课详情:前端实现

<template slot-scope="scope">
     <el-tag v-for="(course,index) in scope.row.courseList" :key="index">{{course.cname}}</el-tag>
</template>

4.5 添加

4.5.0 分析

 

4.5.1 基本操作

1)后端实现:查询所有的班级

 

    /**
     * 查询所有
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @return
     */
    @GetMapping
    public BaseResult findAll() {
        // 查询所有
        List<TbClass> list = tbClassesService.list();
        // 返回
        return BaseResult.ok("查询成功", list);
    }

2)前端实现:班级列表+表单

  • 展示弹出框

  • 填充表单

  • 展示班级列表

  • 展示弹出框

    <template>
      <div>
        <!-- 添加按钮 -->
        <el-button type="primary" @click="dialogStudentVisible = true">添加</el-button>
    ​
    ​
        <!-- 弹出框 start -->
        <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
          <el-form :model="student" label-width="80px">
            <el-form-item label="活动名称">
              <el-input v-model="student.name" autocomplete="off"></el-input>
            </el-form-item>
            <el-form-item label="活动区域">
              <el-select v-model="student.region" placeholder="请选择活动区域">
                <el-option label="区域一" value="shanghai"></el-option>
                <el-option label="区域二" value="beijing"></el-option>
              </el-select>
            </el-form-item>
          </el-form>
          <div slot="footer" class="dialog-footer">
            <el-button @click="dialogStudentVisible = false">取 消</el-button>
            <el-button type="primary" @click="dialogStudentVisible = false">确 定</el-button>
          </div>
        </el-dialog>
        <!-- 弹出框 end -->
      </div>
    </template>
    ​
    <script>
    export default {
      data() {
        return {
          dialogStudentVisible: true,           //学生弹出框控制变量
          student: {
            
          }
        }
      },  
    }
    </script>
    ​
    <style>
    ​
    </style>

  • 填充表单

    <template>
      <div>
        <!-- 添加按钮 -->
        <el-button type="primary" @click="dialogStudentVisible = true">添加</el-button>
    ​
    ​
        <!-- 弹出框 start -->
        <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
          <el-form :model="student" label-width="80px">
            <el-form-item label="班级名称">
              <el-select v-model="student.cid" placeholder="请选择班级">
                <el-option label="区域一" value="shanghai"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="姓名">
              <el-input v-model="student.sname"></el-input>
            </el-form-item>
            <el-form-item label="年龄">
              <el-input v-model="student.age"></el-input>
            </el-form-item>
            <el-form-item label="生日">
              <el-date-picker
                v-model="student.birthday"
                value-format="yyyy-MM-dd"
                type="date"
                placeholder="请选择学生生日">
              </el-date-picker>
            </el-form-item>
            <el-form-item label="性别">
              <el-radio-group v-model="student.gender">
                <el-radio :label="1">男</el-radio>
                <el-radio :label="0">女</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-form>
          {{student}}
          <div slot="footer" class="dialog-footer">
            <el-button @click="dialogStudentVisible = false">取 消</el-button>
            <el-button type="primary" @click="dialogStudentVisible = false">确 定</el-button>
          </div>
        </el-dialog>
        <!-- 弹出框 end -->
      </div>
    </template>
    ​
    <script>
    export default {
      data() {
        return {
          dialogStudentVisible: true,           //学生弹出框控制变量
          student: {
            
          }
        }
      },  
    }
    </script>
    ​
    <style>
    ​
    </style>

  • 展示班级列表

    <template>
      <div>
        <!-- 添加按钮 -->
        <el-button type="primary" @click="openStudentDialog">添加</el-button>
    ​
    ​
        <!-- 弹出框 start -->
        <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
          <el-form :model="student" label-width="80px">
            <el-form-item label="班级名称">
              <el-select v-model="student.cid" placeholder="请选择班级">
                <el-option v-for="(classes,index) in classesList" :key="index" :label="classes.cname" :value="classes.cid"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="姓名">
              <el-input v-model="student.sname"></el-input>
            </el-form-item>
            <el-form-item label="年龄">
              <el-input v-model="student.age"></el-input>
            </el-form-item>
            <el-form-item label="生日">
              <el-date-picker
                v-model="student.birthday"
                value-format="yyyy-MM-dd"
                type="date"
                placeholder="请选择学生生日">
              </el-date-picker>
            </el-form-item>
            <el-form-item label="性别">
              <el-radio-group v-model="student.gender">
                <el-radio :label="1">男</el-radio>
                <el-radio :label="0">女</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-form>
          {{student}}
          <div slot="footer" class="dialog-footer">
            <el-button @click="dialogStudentVisible = false">取 消</el-button>
            <el-button type="primary" @click="dialogStudentVisible = false">确 定</el-button>
          </div>
        </el-dialog>
        <!-- 弹出框 end -->
      </div>
    </template>
    ​
    <script>
    export default {
      data() {
        return {
          dialogStudentVisible: false,           //学生弹出框控制变量
          student: {
            
          },
          classesList: [],                      //班级
        }
      },  
      methods: {
        openStudentDialog() {
          // 查询所有的班级
          this.findAllClasses()
    ​
          // 控制变量
          this.dialogStudentVisible = true
        },
        async findAllClasses() {
          // ajax
          let { data: baseResult } = await this.$axios.get('/classes-service/classes')
          // 处理
          if(baseResult.code == 20000) {
            this.classesList = baseResult.data
          } else {
            this.$message.error(baseResult.message)
          }
        }
      },
    }
    </script>
    ​
    <style>
    ​
    </style>

3)后端实现:基本添加

  • 编写service

  • 编写controller

  • 编写service

    • 接口

       

    • 实现类

      @Service
      @Transactional
      public class TbStudentServiceImpl extends ServiceImpl<TbStudentMapper, TbStudent> implements TbStudentService {
          @Override
          public boolean addStudent(TbStudent tbStudent) {
              // 保存学生基本信息
              int result = baseMapper.insert(tbStudent);
              return result == 1;
          }
      }

  • 编写controller

    package com.czxy.student.controller;
    ​
    import com.czxy.domain.TbStudent;
    import com.czxy.student.service.TbStudentService;
    import com.czxy.vo.BaseResult;
    import org.springframework.web.bind.annotation.*;
    ​
    import javax.annotation.Resource;
    import java.util.List;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @description
     */
    @RestController
    @RequestMapping("/student")
    public class TbStudentController {
    ​
        @Resource
        private TbStudentService tbStudentService;
    ​
        @PostMapping
        public BaseResult save(@RequestBody TbStudent tbStudent) {
            // 添加
            boolean result = tbStudentService.addStudent(tbStudent);
            // 提示
            if(result) {
                return BaseResult.ok("添加成功");
            }
            return BaseResult.error("添加失败");
        }
    ​
    }
    ​

4)前端实现:基本添加

<template>
  <div>
    <!-- 添加按钮 -->
    <el-button type="primary" @click="openStudentDialog">添加</el-button>
​
​
    <!-- 弹出框 start -->
    <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
      <el-form :model="student" label-width="80px">
        <el-form-item label="班级名称">
          <el-select v-model="student.cid" placeholder="请选择班级">
            <el-option v-for="(classes,index) in classesList" :key="index" :label="classes.cname" :value="classes.cid"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="姓名">
          <el-input v-model="student.sname"></el-input>
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model="student.age"></el-input>
        </el-form-item>
        <el-form-item label="生日">
          <el-date-picker
            v-model="student.birthday"
            value-format="yyyy-MM-dd"
            type="date"
            placeholder="请选择学生生日">
          </el-date-picker>
        </el-form-item>
        <el-form-item label="性别">
          <el-radio-group v-model="student.gender">
            <el-radio :label="1">男</el-radio>
            <el-radio :label="0">女</el-radio>
          </el-radio-group>
        </el-form-item>
      </el-form>
      {{student}}
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogStudentVisible = false">取 消</el-button>
        <el-button type="primary" @click="addStudent">确 定</el-button>
      </div>
    </el-dialog>
    <!-- 弹出框 end -->
  </div>
</template>
​
<script>
export default {
  data() {
    return {
      dialogStudentVisible: false,           //学生弹出框控制变量
      student: {
        
      },
      classesList: [],                      //班级
    }
  },  
  methods: {
    openStudentDialog() {
      // 查询所有的班级
      this.findAllClasses()
​
      // 控制变量
      this.dialogStudentVisible = true
    },
    async findAllClasses() {
      // ajax
      let { data: baseResult } = await this.$axios.get('/classes-service/classes')
      // 处理
      if(baseResult.code == 20000) {
        this.classesList = baseResult.data
      } else {
        this.$message.error(baseResult.message)
      }
    },
    async addStudent() {
      let {data:baseResult} = await this.$axios.post('/student-service/student', this.student)
      if(baseResult.code == 20000) {
        //成功
        this.$message.success(baseResult.message)
        //刷新列表
        this.conditionStudent()
        //关闭弹出框
        this.dialogStudentVisible = false
      } else {
        // 失败
        this.$message.error(baseResult.message)
      }
    },
    conditionStudent() {
​
    }
  },
}
</script>
​
<style>
​
</style>

4.5.2 级联城市

1)后端实现

 

    @GetMapping("/{parentId}")
    public BaseResult findAllByParentId(@PathVariable("parentId") String parentId) {
​
        //1 根据父id查询所有城市
        QueryWrapper<TbCity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id", parentId);
        List<TbCity> list = tbCityService.list(queryWrapper);
​
        //2 返回结果
        return BaseResult.ok("查询成功", list);
    }

2)前端实现

  • 异步加载

  • 完善添加

  • 异步加载

     

    <el-form-item label="选择城市">
              <el-cascader v-model="student.cids" :props="cityProps"></el-cascader>
            </el-form-item>
    cityProps: {                          //城市级联菜单的属性设置
            lazy: true,                         //开启
            async lazyLoad (node, resolve) {          //加载数据
              // 1. 如果 node.root == true 表示第一次加载,也就是省
              let parentId = null
              if(node.root == true) {
                parentId = "0"
              } else {
                // 其他 - node.value可以获得当前节点的id的值,例如:省的id
                parentId = node.value
              }
              console.info(node)
    ​
              // 2. ajax 查询所有的城市
              let { data:baseResult } = await _vue.$axios.get(`/student-service/city/${parentId}`)
    ​
              // 处理查询结果,如果是县,表示是叶子
              baseResult.data.forEach(city=>{
                city.leaf = node.level >=2
              })
              // 通过调用resolve将子节点数据返回,通知组件数据加载完成
              resolve(baseResult.data);
            },
            label: 'cityName',
            value: 'cid'
          },

  • 完善添加

     

    <template>
      <div>
        <!-- 添加按钮 -->
        <el-button type="primary" @click="openStudentDialog">添加</el-button>
    ​
    ​
        <!-- 弹出框 start -->
        <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
          <el-form :model="student" label-width="80px">
            <el-form-item label="班级名称">
              <el-select v-model="student.cid" placeholder="请选择班级">
                <el-option v-for="(classes,index) in classesList" :key="index" :label="classes.cname" :value="classes.cid"></el-option>
              </el-select>
            </el-form-item>
            <el-form-item label="选择城市">
              <el-cascader v-model="student.cids" :props="cityProps"></el-cascader>
            </el-form-item>
            <el-form-item label="姓名">
              <el-input v-model="student.sname"></el-input>
            </el-form-item>
            <el-form-item label="年龄">
              <el-input v-model="student.age"></el-input>
            </el-form-item>
            <el-form-item label="生日">
              <el-date-picker
                v-model="student.birthday"
                value-format="yyyy-MM-dd"
                type="date"
                placeholder="请选择学生生日">
              </el-date-picker>
            </el-form-item>
            <el-form-item label="性别">
              <el-radio-group v-model="student.gender">
                <el-radio :label="1">男</el-radio>
                <el-radio :label="0">女</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-form>
          {{student}}
          <div slot="footer" class="dialog-footer">
            <el-button @click="dialogStudentVisible = false">取 消</el-button>
            <el-button type="primary" @click="addStudent">确 定</el-button>
          </div>
        </el-dialog>
        <!-- 弹出框 end -->
      </div>
    </template>
    ​
    <script>
    let _vue = null
    export default {
      data() {
        _vue = this                             //缓存vue对象
        return {
          dialogStudentVisible: false,          //学生弹出框控制变量
          student: {
            cids: []
          },
          classesList: [],                      //班级
          cityProps: {                          //城市级联菜单的属性设置
            lazy: true,                         //开启
            async lazyLoad (node, resolve) {          //加载数据
              // 1. 如果 node.root == true 表示第一次加载,也就是省
              let parentId = null
              if(node.root == true) {
                parentId = "0"
              } else {
                // 其他 - node.value可以获得当前节点的id的值,例如:省的id
                parentId = node.value
              }
              console.info(node)
    ​
              // 2. ajax 查询所有的城市
              let { data:baseResult } = await _vue.$axios.get(`/student-service/city/${parentId}`)
    ​
              // 处理查询结果,如果是县,表示是叶子
              baseResult.data.forEach(city=>{
                city.leaf = node.level >=2
              })
              // 通过调用resolve将子节点数据返回,通知组件数据加载完成
              resolve(baseResult.data);
            },
            label: 'cityName',
            value: 'cid'
          },
        }
      },  
      methods: {
        openStudentDialog() {
          // 查询所有的班级
          this.findAllClasses()
    ​
          // 控制变量
          this.dialogStudentVisible = true
        },
        async findAllClasses() {
          // ajax
          let { data: baseResult } = await this.$axios.get('/classes-service/classes')
          // 处理
          if(baseResult.code == 20000) {
            this.classesList = baseResult.data
          } else {
            this.$message.error(baseResult.message)
          }
        },
        async addStudent() {
          // 处理所选城市数据  数组转字符串, [1,2,3] --> 1,2,3
          this.student.cityIds = this.student.cids.join(',')
          // 发送ajax
          let {data:baseResult} = await this.$axios.post('/student-service/student', this.student)
          if(baseResult.code == 20000) {
            //成功
            this.$message.success(baseResult.message)
            //刷新列表
            this.conditionStudent()
            //关闭弹出框
            this.dialogStudentVisible = false
          } else {
            // 失败
            this.$message.error(baseResult.message)
          }
        },
        conditionStudent() {
    ​
        }
      },
    }
    </script>
    ​
    <style>
    ​
    </style>

4.5.2 选课

1)查询所有课程:后端实现

 

package com.czxy.course.controller;
​
import com.czxy.course.service.TbCourseService;
import com.czxy.domain.TbCourse;
import com.czxy.vo.BaseResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
import javax.annotation.Resource;
import java.util.List;
​
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 * @description
 */
@RestController
@RequestMapping("/course")
public class TbCourseController {
​
    @Resource
    private TbCourseService tbCourseService;
​
    @GetMapping
    public BaseResult findAll() {
        List<TbCourse> list = tbCourseService.list();
        return BaseResult.ok("查询成功",list);
    }
​
}
​

2)显示所有课程:前端实现

 

<template>
  <div>
    <!-- 添加按钮 -->
    <el-button type="primary" @click="openStudentDialog">添加</el-button>
​
​
    <!-- 弹出框 start -->
    <el-dialog title="添加学生" :visible.sync="dialogStudentVisible">
      <el-form :model="student" label-width="80px">
        <el-form-item label="班级名称">
          <el-select v-model="student.cid" placeholder="请选择班级">
            <el-option v-for="(classes,index) in classesList" :key="index" :label="classes.cname" :value="classes.cid"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="选择城市">
          <el-cascader v-model="student.cids" :props="cityProps"></el-cascader>
        </el-form-item>
        <el-form-item label="姓名">
          <el-input v-model="student.sname"></el-input>
        </el-form-item>
        <el-form-item label="年龄">
          <el-input v-model="student.age"></el-input>
        </el-form-item>
        <el-form-item label="生日">
          <el-date-picker
            v-model="student.birthday"
            value-format="yyyy-MM-dd"
            type="date"
            placeholder="请选择学生生日">
          </el-date-picker>
        </el-form-item>
        <el-form-item label="性别">
          <el-radio-group v-model="student.gender">
            <el-radio :label="1">男</el-radio>
            <el-radio :label="0">女</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="选课">
          <el-checkbox-group v-model="student.courseIds">
            <el-checkbox v-for="(course,index) in courseList" :key="index" :label="course.cid">{{course.cname}}</el-checkbox>
          </el-checkbox-group>
        </el-form-item>
      </el-form>
      {{student}}
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogStudentVisible = false">取 消</el-button>
        <el-button type="primary" @click="addStudent">确 定</el-button>
      </div>
    </el-dialog>
    <!-- 弹出框 end -->
  </div>
</template>
​
<script>
let _vue = null
export default {
  data() {
    _vue = this                             //缓存vue对象
    return {
      dialogStudentVisible: false,          //学生弹出框控制变量
      student: {
        cids: [],
        courseIds: []
      },
      classesList: [],                      //班级列表
      cityProps: {                          //城市级联菜单的属性设置
        lazy: true,                         //开启
        async lazyLoad (node, resolve) {          //加载数据
          // 1. 如果 node.root == true 表示第一次加载,也就是省
          let parentId = null
          if(node.root == true) {
            parentId = "0"
          } else {
            // 其他 - node.value可以获得当前节点的id的值,例如:省的id
            parentId = node.value
          }
          console.info(node)
​
          // 2. ajax 查询所有的城市
          let { data:baseResult } = await _vue.$axios.get(`/student-service/city/${parentId}`)
​
          // 处理查询结果,如果是县,表示是叶子
          baseResult.data.forEach(city=>{
            city.leaf = node.level >=2
          })
          // 通过调用resolve将子节点数据返回,通知组件数据加载完成
          resolve(baseResult.data);
        },
        label: 'cityName',
        value: 'cid'
      },
      courseList: [],                       //课程列表
    }
  },  
  methods: {
    openStudentDialog() {
      // 查询所有的班级
      this.findAllClasses()
      // 查询所有的选课
      this.findAllCourse()
​
      // 控制变量
      this.dialogStudentVisible = true
    },
    async findAllClasses() {
      // ajax
      let { data: baseResult } = await this.$axios.get('/classes-service/classes')
      // 处理
      if(baseResult.code == 20000) {
        this.classesList = baseResult.data
      } else {
        this.$message.error(baseResult.message)
      }
    },
    async addStudent() {
      // 处理所选城市数据  数组转字符串, [1,2,3] --> 1,2,3
      this.student.cityIds = this.student.cids.join(',')
      // 发送ajax
      let {data:baseResult} = await this.$axios.post('/student-service/student', this.student)
      if(baseResult.code == 20000) {
        //成功
        this.$message.success(baseResult.message)
        //刷新列表
        this.conditionStudent()
        //关闭弹出框
        this.dialogStudentVisible = false
      } else {
        // 失败
        this.$message.error(baseResult.message)
      }
    },
    async findAllCourse() {
      let {data:baseResult} = await this.$axios.get('/course-service/course')
      this.courseList = baseResult.data
    },
    conditionStudent() {
​
    }
  },
}
</script>
​
<style>
​
</style>

3)中间表:后端基本+添加

 

package com.czxy.course.controller;
​
import com.czxy.course.service.TbStudentCourseService;
import com.czxy.domain.TbStudentCourse;
import com.czxy.vo.BaseResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
​
import javax.annotation.Resource;
​
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 * @description
 */
@RestController
@RequestMapping("/stduentCourse")
public class TbStudentCourseController {
​
    @Resource
    private TbStudentCourseService tbStudentCourseService;
​
    @PostMapping
    public BaseResult save(@RequestBody TbStudentCourse tbStudentCourse) {
        // 保存
        boolean result = tbStudentCourseService.save(tbStudentCourse);
        if(result) {
            return BaseResult.ok("添加成功");
        }
        return BaseResult.error("添加失败");
    }
​
}
​

4)修改后端添加(feign远程调用)

  • 在学生服务中

    • 定义选课feign

    • 修改学生添加,保存选课信息

  • 定义选课feign

     

    package com.czxy.student.feign;
    ​
    import com.czxy.domain.TbStudentCourse;
    import com.czxy.vo.BaseResult;
    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestBody;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @description
     */
    //@FeignClient(value = "服务名", path = "controller类路径")
    @FeignClient(value = "course-service", path = "/stduentCourse")
    public interface StudentCourseFeign {
    ​
        @PostMapping
        public BaseResult save(@RequestBody TbStudentCourse tbStudentCourse);
    }
    ​

  • 版本1:修改学生添加,保存选课信息

     

    package com.czxy.student.service.impl;
    ​
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.czxy.domain.TbStudent;
    import com.czxy.domain.TbStudentCourse;
    import com.czxy.student.feign.StudentCourseFeign;
    import com.czxy.student.mapper.TbStudentMapper;
    import com.czxy.student.service.TbStudentService;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    ​
    import javax.annotation.Resource;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @description
     */
    @Service
    @Transactional
    public class TbStudentServiceImpl extends ServiceImpl<TbStudentMapper, TbStudent> implements TbStudentService {
        @Resource
        private StudentCourseFeign studentCourseFeign;
        @Override
        public boolean addStudent(TbStudent tbStudent) {
            // 保存学生基本信息
            int result = baseMapper.insert(tbStudent);
    ​
            // 保存选课信息
            for (Integer courseId : tbStudent.getCourseIds()) {
                // 准备选课对象
                TbStudentCourse tbStudentCourse = new TbStudentCourse();
                tbStudentCourse.setCid(courseId);
                tbStudentCourse.setSid(tbStudent.getSid());
                // TODO 保存 ,没有处理异常
                studentCourseFeign.save(tbStudentCourse);
            }
    ​
            return result == 1;
        }
    }
    ​
  • 版本2:修改学生添加,保存选课信息(课程有错,学生回滚)

    package com.czxy.student.service.impl;
    ​
    import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    import com.czxy.domain.TbStudent;
    import com.czxy.domain.TbStudentCourse;
    import com.czxy.student.feign.StudentCourseFeign;
    import com.czxy.student.mapper.TbStudentMapper;
    import com.czxy.student.service.TbStudentService;
    import com.czxy.vo.BaseResult;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    ​
    import javax.annotation.Resource;
    ​
    /**
     * @author 桐叔
     * @email liangtong@itcast.cn
     * @description
     */
    @Service
    @Transactional
    public class TbStudentServiceImpl extends ServiceImpl<TbStudentMapper, TbStudent> implements TbStudentService {
        @Resource
        private StudentCourseFeign studentCourseFeign;
        @Override
        public boolean addStudent(TbStudent tbStudent) {
            // 保存学生基本信息
            int result = baseMapper.insert(tbStudent);
    ​
            // 记录操作结果
            boolean flag = result == 1;
    ​
            // 保存选课信息
            for (Integer courseId : tbStudent.getCourseIds()) {
                // 准备选课对象
                TbStudentCourse tbStudentCourse = new TbStudentCourse();
                tbStudentCourse.setCid(courseId);
                tbStudentCourse.setSid(tbStudent.getSid());
                // 保存课程  正确 code == 20000 , 错误 code == 0
                BaseResult baseResult = studentCourseFeign.save(tbStudentCourse);
                flag &= (baseResult.getCode() == 20000);
    ​
            }
    ​
            // 如果false抛异常 ,解决:课程有错,学生回滚
            if(flag == false) {
                throw new RuntimeException("添加失败");
            }
            //TODO 未解决问题:部分课程已经提交,需使用“分布式事务”解决
    ​
            return flag;
        }
    }
    ​

4. 6 修改

4.6.1 分析

 

4.5.2 查询详情

1) 分析

  • 基本数据:只要查询就可以回显(姓名、性别等)

  • 关联数据:

    • 班级:有数据直接回显

    • 城市:需要一个==数组==,存放一组城市数据,目前有的数据为字符串1,2,3。将在前端处理数据。

    • 选课:也需要一个数组,存在一组课程id数据。将在后端处理数据。

2)后端

  • 编写controller

  • 编写service

  • 编写controller

     

        @GetMapping("/{studentId}")
        public BaseResult findById(@PathVariable("studentId") Integer studentId) {
            // 查询
            TbStudent tbStudent = tbStudentService.findById(studentId);
            // 返回
            return BaseResult.ok("查询详情", tbStudent);
        }

  • 编写service

     

     TbStudent findById(Integer studentId);

        @Override
        public TbStudent findById(Integer studentId) {
            //1 学生详情
            TbStudent tbStudent = baseMapper.selectById(studentId);
            //2 选课信息
            BaseResult<List<TbCourse>> tbCourseListBaseResult = courseFeign.findAllByStudentId(studentId);
            List<TbCourse> tbCourseList = tbCourseListBaseResult.getData();
            tbStudent.setCourseList(tbCourseList);
            tbStudent.setCourseIds(tbCourseList.stream().map(course->course.getCid()).collect(Collectors.toList()));
    ​
            //3 返回
            return tbStudent;
        }

3)前端

 

openStudentDialog(studentId) {
      // 查询所有的班级
      this.findAllClasses()
      // 查询所有的选课
      this.findAllCourse()
​
      // 修改前查询详情
      if(studentId) {
        this.findStudentById(studentId)
        this.studentDialogTitle = '修改学生'
      } else {
        this.studentDialogTitle = '添加学生'
      }
​
      // 控制变量
      this.dialogStudentVisible = true
​
    },
        
async findStudentById(sid) {
      let {data:baseResult} = await this.$axios.get(`/student-service/student/${sid}`)
      // 获得结果
      this.student = baseResult.data
      // 处理数据:城市 "cityIds": "320000,321300,321322" --> cid : ["320000","321300","321322"]
      this.student.cids = this.student.cityIds.split(',')
    }

4)级联菜单回显

  • element ui的级联菜单先渲染组件时,如果有数据,将触发自动查询功能。

  • 步骤:

    1. 定义变量,隐藏级联菜单

    2. 查询数据成功后,显示菜单

    3. 提交数据后,隐藏菜单

    4. 【待完善】,点击x后,没有处理

  1. 定义变量,隐藏级联菜单

     

  2. 查询数据成功后,显示菜单

     

  3. 提交数据后,隐藏菜单

     

  4. 【待完善】,点击x后,没有处理

4.5.3 更新添加功能

1)学生服务

  • 优化controller

     

  • 修改service

  • 编写feign

  • 修改service

     

  • 编写feign

     

2)课程服务

 

    @DeleteMapping("/delete/student/{sid}")
    public BaseResult deleteAllBySid(@PathVariable("sid") Integer sid) {
        // 1 设置条件
        QueryWrapper<TbStudentCourse> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("s_id", sid);
​
        // 2 删除
        boolean remove = tbStudentCourseService.remove(queryWrapper);
​
        // 3 返回
        if(remove) {
            return BaseResult.ok("删除成功");
        }
        return BaseResult.error("删除失败");
​
    }
​

3)修复前端

  • 性别回显

     

  • 添加级联显示

相关文章:

  • 为解决bypy大文件上传报错—获取百度云文件直链并使用Aria2上传文件至服务器
  • java中的集合之List
  • 【编程基础知识】mysql根据某个int字段计算到每一行为止的累加值怎么实现
  • 怎样在备忘录中添加提醒?怎么设置备忘录提醒
  • 互联网环境下CentOS7部署K8S
  • 【Unity基础】如何选择Mono的.Net API版本
  • 【风格迁移】CAST:对比学习,从图像特征而非其二阶统计量(Gram矩阵)中学习风格
  • GPU编程学习
  • spark基础
  • ChatGpt大模型入门
  • (二十三)Flask之高频面试点
  • 2月21日,每日信息差
  • 普通索引还是唯一索引?
  • 详解:递归 和 排序(冒泡排序,选择排序,插入排序,归并排序,快速排序,希尔排序)
  • 【问题记录】防止mimikatz获取到明文密码
  • 超实用的JS常用算法详解(推荐)
  • 02-nginx环境准备
  • CSS 基础知识 属性
  • 【学生管理系统】整合JWT(完)
  • maya2023 安装和导入PyMEL
  • Java学习--JDBC
  • 【HDU No. 1224】 免费DIY之旅
  • 中国软件三季度业绩预测,中国软件股票趋势预测
  • 【MATLAB教程案例26】图像特征点提取算法matlab仿真与分析——sift,surf,kaze,corner,BRISK等
  • Tinyhttpd -- 用 C 从零写一个 HTTP 服务器
  • 计算机网络--应用层(https)
  • LeetCode每日一题——902. 最大为 N 的数字组合
  • 【上传图片,文件,视频功能合集】vue-elementul简单实现上传文件,上传图片,上传视频功能【详细注释,简单易用】
  • 大学四年庸庸碌碌,我弯道超车上了软件测试
  • 信安软考 第十八章 网络安全测评技术与标准
  • 粒子群算法PSO求解最大值和最小值案例(超详细注释)
  • ArrayList和CopyOnWriteArrayList