学生管理系统

前端使用vue2+elementUI+axios

后端使用springboot+ssm+swagger+通用mapper

1、用户登录和注册

1.1、搭建环境

  • 前端

    • 创建vue项目 使用的是vue2

    • 安装第三方组件

      npm install axios // 导入 axios
      vue add element //添加element插件 
      

      运行vue add element的选择

    在这里插入图片描述

    • 引入清除默认样式css

      main.js

      import './assets/reset.css' //清除浏览器默认样式
      
      import './plugins/element.js' //element 插件 引入elementui
      
      import Vue from 'vue'
      import App from './App.vue'
      import router from './router'
      import store from './store'
      
      import axios from 'axios' //引入axios ,发送ajax
      
      Vue.config.productionTip = false;
      Vue.prototype.axios = axios;  //将axios添加到vue对象中
      
      new Vue({
        router,
        store,
        render: h => h(App)
      }).$mount('#app')
      
    • 给app.vue设置样式,以及删除不需要的代码

      app.vue

      <template>
          <!--  路由视图  -->
          <router-view></router-view> 
      </template>
      
      <script>
          export default {
              name: 'app',
          }
      </script>
          
      <style>
          html,body{
              height: 100%;
          }
      </style>
      
  • 创建maven项目

    pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.czxy</groupId>
        <artifactId>student-manager</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.2.5.RELEASE</version>
        </parent>
        <!--2  确定版本-->
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <java.version>1.8</java.version>
            <spring-cloud-release.version>Hoxton.SR3</spring-cloud-release.version>
            <nacos.version>1.1.0</nacos.version>
            <alibaba.cloud.version>2.2.1.RELEASE</alibaba.cloud.version>
            <mybatis.starter.version>1.3.2</mybatis.starter.version>
            <mapper.starter.version>2.0.2</mapper.starter.version>
            <pageHelper.starter.version>1.2.5</pageHelper.starter.version>
            <mysql.version>8.0.24</mysql.version>
            <durid.starter.version>1.1.10</durid.starter.version>
            <mybatis.plus.version>3.4.0</mybatis.plus.version>
            <swagger.version>2.7.0</swagger.version>
            <jwt.jjwt.version>0.9.0</jwt.jjwt.version>
            <jwt.joda.version>2.9.7</jwt.joda.version>
            <beanutils.version>1.9.3</beanutils.version>
        </properties>
    
        <!-- 3  添加依赖 -->
        <dependencies>
            <!--web开发启动器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <!--测试启动器-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
            </dependency>
            <!-- mybatis启动器 -->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.starter.version}</version>
            </dependency>
            <!-- 通用Mapper启动器 -->
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper-spring-boot-starter</artifactId>
                <version>${mapper.starter.version}</version>
            </dependency>
            <dependency>
                <groupId>com.github.pagehelper</groupId>
                <artifactId>pagehelper-spring-boot-starter</artifactId>
                <version>${pageHelper.starter.version}</version>
            </dependency>
    
            <!-- mysql驱动 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
    
            <!-- Druid连接池 -->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${durid.starter.version}</version>
            </dependency>
    
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>${swagger.version}</version>
            </dependency>
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger-ui</artifactId>
                <version>${swagger.version}</version>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
            </dependency>
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-lang3</artifactId>
                <version>3.11</version>
            </dependency>
        </dependencies>
    
    </project>
    
    • 在resources目录下引入application.yml配置文件,配置数据库相关配置

      server:
        port: 8081
      
      spring:
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/ssm_db3?useUnicode=true&characterEncoding=utf8
          username: root
          password: root
          druid:    #druid 连接池配置
            initial-size: 3      #初始化连接池大小
            min-idle: 1           #最小连接数
            max-active: 20        #最大连接数
            test-on-borrow: true  #获取连接时候验证,会影响性能
      logging:
        pattern:
          level: logs-%level %msg%n
        #减少项目启动时的日志输出
        level:
          root: warn
          #指定包中的可u的执行日志
          com.czxy: debug
      
    • 编写启动类

    • 添加swagger配置类

      package com.czxy.config;
      
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import springfox.documentation.builders.ApiInfoBuilder;
      import springfox.documentation.builders.PathSelectors;
      import springfox.documentation.builders.RequestHandlerSelectors;
      import springfox.documentation.service.*;
      import springfox.documentation.spi.DocumentationType;
      import springfox.documentation.spi.service.contexts.SecurityContext;
      import springfox.documentation.spring.web.plugins.Docket;
      import springfox.documentation.swagger2.annotations.EnableSwagger2;
      
      import java.util.ArrayList;
      import java.util.List;
      
      /**
       * Swagger2 配置类,
       * 访问路径:swagger-ui.html
       * 自动注册:
       *     位置:resources/META-INF/spring.factories
       *     内容:
       *        org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
       *          com.czxy.config.Swagger2Configuration
       */
      @Configuration
      @EnableSwagger2
      public class Swagger2ConfigurationV3 {
      
          @Bean
          public Docket createRestApi() {
              // 1 确定文档Swagger版本
              Docket docket = new Docket(DocumentationType.SWAGGER_2);
              // 2 设置 api基本信息
              docket.apiInfo(apiInfo());
              // 3 设置自定义加载路径
              docket = docket.select()
                      .apis(RequestHandlerSelectors.basePackage("com.czxy"))
                      .paths(PathSelectors.any())
                      .build();
              //4 设置权限
              docket.securitySchemes(securitySchemes());
              docket.securityContexts(securityContexts());
      
              return docket;
          }
      
          private ApiInfo apiInfo() {
              return new ApiInfoBuilder()
                      .title("API")
                      .description("基于swagger接口文档")
                      .contact(new Contact("梁桐","http://www.javaliang.com","liangtong@itcast.cn"))
                      .version("1.0")
                      .build();
          }
      
          private List<ApiKey> securitySchemes() {
              List<ApiKey> list = new ArrayList<>();
              // name 为参数名  keyname是页面传值显示的 keyname, name在swagger鉴权中使用
              list.add(new ApiKey("Authorization", "Authorization", "header"));
              return list;
          }
      
          private List<SecurityContext> securityContexts() {
              List<SecurityContext> list = new ArrayList<>();
              list.add(SecurityContext.builder()
                      .securityReferences(defaultAuth())
                      .forPaths(PathSelectors.regex("^(?!auth).*$"))
                      .build());
              return list;
          }
      
          private List<SecurityReference> defaultAuth() {
              AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
              AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
              authorizationScopes[0] = authorizationScope;
              List<SecurityReference> list = new ArrayList();
              list.add(new SecurityReference("Authorization", authorizationScopes));
              return list;
          }
      
      }
      
    • 编写前端响应类

      package com.czxy.vo;
      
      
      import java.util.HashMap;
      import java.util.Map;
      
      /**
       * @author 桐叔
       * @email liangtong@itcast.cn
       */
      public class BaseResult<T> {
      
          //成功状态码
          public static final int OK = 20000;
          //失败状态码
          public static final int ERROR = 0;
      
          //返回码
          private Integer code;
          //返回消息
          private String message;
      
          //存放数据
          private T data;
          //其他数据
          private Map<String,Object> other = new HashMap<>();
      
          public BaseResult() {
      
          }
      
          public BaseResult(Integer code, String message) {
              this.code = code;
              this.message = message;
          }
          public BaseResult(Integer code, String message, T data) {
              this.code = code;
              this.message = message;
              this.data = data;
          }
      
          /**
           * 快捷成功BaseResult对象
           * @param message
           * @return
           */
          public static BaseResult ok(String message){
              return new BaseResult(BaseResult.OK , message);
          }
      
          public static BaseResult ok(String message, Object data){
              return new BaseResult(BaseResult.OK , message, data );
          }
      
          /**
           * 快捷失败BaseResult对象
           * @param message
           * @return
           */
          public static BaseResult error(String message){
              return new BaseResult(BaseResult.ERROR , message);
          }
      
          /**
           * 自定义数据区域
           * @param key
           * @param msg
           * @return
           */
          public BaseResult append(String key , Object msg){
              other.put(key , msg);
              return this;
          }
      
          public Integer getCode() {
              return code;
          }
      
          public String getMessage() {
              return message;
          }
      
          public T getData() {
              return data;
          }
      
          public Map<String, Object> getOther() {
              return other;
          }
      }
      

1.2 、用户登录

1.2.0、数据库

/*Table structure for table `tb_user` */

DROP TABLE IF EXISTS `tb_user`;

CREATE TABLE `tb_user` (
  `u_id` varchar(32) NOT NULL COMMENT '用户编号',
  `user_name` varchar(50) DEFAULT NULL COMMENT '用户名',
  `password` varchar(32) DEFAULT NULL COMMENT '密码',
  `gender` bit(1) DEFAULT NULL COMMENT '性别,1表示男,0表示女',
  `city_ids` varchar(50) DEFAULT NULL '城市信息',
  PRIMARY KEY (`u_id`),
  UNIQUE KEY `user_name` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `tb_user` */

insert  into `tb_user`(`u_id`,`user_name`,`password`,`gender`,`city_ids`) values ('1','jack','1234','','32000,321300,321322'),('10','jack5','1234','',NULL),('2','rose','1234','\0',NULL),('3','张三','1234','',NULL),('4','tom','1234','',NULL),('5','jack2','1234','',NULL),('6','jack1','1234','',NULL),('7','jack3','1234','',NULL),('8','jack4','1234','',NULL),('cd0d2523b5024589af142787de8a7b2a','jack6','1234','',NULL);

1.2.1、后端实现

  • 步骤

    • 1.编写javaBean 对应数据库的user表
    • 2.编写mapper
    • 3.编写service 通过获取的user对象与数据库进行交互,判断用户名,密码是否正确
    • 4.编写controller 调用service,返回登录信息
  • 1 编写javaBean

    package com.czxy.domain;
    
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.util.List;
    
    @Data
    @Table(name = "tb_user")
    public class User {
        @Id
        @Column(name = "u_id")
        private String uid;
    
        @Column(name = "user_name")
        private String username;
    
        private String password;
    
        private Byte gender;
    
        @Column(name = "city_ids")
        private String cityIds;
    
    }
    
  • 编写mapper

    package com.czxy.mapper;
    
    import com.czxy.domain.User;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface UserMapper extends tk.mybatis.mapper.common.Mapper<User> {
    }
    
  • 编写serivce接口和实现类,及登录校验

    • 接口

      package com.czxy.service;
      
      import com.czxy.domain.User;
      
      public interface UserService {
          /**
           * 登录
           * @param user
           * @return
           */
          User login(User user);
      }
      
    • 实现类

      package com.czxy.service.impl;
      
      import com.czxy.domain.User;
      import com.czxy.mapper.UserMapper;
      import com.czxy.service.UserService;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      import tk.mybatis.mapper.entity.Example;
      
      import javax.annotation.Resource;
      
      @Service
      @Transactional //开启事务
      public class UserServiceImpl implements UserService {
      
          @Resource //注入mapper
          private UserMapper userMapper;
      
          @Override
          public User login(User user) {
              // 设置查询条件
              // 用户名和密码与数据库行匹配
              Example example = new Example(User.class);
              Example.Criteria criteria = example.createCriteria();
              criteria.andEqualTo("username",user.getUsername());
              criteria.andEqualTo("password",user.getPassword());
              // 条件查询
              User login = userMapper.selectOneByExample(example);
      
              return login;
          }
      }
      
  • 编写controller,进行接收和响应

    package com.czxy.controller;
    
    import com.czxy.domain.User;
    import com.czxy.service.UserService;
    import com.czxy.vo.BaseResult;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    
    @RequestMapping("/user")
    @RestController //以json数据响应
    @CrossOrigin //跨域
    public class UserController {
    
        @Resource //注入service
        private UserService service;
    
        /**
         *  登录校验
         * @param user
         * @return 是否登录成功
         */
        @PostMapping("/login")
        public BaseResult login(@RequestBody User user){
            try {
                User login = service.login(user);
                if (login!=null){
                    return BaseResult.ok("登录成功");
                }else {
                    return BaseResult.error("用户名或密码错误");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("登录失败,请稍后重试");
            }
        }
    }
    
  • 使用swagger测试

1.2.2、前端实现

  • 步骤

    • 创建Login.vue页面
    • 添加路由
    • 编写login的基本页面
    • 编写表单校验
    • 调用后端进行校验
  • 添加路由

    /src/router/index.js

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    
    Vue.use(VueRouter)
    
    const routes = [
      {
        path: '/',
        name: 'home',
        redirect:'/login' //重定向到登录页面
      },
      {
        path:'/login',
        name:'登录页面',
        component:()=>import("../views/Login")
      }
    ]
    
    const router = new VueRouter({
      mode: 'history',
      base: process.env.BASE_URL,
      routes
    })
    
    export default router
    
  • 编写登录的基本页面 和form表单的校验

    <template>
        <div class="login">
    <!--    登录卡片start    -->
            <el-card class="box-card">
                <div slot="header" class="clearfix">
                    <el-button type="text">登录</el-button>
                </div>
    
    <!--     登录表单start     -->
                <el-form :model="user" :rules="rules" ref="loginFrom" label-width="80px">
                    <el-form-item label="用户名" prop="username">
                        <el-input  v-model="user.username" prefix-icon="el-icon-user" placeholder="请输入用户名"></el-input>
                    </el-form-item>
                    <el-form-item label="密码" prop="password">
                        <el-input  v-model="user.password" prefix-icon="el-icon-lock" placeholder="请输入密码" show-password></el-input>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="login">提交</el-button>
                        <el-button @click="resetForm('loginFrom')">重置</el-button>
                         <!--      跳转到注册页面           -->
                        <el-link href="/register" :underline="false" style="float: right">没有账号,立即注册</el-link>
                    </el-form-item>
                </el-form>
    <!--     登录表单end       -->
            </el-card>
    <!--    登录卡片end    -->
    
        </div>
    </template>
    
    <script>
        export default {
            name: "Login",
            data(){
                return{
                    user:{}, //登录表单绑定的对象,
                    rules:{     //表单校验规则
                        username:[ //username与上面el-form-item的prop对应
                            {required:true,message:'请输入用户名',trigger:'blur'},
                            {min:3,max:6,message:'用户名长度在3-6之间',trigger:'blur'}
                        ],
                        password:[
                            {required:true,message:'请输入密码',trigger:'blur'},
                            {min:4,max:10,message:'密码长度在4-10之间',trigger:'blur'}
                        ]
                    }
                }
            },
            methods:{
                //重置表单
                resetForm(formName) {
                    this.$refs[formName].resetFields();
                },
                //登录方法
                login(){
                    
                }
            }
        }
    </script>
    
    <style scoped>
        <!--居中-->
        .login{
            height: 100%;
            display: flex;
            justify-content: center;
            flex-direction: row;
            align-items: center;
        }
        .box-card{
            width: 480px;
        }
    </style>
    
  • 编写login方法

    //登录方法
    login(){
        //进行表单校验,如果校验通过发送ajax 如果不通过进行提示
        this.$refs.loginFrom.validate(async (valid) => {
            if (valid) {  //校验通过执行的方法
                let {data} = await this.axios.post(`http://localhost:8081/user/login`,this.user);
                // 状态码为20000 为成功 为0为失败
                if (data.code==20000){
                    // 提示信息
                    this.$message.success(data.message);
                    this.$router.push('/home') //跳转到首页
                }else {
                    //失败的提示信息
                    this.$message.error(data.message);
                }
            } else {
                return false;
            }
        });
    }
    

页面效果

在这里插入图片描述

1.3、用户注册

1.3.0、省市县sql语句

CREATE TABLE tb_city(
  c_id VARCHAR(32) PRIMARY KEY COMMENT '城市ID',
  city_name VARCHAR(20) COMMENT '城市名称' ,
  parent_id VARCHAR(32) COMMENT '父ID'
);

INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320000','江苏省','0');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140000','山西省','0');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130000','河北省','0');

INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320100','南京市','320000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320102','玄武区','320100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('320103','白下区','320100');

INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('321300','宿迁市','320000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('321322','沭阳县','321300');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('321323','泗阳县','321300');


INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140100','太原市','140000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140106','迎泽区','140100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140108','尖草坪区','140100');

INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140800','运城市','140000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140823','闻喜县','140800');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('140828','夏 县','140800');

INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130100','石家庄市','130000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130127','高邑县','130100');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('130185','鹿泉市','130100');

INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('131000','廊坊市','130000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('131003','广阳区','131000');
INSERT INTO tb_city(c_id,city_name,parent_id) VALUES('131022','固安县','131000');

1.3.1、后端实现

  • 步骤
    • 编写用户名是否存在的校验方法 – 拥有表单提交前的校验,如果用户名已经存在则不能提交表单
    • 编写省市县的查询方法
    • 编写用户注册的方法
1、判断用户名是否存在的方法
  • 分析

    1. 获取前端发送的用户名
    2. 与数据库进行交互判断用户名是否存在
    3. 返回结果
  • 实现

    UserController

    /**
     * 判断用户名是否存在
     * @param username 用户名数据
     * @return
     */
    @GetMapping("/check/{username}")
    public BaseResult checkUsername(@PathVariable("username") String username){
        try {
            boolean result = service.checkUsername(username);
            //获取查询结果 true为用户名可用,false为用户名不可用
            if (result){
                return BaseResult.ok("用户名可用");
            }else {
                return BaseResult.error("用户名已存在,请重新输入");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.error("用户名已存在,请重新输入");
        }
    }
    

    UserService接口

    /**
     * 用户名校验
     * @param username 用户名
     * @return
     */
    boolean checkUsername(String username);
    

    UserService实现类

    @Override
    public boolean checkUsername(String username) {
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();
        //拼接条件
        criteria.andEqualTo("username",username);
        User user = userMapper.selectOneByExample(example);
    
        //如果用户名存在则不能添加返回false
        //如果用户名不存在则可以添加
        if (user == null){
            return true;
        }
        return false;
    }
    
2、省市县的查询方法
  • 分析

在这里插入图片描述

  • 步骤

    1. 编写City类
    2. 编写CityMapper类 编写查询方法
    3. 编写CityService接口及实现类
    4. 编写CityController 进行接收请求及响应
  • javaBean

    package com.czxy.domain;
    
    import com.fasterxml.jackson.annotation.JsonIgnore;
    import com.fasterxml.jackson.annotation.JsonInclude;
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.Transient;
    import java.util.ArrayList;
    import java.util.List;
    
    @Table(name = "tb_city")
    @Data
    public class City {
        @Id
        @Column(name = "c_id")
        private String cid;
    
        @Column(name = "city_name")
        private String cityName;
    
        @Column(name = "parent_id")
        @JsonIgnore //不转为json数据
        private String parentId;
    
        @Transient // 不进行数据的查询
        @JsonInclude(JsonInclude.Include.NON_EMPTY) // 如果为空就不转化为json数据
        private List<City> children = new ArrayList<>();
    }
    
  • CityMapper

    package com.czxy.mapper;
    
    import com.czxy.domain.City;
    import org.apache.ibatis.annotations.*;
    
    import java.util.List;
    
    @Mapper
    public interface CityMapper extends tk.mybatis.mapper.common.Mapper<City> {
    
    
        @Select("select * from tb_city where parent_id = #{parentId}")
        @Results( //只用一次,所有没有给id
                value = { //字段的映射关系
                        @Result(property = "cid",column = "c_id",id = true),
                        @Result(property = "cityName",column = "city_name"),
                        @Result(property = "parentId",column = "parent_id"),
                        // 一对多的查询当前city的子集合 c_id 为方法的参数
                        @Result(property = "children",column = "c_id",many = @Many(select = "findByParentId"))
                }
        )
        List<City> findByParentId(@Param("parentId") String parentId);
    }
    
  • CityService

    • 接口

      package com.czxy.service;
      
      import com.czxy.domain.City;
      
      import java.util.List;
      
      public interface CityService {
          /**
           * 查询省市县集合
           * @return
           */
          List<City> selectCityList();
      }
      
    • 实现类

      package com.czxy.service.impl;
      
      import com.czxy.domain.City;
      import com.czxy.mapper.CityMapper;
      import com.czxy.service.CityService;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      
      import javax.annotation.Resource;
      import java.util.List;
      
      @Service
      @Transactional //事务管理
      public class CityServiceImpl implements CityService {
      
          @Resource
          private CityMapper cityMapper;
      
          @Override
          public List<City> selectCityList() {
              // 查询所有的省 省的parentId为0
              // city的子集合会在mapper的方法里面进行查询
              List<City> list = cityMapper.findByParentId("0");
              return list;
          }
      }
      
  • CityController

    package com.czxy.controller;
    
    import com.czxy.domain.City;
    import com.czxy.service.CityService;
    import com.czxy.vo.BaseResult;
    import org.springframework.web.bind.annotation.CrossOrigin;
    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;
    
    @RequestMapping("/city")
    @RestController
    @CrossOrigin // 开启跨域
    public class CityController {
    
        @Resource
        private CityService service;
    
        @GetMapping
        public BaseResult<List<City>> selectCityList(){
            try {
                //查询省市县集合并返回
                List<City> list = service.selectCityList();
                return BaseResult.ok("查询成功",list);
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("查询失败");
            }
        }
    }
    
3 、用户注册
  • 步骤

    • 编写controller获取请求
    • 编写service添加用户
  • 实现

    • userContorller

      @PostMapping("/register")
      public BaseResult register(@RequestBody User login){
          try {
              boolean f = service.register(login);
              if (f){
                  return BaseResult.ok("注册成功");
              }else {
                  return BaseResult.error("注册失败,请稍后重试");
              }
          } catch (Exception e) {
              e.printStackTrace();
              return BaseResult.error("系统错误,请稍后重试");
          }
      }
      
    • userservice

      接口

      /**
       * 用户注册
       * @param login 用户数据
       * @return
       */
      boolean register(User login);
      

      实现类

      @Override
      public boolean register(User login) {
          //设置uid
          login.setUid(UUID.randomUUID().toString().replace("-",""));
          int i = userMapper.insert(login);
          // 如果数据库的改动行数为1则注册成功
          return i==1;
      }
      

1.3.2、前端实现

  • 步骤

    • 创建register.vue并添加路由
    • 编写注册页面
    • 编写查询省市县的信息
    • 编写表单校验
    • 编写登录方法
  • 创建页面,并添加路由

在这里插入图片描述

  • 编写基本页面

    <template>
        <div class="register">
            <!--    注册卡片start    -->
            <el-card class="box-card">
                <div slot="header" class="clearfix">
                    <el-button type="text">注册</el-button>
                </div>
    
                <!--     注册表单start     -->
                <el-form :model="user" :rules="rules" ref="registerFrom" label-width="80px">
                    <el-form-item label="用户名" prop="username">
                        <el-input  v-model="user.username" prefix-icon="el-icon-user" placeholder="请输入用户名"></el-input>
                    </el-form-item>
                    <el-form-item label="密码" prop="password">
                        <el-input  v-model="user.password" prefix-icon="el-icon-lock" placeholder="请输入密码" show-password></el-input>
                    </el-form-item>
                    <el-form-item label="确认密码" prop="repassword">
                        <el-input   v-model="user.repassword" prefix-icon="el-icon-lock" placeholder="请输入确认密码" show-password></el-input>
                    </el-form-item>
                    <el-form-item label="性别" >
                        <el-radio-group v-model="user.gender">
                            <el-radio :label="1">男</el-radio>
                            <el-radio :label="0">女</el-radio>7
                        </el-radio-group>
                    </el-form-item>
                    <el-form-item label="籍贯">
                        <!--       修改集合的label和value的默认值             -->
                        <el-cascader
                                v-model="user.cityList"
                                :options="cityList"
                                :props="{ value:'cid',label:'cityName'}"
                                ></el-cascader>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="register">注册</el-button>
                        <el-button @click="resetForm('registerFrom')">重置</el-button>
                        <!--      跳转到登录页面           -->
                        <el-link href="/login" :underline="false" style="float: right">已有账号,立即登录</el-link>
                    </el-form-item>
                </el-form>
                <!--     注册表单end       -->
            </el-card>
            <!--    注册卡片end    -->
    
        </div>
    </template>
    
    <script>
        export default {
            name: "Register",
            data(){
                return{
                    user:{}, //注册表单绑定的对象,
                    rules:{     //表单校验规则
                    },
                    cityList:[], //省市县列表
                }
            },
            methods:{
                //重置表单
                resetForm(formName) {
                    this.$refs[formName].resetFields();
                },
                //注册方法
                register(){
    
                },
                async selectCityList(){ // 查询省市县方法
                    let {data} = await this.axios.get(`http://localhost:8081/city`);
                    if (data.code==20000){
                        this.cityList = data.data;
                    }
                }
            },
            mounted() {
                //页面加载时,调用查询省市县的方法
                this.selectCityList();
            }
        }
    </script>
    
    <style scoped>
        .register{
            height: 100%;
            display: flex;
            justify-content: center;
            flex-direction: row;
            align-items: center;
        }
        .box-card{
            width: 500px;
        }
    </style>
    
  • 表单校验

    在data区域里面定义自定义校验方法

    data(){
        // 用户名的校验方法
        var usernameValidator = async (rule,value,callback)=>{
            //value为校验的值
            // callback为回调函数
            let {data} = await this.axios.get(`http://localhost:8081/user/check/${value}`);
            if (data.code==20000){
                return callback();
            } else {
                return callback(new Error(data.message))
            }
        };
        //确认密码的校验
        var repasswordValidatator = (rule,value,callback) =>{
            //如果确认密码和密码不一致,返回不一致
            if (value != this.user.password){
                callback(new Error("确认密码与密码不一致,请重新输入"))
            }
            //校验通过
            callback();
        };
        return{
            user:{}, //注册表单绑定的对象,
            rules:{     //表单校验规则
                username:[
                    {required:true,message:'请输入用户名',trigger:'blur'},
                    {min:3,max:6,message:'用户名长度在3-6之间',trigger:'blur'},
                    {validator:usernameValidator,trigger:'blur'} //自定义校验方法
                ],
                password:[
                    {required:true,message:'请输入密码',trigger:'blur'},
                    {min:3,max:10,message:'密码长度在3-10之间',trigger:'blur'}
                ],
                repassword:[
                    {required:true,message:'请输入确认密码',trigger:'blur'},
                    {validator:repasswordValidatator,trigger:'blur'}
                ]
            },
            cityList:[], //省市县列表
        }
    },
    
  • 注册方法

//注册方法
register(){
    //进行表单校验,如果校验通过发送ajax 如果不通过进行提示
    this.$refs.registerFrom.validate(async (valid) => {
        if (valid) { //校验通过执行的方法
            // 对user的cityList字段进行处理,修改为字符串类型
            let temp = this.user.cityList.toString();
            // javabean的字段为cityIds
            this.user.cityIds = temp.substring(1,temp.length);
            let {data} = await this.axios.post(`http://localhost:8081/user/register`,this.user);
            // 状态码为20000 为成功 为0为失败
            if (data.code==20000){
                // 提示信息
                this.$message.success(data.message);
                this.$router.push('/login') //跳转到登录页面
            }else {
                //失败的提示信息
                this.$message.error(data.message);
            }
        } else {
            return false;
        }
    });
}
  • 完整代码

    <template>
        <div class="register">
            <!--    注册卡片start    -->
            <el-card class="box-card">
                <div slot="header" class="clearfix">
                    <el-button type="text">注册</el-button>
                </div>
    
                <!--     注册表单start     -->
                <el-form :model="user" :rules="rules" ref="registerFrom" label-width="80px">
                    <el-form-item label="用户名" prop="username">
                        <el-input  v-model="user.username" prefix-icon="el-icon-user" placeholder="请输入用户名"></el-input>
                    </el-form-item>
                    <el-form-item label="密码" prop="password">
                        <el-input  v-model="user.password" prefix-icon="el-icon-lock" placeholder="请输入密码" show-password></el-input>
                    </el-form-item>
                    <el-form-item label="确认密码" prop="repassword">
                        <el-input  v-model="user.repassword" prefix-icon="el-icon-lock" placeholder="请输入确认密码" show-password></el-input>
                    </el-form-item>
                    <el-form-item label="性别" >
                        <el-radio-group v-model="user.gender">
                            <el-radio :label="1">男</el-radio>
                            <el-radio :label="0">女</el-radio>7
                        </el-radio-group>
                    </el-form-item>
                    <el-form-item label="籍贯">
                        <!--       修改集合的label和value的默认值             -->
                        <el-cascader
                                v-model="user.cityList"
                                :options="cityList"
                                :props="{ value:'cid',label:'cityName'}"
                                ></el-cascader>
                    </el-form-item>
                    <el-form-item>
                        <el-button type="primary" @click="register">注册</el-button>
                        <el-button @click="resetForm('registerFrom')">重置</el-button>
                        <!--      跳转到登录页面           -->
                        <el-link href="/register" :underline="false" style="float: right">已有账号,立即登录</el-link>
                    </el-form-item>
                </el-form>
                <!--     注册表单end       -->
            </el-card>
            <!--    注册卡片end    -->
    
        </div>
    </template>
    
    <script>
        export default {
            name: "Register",
            data(){
                // 用户名的校验方法
                var usernameValidator = async (rule,value,callback)=>{
                    //value为校验的值
                    // callback为回调函数
                    let {data} = await this.axios.get(`http://localhost:8081/user/check/${value}`);
                    if (data.code==20000){
                        return callback();
                    } else {
                        return callback(new Error(data.message))
                    }
                };
                //确认密码的校验
                var repasswordValidatator = (rule,value,callback) =>{
                    //如果确认密码和密码不一致,返回不一致
                    if (value != this.user.password){
                        callback(new Error("确认密码与密码不一致,请重新输入"))
                    }
                    //校验通过
                    callback();
                };
                return{
                    user:{}, //注册表单绑定的对象,
                    rules:{     //表单校验规则
                        username:[
                            {required:true,message:'请输入用户名',trigger:'blur'},
                            {min:3,max:6,message:'用户名长度在3-6之间',trigger:'blur'},
                            {validator:usernameValidator,trigger:'blur'} //自定义校验方法
                        ],
                        password:[
                            {required:true,message:'请输入密码',trigger:'blur'},
                            {min:3,max:10,message:'密码长度在3-10之间',trigger:'blur'}
                        ],
                        repassword:[
                            {required:true,message:'请输入确认密码',trigger:'blur'},
                            {validator:repasswordValidatator,trigger:'blur'}
                        ]
                    },
                    cityList:[], //省市县列表
                }
            },
            methods:{
                //重置表单
                resetForm(formName) {
                    this.$refs[formName].resetFields();
                },
                //注册方法
                register(){
                    //进行表单校验,如果校验通过发送ajax 如果不通过进行提示
                    this.$refs.registerFrom.validate(async (valid) => {
                        if (valid) { //校验通过执行的方法
                            // 对user的cityList字段进行处理,修改为字符串类型
                            let temp = this.user.cityList.toString();
                            // javabean的字段为cityIds
                            this.user.cityIds = temp.substring(1,temp.length);
                            let {data} = await this.axios.post(`http://localhost:8081/user/register`,this.user);
                            // 状态码为20000 为成功 为0为失败
                            if (data.code==20000){
                                // 提示信息
                                this.$message.success(data.message);
                                this.$router.push('/login') //跳转到登录页面
                            }else {
                                //失败的提示信息
                                this.$message.error(data.message);
                            }
                        } else {
                            return false;
                        }
                    });
                },
                async selectCityList(){  // 查询省市县方法
                    let {data} = await this.axios.get(`http://localhost:8081/city`);
                    if (data.code==20000){
                        this.cityList = data.data;
                    }
                }
            },
            mounted() {
                //页面加载时,调用查询省市县的方法
                this.selectCityList();
            }
        }
    </script>
    
    <style scoped>
        .register{
            height: 100%;
            display: flex;
            justify-content: center;
            flex-direction: row;
            align-items: center;
        }
        .box-card{
            width: 500px;
        }
    </style>
    
  • 页面效果

在这里插入图片描述

2、学生管理系统

2.1、首页

  • 步骤

    • 创建home.vue,并添加路由
    • 编写首页和导航条
  • 实现

    • 路由

在这里插入图片描述

  • 首页

    <template>
        <el-container>
            <el-header>
                <!--   导航条         -->
                <Header></Header>
            </el-header>
            <el-main>
                <!--    二级路由视图        -->
                <router-view></router-view>
            </el-main>
        </el-container>
    </template>
    
    <script>
        import Header from '../components/Header'
        export default {
            name: "Home",
            components:{
                Header
            }
        }
    </script>
    
    <style scoped>
        .el-header {
            text-align: center;
            line-height: 60px;
            padding: 0;
        /*取消默认的20px内边距*/
        }
        .el-container{
            height: 100%;
        }
    </style>
    
  • 导航条

    router是否使用 vue-router 的模式,启用该模式会在激活导航时以 index 作为 path 进行路由跳转

    default-active 当前激活菜单的 index 设置为当前路由的路径

    <template>
        <div>
            <el-menu
                    :default-active="$route.path"
                    mode="horizontal"
                    background-color="#545c64"
                    text-color="#fff"
                    router
                    active-text-color="#ffd04b">
                <el-menu-item index="/home">首页</el-menu-item>
                <el-submenu index="2">
                    <template slot="title">班级管理</template>
                    <el-menu-item index="/classList">班级列表</el-menu-item>
                </el-submenu>
                <el-submenu index="3">
                    <template slot="title">学生管理</template>
                    <el-menu-item index="/stuList">学生列表</el-menu-item>
                </el-submenu>
            </el-menu>
        </div>
    </template>
    
    <script>
        export default {
            name: "Header"
        }
    </script>
    
    <style scoped>
    
    </style>
    

2.1、班级管理

2.1.0、 sql语句

DROP TABLE IF EXISTS `tb_class`;

CREATE TABLE `tb_class` (
  `c_id` varchar(32) NOT NULL COMMENT '班级ID',
  `c_name` varchar(50) DEFAULT NULL COMMENT '班级名称',
  `desc` varchar(200) DEFAULT NULL COMMENT '班级描述',
  PRIMARY KEY (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

/*Data for the table `tb_class` */

insert  into `tb_class`(`c_id`,`c_name`,`desc`) values ('c001','Java12','123'),('c002','Java34班','。。。。'),('c003','Java56版','56版'),('c005','去问问','1111阿斯顿'),('c007','1212','111'),('c009','超神班','艾念超的划水班级'),('string','string','string');

2.1.1、后端实现

  • 步骤

    • 编写Classes类
    • 编写Controller,Service,mapper进行增删改查操作
  • 实现

    • Classes类

      package com.czxy.domain;
      
      import lombok.Data;
      
      import javax.persistence.Column;
      import javax.persistence.Id;
      import javax.persistence.Table;
      
      @Data
      @Table(name = "tb_class")
      public class Classes {
          @Id
          @Column(name = "c_id")
          private String cid;
          
          @Column(name = "c_name")
          private String cname;
          
          @Column(name = "`desc`")
          private String desc;
      }
      
    • ClassesController

      package com.czxy.controller;
      
      import com.czxy.domain.Classes;
      import com.czxy.service.ClassesService;
      import com.czxy.vo.BaseResult;
      import org.springframework.web.bind.annotation.*;
      
      import javax.annotation.Resource;
      import java.util.List;
      
      @RestController
      @RequestMapping("/class")
      @CrossOrigin
      public class ClassesController {
          @Resource
          private ClassesService service;
      
          /**
           * 根据id查询
           * @param id
           * @return
           */
          @GetMapping("/{id}")
          public BaseResult<Classes> selectById(@PathVariable("id") String id){
              try {
                  Classes classes = service.selectById(id);
                  return BaseResult.ok("查询成功",classes);
              } catch (Exception e) {
                  e.printStackTrace();
                  return BaseResult.error("查询失败");
              }
          }
      
          /**
           * 查询所有
           * @return
           */
          @GetMapping
          public BaseResult<List<Classes>> selectAll(){
              try {
                  List<Classes> list = service.selectAll();
                  return  BaseResult.ok("查询成功",list);
              } catch (Exception e) {
                  e.printStackTrace();
                  return BaseResult.error("查询失败");
              }
          }
      
          /**
           * 添加或者更新方法
           * @return
           */
          @PostMapping("/insertOrUpdate")
          public BaseResult insert(@RequestBody Classes classes){
              try {
                  // true 添加或者更新成功, false 失败
                  boolean result = service.insertOrUpdate(classes);
                  if (result){
                      return BaseResult.ok("编辑成功");
                  }else {
                      return BaseResult.error("编辑失败");
                  }
              } catch (Exception e) {
                  e.printStackTrace();
                  return BaseResult.error("编辑失败");
              }
          }
      
          @DeleteMapping("/{id}")
          public BaseResult delById(@PathVariable("id") String id){
              try {
                  boolean f = service.del(id);
                  if (f) {
                      return BaseResult.ok("删除成功");
                  }else {
                      return BaseResult.error("删除失败");
                  }
              } catch (Exception e) {
                  e.printStackTrace();
                  return BaseResult.error("删除失败");
              }
          }
      }
      
    • ClassesService

      接口

      package com.czxy.service;
      
      import com.czxy.domain.Classes;
      
      import java.util.List;
      
      public interface ClassesService {
          /**
           * 根据id查询
           * @param id
           * @return
           */
          Classes selectById(String id);
      
          /**
           * 查询所有
           * @return
           */
          List<Classes> selectAll();
      
          /**
           * 添加或者更新
           * @param classes
           * @return
           */
          boolean insertOrUpdate(Classes classes);
      
          /**
           * 根据id删除
           * @param id
           * @return
           */
          boolean del(String id);
      }
      

      实现类

      package com.czxy.service.impl;
      
      import com.czxy.domain.Classes;
      import com.czxy.mapper.ClassesMapper;
      import com.czxy.service.ClassesService;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      
      import javax.annotation.Resource;
      import java.util.List;
      
      @Service
      @Transactional
      public class ClassesServiceImpl implements ClassesService {
      
          @Resource
          private ClassesMapper classesMapper;
      
          @Override
          public Classes selectById(String id) {
              return classesMapper.selectByPrimaryKey(id);
          }
      
          @Override
          public List<Classes> selectAll() {
              return classesMapper.selectAll();
          }
      
          @Override
          public boolean insertOrUpdate(Classes classes) {
              Classes temp = selectById(classes.getCid());
              // 如果temp存在,进行修改操作,否则进行添加操作
              int result = 0;
              if (temp == null){
                  result = classesMapper.insertSelective(classes);
              }else {
                  result = classesMapper.updateByPrimaryKeySelective(classes);
              }
              return result == 1;
          }
      
          @Override
          public boolean del(String id) {
              int i = classesMapper.deleteByPrimaryKey(id);
              return i==1;
          }
      }
      
    • ClassesMapper

      package com.czxy.mapper;
      
      import com.czxy.domain.Classes;
      import org.apache.ibatis.annotations.Mapper;
      
      @Mapper
      public interface ClassesMapper extends tk.mybatis.mapper.common.Mapper<Classes> {
      }
      

2.1.2、前端实现

  • 步骤

    • 创建classList.vue,并添加路由
    • 编写表格显示班级列表
    • 编写对话框进行添加和修改操作
    • 编写删除操作
  • 路由

在这里插入图片描述

  • 编写表格

    <template>
        <div>
    <!--    班级列表start    -->
            <el-table :data="classList" border stripe style="width: 100%">
                <el-table-column label="班级编号" min-width="180" prop="cid"></el-table-column>
                <el-table-column label="班级名称" min-width="180" prop="cname"></el-table-column>
                <el-table-column  label="描述" min-width="180" prop="desc"></el-table-column>
                <el-table-column  label="操作" min-width="230px">
                    <template slot-scope="scope">
                        <el-button>修改</el-button>
                        <el-button type="danger" @click="del(scope.row.cid)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
    <!--    班级列表end    -->
        </div>
    </template>
    
    <script>
        export default {
            name: "ClassList",
            data(){
                return{
                    classList:[] // 班级列表
                }
            },
            methods:{
                async selectClassList(){ //查询班级列表
                    let {data} = await this.axios.get(`http://localhost:8081/class`);
                    if (data.code == 20000){
                        this.classList = data.data;
                    }
                },
                del(id){ //删除
                    
                }
            },
            mounted(){
                this.selectClassList();
            }
        }
    </script>
    
    <style scoped>
    
    </style>
    
  • 删除方法

    del(id){ //删除
        this.$confirm('是否删除该班级', '删除操作', {
            type: 'warning'
        }).then(async () => {
            let {data} = await this.axios.delete(`http://localhost:8081/class/${id}`);
            if (data.code==20000){
                // 成功提示及重新查询班级列表
                this.$message.success(data.message);
                this.selectClassList();
            } else {
                this.$message.error(data.message)
            }
        }).catch(() => {
            this.$message.info('取消成功')
        });
    },
    
  • 添加和删除对话框

    <!--    添加和删除的对话框 start   -->
            <el-dialog :title="dialogTitle==0?'添加班级':'修改班级'" width="600px" :visible.sync="classDialogFormVisible">
                <el-form :model="classes" :rules="dialogTitle==0?rules:{cid:[]}" label-width="80px" ref="classFrom">
                    <el-form-item label="班级编号" prop="cid">
                        <el-input v-model="classes.cid" placeholder="请输入班级编号"  :disabled="dialogTitle==1"></el-input>
                    </el-form-item>
                    <el-form-item label="班级名称">
                        <el-input v-model="classes.cname" placeholder="请输入班级名"></el-input>
                    </el-form-item>
                    <el-form-item label="描述">
                        <el-input v-model="classes.desc" type="textarea"  maxlength="80" :rows="4" placeholder="请输入描述"></el-input>
    
                    </el-form-item>
                </el-form>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="classDialogFormVisible = false">取 消</el-button>
                    <el-button type="primary" @click="insertOrUpdate">确 定</el-button>
                </div>
            </el-dialog>
    <!--    添加和删除的对话框 end   -->
    

    script部分

    <script>
        export default {
            name: "ClassList",
            data(){
                var cidValidator = async (rule,value,callback)=>{
                    let {data} = await this.axios.get(`http://localhost:8081/class/${value}`);
                    if (data.code==20000&&data.data){
                        callback(new Error('班级编号以存在,请重新输入'))
                    }
                    callback()
                };
                return{
                    classList:[], // 班级列表
                    classes:{},//表达绑定的对象,
                    classDialogFormVisible:false, //对话框的显隐
                    dialogTitle:0, //对话框的标题,0为添加,1为修改
                    rules:{ // 添加的校验规则
                        cid:[
                            {required:true,message:'请输入班级id',trigger:"blur"},
                            {validator:cidValidator,trigger:"blur"}
                        ]
                    },
                }
            },
            methods:{
                async selectClassList(){ //查询班级列表
                    let {data} = await this.axios.get(`http://localhost:8081/class`);
                    if (data.code == 20000){
                        this.classList = data.data;
                    }
                },
                del(id){ //删除
                    this.$confirm('是否删除该班级', '删除操作', {
                        type: 'warning'
                    }).then(async () => {
                        let {data} = await this.axios.delete(`http://localhost:8081/class/${id}`);
                        if (data.code==20000){
                            // 成功提示及重新查询班级列表
                            this.$message.success(data.message);
                            this.selectClassList();
                        } else {
                            this.$message.error(data.message)
                        }
                    }).catch(() => {
                        this.$message.info('取消成功')
                    });
                },
                async editView(id){ //修改页面
                    //清除提示错误的样式
                    if (this.$refs.classFrom) {
                        this.$refs.classFrom.resetFields();
                    }
                    let {data} = await this.axios.get(`http://localhost:8081/class/${id}`);
                    // 根据id查询 查询成功将对话框显示出来,并给classes对象赋值
                    if (data.code==20000){
                        this.classes = data.data;
                        this.classDialogFormVisible = true;
                        //设置对话框的标题
                        this.dialogTitle = 1;
                    }
                },
                addView(){ //添加用户页面
                    //清空 class对象
                    this.classes = {};
                    this.classDialogFormVisible = true;
                    //设置对话框的标题
                    this.dialogTitle = 0;
                    //清除提示错误的样式
                    if (this.$refs.classFrom) {
                        this.$refs.classFrom.resetFields();
                    }
                },
                async insertOrUpdate(){ //添加或者更新操作
                    this.$refs.classFrom.validate(async (valid) => {
                        if (valid) {
                            // 校验通过调用后端
                            let {data} = await this.axios.post(`http://localhost:8081/class/insertOrUpdate`,this.classes);
                            if (data.code==20000){
                                //成功提示,刷新表格
                                this.$message.success(data.message);
                                this.selectClassList();
                                //关闭对话框
                                this.classDialogFormVisible = false;
                            } else {
                                //失败提示
                                this.$message.error(data.message);
                            }
                        } else {
                            return false;
                        }
                    });
                },
            },
            mounted(){
                this.selectClassList();
            }
        }
    </script>
    
班级列表页面完整代码

classList.vue

<template>
    <div>
<!--    添加和删除的对话框 start   -->
        <el-dialog :title="dialogTitle==0?'添加班级':'修改班级'" width="600px" :visible.sync="classDialogFormVisible">
            <el-form :model="classes" :rules="dialogTitle==0?rules:{cid:[]}" label-width="80px" ref="classFrom">
                <el-form-item label="班级编号" prop="cid">
                    <el-input v-model="classes.cid" placeholder="请输入班级编号" :disabled="dialogTitle==1"></el-input>
                </el-form-item>
                <el-form-item label="班级名称">
                    <el-input v-model="classes.cname" placeholder="请输入班级名"></el-input>
                </el-form-item>
                <el-form-item label="描述">
                    <el-input v-model="classes.desc" type="textarea"  maxlength="80" :rows="4" placeholder="请输入描述"></el-input>

                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="classDialogFormVisible = false">取 消</el-button>
                <el-button type="primary" @click="insertOrUpdate">确 定</el-button>
            </div>
        </el-dialog>
<!--    添加和删除的对话框 end   -->

<!--    添加班级按钮    -->
        <el-button type="primary" @click="addView">添加班级</el-button>

<!--    班级列表start    -->
        <el-table :data="classList" border stripe style="width: 100%">
            <el-table-column label="班级编号" min-width="180" prop="cid"></el-table-column>
            <el-table-column label="班级名称" min-width="180" prop="cname"></el-table-column>
            <el-table-column  label="描述" min-width="180" prop="desc"></el-table-column>
            <el-table-column  label="操作" min-width="230px">
                <template slot-scope="scope">
                    <el-button @click="editView(scope.row.cid)">修改</el-button>
                    <el-button type="danger" @click="del(scope.row.cid)">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
<!--    班级列表end    -->
    </div>
</template>

<script>
    export default {
        name: "ClassList",
        data(){
            var cidValidator = async (rule,value,callback)=>{
                let {data} = await this.axios.get(`http://localhost:8081/class/${value}`);
                if (data.code==20000&&data.data){
                    callback(new Error('班级编号以存在,请重新输入'))
                }
                callback()
            };
            return{
                classList:[], // 班级列表
                classes:{},//表达绑定的对象,
                classDialogFormVisible:false, //对话框的显隐
                dialogTitle:0, //对话框的标题,0为添加,1为修改
                rules:{ // 添加的校验规则
                    cid:[
                        {required:true,message:'请输入班级id',trigger:"blur"},
                        {validator:cidValidator,trigger:"blur"}
                    ]
                },
            }
        },
        methods:{
            async selectClassList(){ //查询班级列表
                let {data} = await this.axios.get(`http://localhost:8081/class`);
                if (data.code == 20000){
                    this.classList = data.data;
                }
            },
            del(id){ //删除
                this.$confirm('是否删除该班级', '删除操作', {
                    type: 'warning'
                }).then(async () => {
                    let {data} = await this.axios.delete(`http://localhost:8081/class/${id}`);
                    if (data.code==20000){
                        // 成功提示及重新查询班级列表
                        this.$message.success(data.message);
                        this.selectClassList();
                    } else {
                        this.$message.error(data.message)
                    }
                }).catch(() => {
                    this.$message.info('取消成功')
                });
            },
            async editView(id){ //修改页面
                //清除提示错误的样式
                if (this.$refs.classFrom) {
                    this.$refs.classFrom.resetFields();
                }
                let {data} = await this.axios.get(`http://localhost:8081/class/${id}`);
                // 根据id查询 查询成功将对话框显示出来,并给classes对象赋值
                if (data.code==20000){
                    this.classes = data.data;
                    this.classDialogFormVisible = true;
                    //设置对话框的标题
                    this.dialogTitle = 1;
                }
            },
            addView(){ //添加用户页面
                //清空 class对象
                this.classes = {};
                this.classDialogFormVisible = true;
                //设置对话框的标题
                this.dialogTitle = 0;
  				//清除提示错误的样式
                if (this.$refs.classFrom) {
                    this.$refs.classFrom.resetFields();
                }
            },
            async insertOrUpdate(){ //添加或者更新操作
                this.$refs.classFrom.validate(async (valid) => {
                    if (valid) {
                        // 校验通过调用后端
                        let {data} = await this.axios.post(`http://localhost:8081/class/insertOrUpdate`,this.classes);
                        if (data.code==20000){
                            //成功提示,刷新表格
                            this.$message.success(data.message);
                            this.selectClassList();
                            //关闭对话框
                            this.classDialogFormVisible = false;
                        } else {
                            //失败提示
                            this.$message.error(data.message);
                        }
                    } else {
                        return false;
                    }
                });
            },
        },
        mounted(){
            this.selectClassList();
        }
    }
</script>

<style scoped>

</style>

2.2、学生管理

2.2.1、sql语句

DROP TABLE IF EXISTS `tb_course`;

CREATE TABLE `tb_course` (
  `c_id` varchar(32) NOT NULL COMMENT '课程ID',
  `cname` varchar(50) DEFAULT NULL COMMENT '课程名称',
  `desc` varchar(100) DEFAULT NULL COMMENT '课程描述',
  PRIMARY KEY (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert  into `tb_course`(`c_id`,`cname`,`desc`) values ('c001','Java基础','JavaSE所有课程'),('c002','JavaWeb','Java Web 所有课程'),('c003','SSM','Spring Mvc、Spring、MyBatis所有课程');


DROP TABLE IF EXISTS `tb_student`;

CREATE TABLE `tb_student` (
  `s_id` varchar(32) NOT NULL COMMENT '学生ID',
  `sname` varchar(50) DEFAULT NULL COMMENT '姓名',
  `age` int(11) DEFAULT NULL COMMENT '年龄',
  `birthday` datetime DEFAULT NULL COMMENT '生日',
  `gender` char(1) DEFAULT NULL COMMENT '性别',
  `c_id` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`s_id`),
  KEY `c_id` (`c_id`),
  CONSTRAINT `tb_student_ibfk_1` FOREIGN KEY (`c_id`) REFERENCES `tb_class` (`c_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert  into `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`) values ('c002','李四',11,'2022-03-01 00:00:00','1','c001'),('cs001','张四',120,'2022-03-10 00:00:00','1','c001'),('s001','张三',12,'2022-03-21 00:00:00','0','c001'),('s0019','艾念超',88,'2022-02-11 00:00:00','0','c009'),('s002','钱四',19,'2001-05-16 00:00:00','1','c001'),('s003','gt',12,'2022-03-22 00:00:00','1','c002'),('s004','李三',19,'2001-04-14 00:00:00','0','c002'),('s0090','anc1',19,'2022-03-01 00:00:00','1','c002'),('s2202','anc',12,'2022-04-04 00:00:00','1','c009'),('s2222','艾念超',1212,'2022-03-22 00:00:00','1','c009');

DROP TABLE IF EXISTS `tb_student_course`;

CREATE TABLE `tb_student_course` (
  `s_id` varchar(32) NOT NULL DEFAULT '' COMMENT '学生ID',
  `c_id` varchar(32) NOT NULL DEFAULT '' COMMENT '课程ID',
  `score` double DEFAULT NULL,
  PRIMARY KEY (`s_id`,`c_id`),
  KEY `c_id` (`c_id`),
  CONSTRAINT `tb_student_course_ibfk_2` FOREIGN KEY (`c_id`) REFERENCES `tb_course` (`c_id`),
  CONSTRAINT `tb_student_course_ibfk_1` FOREIGN KEY (`s_id`) REFERENCES `tb_student` (`s_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


insert  into `tb_student_course`(`s_id`,`c_id`,`score`) values ('c002','c002',NULL),('c002','c003',NULL),('s001','c001',100),('s001','c002',95),('s001','c003',NULL),('s002','c001',100),('s002','c002',95),('s002','c003',100),('s003','c001',80),('s003','c002',NULL);

2.2.2、分页、条件查询后端实现

  • 步骤

    • 创建javabean
    • 创建mapper
    • 创建service
      • 分页条件查询
      • 选课信息和班级的赋值
    • 创建controller 接收请求和返回
  • JavaBean

    Student.class 学生类

    package com.czxy.domain;
    
    import com.fasterxml.jackson.annotation.JsonFormat;
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import javax.persistence.Transient;
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.stream.Collectors;
    
    @Data
    @Table(name = "tb_student")
    public class Student {
    
        @Id
        @Column(name = "s_id")
        private String sid;
    
        private String sname;
    
        private Integer age;
    
        @JsonFormat(pattern = "yyyy-MM-dd",timezone = "GMT+8")
        private Date birthday;
    
        private String gender;
    
        @Column(name = "c_id")
        private String cid;
    
        @Transient //不进行查询
        private Classes classes; //学生的所在班级
    
        @Transient
        private List<Course> courseList = new ArrayList<>(); //学生选课列表
    
        @Transient
        private List<String> courseIds = new ArrayList<>(); //选课id列表
    
        public void setCourseList(List<Course> courseList) {
            this.courseList = courseList;
            //给选课id赋值
            this.courseIds = courseList.stream().map(course -> course.getCid()).collect(Collectors.toList());
        }
    }
    

    course类 选课类

    package com.czxy.domain;
    
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Data
    @Table(name = "tb_course")
    public class Course {
        @Id
        @Column(name = "c_id")
        private String cid;
    
        private String cname;
    
        @Column(name = "`desc`")
        private String desc;
    }
    

    StudentVo 分页、条件参数封装类

    package com.czxy.vo;
    
    import lombok.Data;
    
    //条件查询的封装对象
    @Data
    public class StudentVo {
    
        private String cid; //班级编号
    
        private String sname; //模糊查询学生名
    
        private String startAge; //年龄范围
    
        private String endAge; //年龄范围
    
        private Integer pageNum = 1; //页数
    
        private Integer pageSize = 3; //一页显示多少条
    }
    
  • StudentController类

    package com.czxy.controller;
    
    import com.czxy.domain.Student;
    import com.czxy.service.StudentService;
    import com.czxy.vo.BaseResult;
    import com.czxy.vo.StudentVo;
    import com.github.pagehelper.PageInfo;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    
    @RestController
    @RequestMapping("/student")
    @CrossOrigin //跨域
    public class StudentController {
        @Resource
        private StudentService service;
    
        /**
         * 分页、条件查询
         * @param vo 分页、条件参数
         * @return 分页对象
         */
        @PostMapping("/condition")
        public BaseResult<PageInfo<Student>> condition(@RequestBody StudentVo vo){
            try {
                PageInfo<Student> pageInfo = service.condition(vo);
                return BaseResult.ok("查询成功",pageInfo);
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("查询失败");
            }
        }
    }
    
  • service

    接口

    package com.czxy.service;
    
    import com.czxy.domain.Student;
    import com.czxy.vo.StudentVo;
    import com.github.pagehelper.PageInfo;
    
    public interface StudentService {
        /**
         * 条件查询
         * @param vo 查询参数
         * @return
         */
        PageInfo<Student> condition(StudentVo vo);
    }
    

    实现类

    package com.czxy.service.impl;
    
    import com.czxy.domain.Classes;
    import com.czxy.domain.Course;
    import com.czxy.domain.Student;
    import com.czxy.mapper.ClassesMapper;
    import com.czxy.mapper.CourseMapper;
    import com.czxy.mapper.StudentMapper;
    import com.czxy.service.StudentService;
    import com.czxy.vo.StudentVo;
    import com.github.pagehelper.PageHelper;
    import com.github.pagehelper.PageInfo;
    import org.apache.commons.lang3.StringUtils;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import tk.mybatis.mapper.entity.Example;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @Service
    @Transactional
    public class StudentServiceImpl implements StudentService {
    
        @Resource
        private StudentMapper studentMapper; //学生mapper
    
        @Resource
        private ClassesMapper classesMapper; //班级mapper
    
        @Resource
        private CourseMapper courseMapper; //选课mapper
    
        @Override
        public PageInfo<Student> condition(StudentVo vo) {
            // 设置分页信息
            PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
    
            // 拼接参数
            Example example = new Example(Student.class);
            Example.Criteria criteria = example.createCriteria();
    
            // 如果vo中的条件存在则添加条件
            // StringUtils.isNotBlank 参数不为null和空字符串 返回true
            if (StringUtils.isNotBlank(vo.getCid())){
                criteria.andEqualTo("cid",vo.getCid());
            }
            if (StringUtils.isNotBlank(vo.getSname())){
                //模糊查询
                criteria.andLike("sname","%"+vo.getSname()+"%");
            }
            if (StringUtils.isNotBlank(vo.getStartAge())){
                // 年龄大于startAge
                criteria.andGreaterThanOrEqualTo("age",vo.getStartAge());
            }
            if (StringUtils.isNotBlank(vo.getEndAge())){
                // 年龄大于endAge
                criteria.andLessThanOrEqualTo("age",vo.getEndAge());
            }
    
            List<Student> list = studentMapper.selectByExample(example);
    
            // 添加班级 和 选课信息
            list.forEach(student -> {
                // 根据id查询班级 给学生添加班级
                Classes classes = classesMapper.selectByPrimaryKey(student.getCid());
                student.setClasses(classes);
    
                // 查询学生选课信息
                List<Course> courseList = courseMapper.selectBySid(student.getSid());
                student.setCourseList(courseList);
    
            });
    
            return new PageInfo<>(list);
    
        }
    }
    
  • mapper

    • StudentMapper类

      package com.czxy.mapper;
      
      
      import com.czxy.domain.Student;
      import tk.mybatis.mapper.common.Mapper;
      
      @org.apache.ibatis.annotations.Mapper
      public interface StudentMapper extends Mapper<Student> {
      }
      
    • CourseMapper类

      package com.czxy.mapper;
      
      import com.czxy.domain.Course;
      import org.apache.ibatis.annotations.Param;
      import org.apache.ibatis.annotations.Result;
      import org.apache.ibatis.annotations.Results;
      import org.apache.ibatis.annotations.Select;
      import tk.mybatis.mapper.common.Mapper;
      
      import java.util.List;
      
      @org.apache.ibatis.annotations.Mapper
      public interface CourseMapper extends Mapper<Course> {
          /**
           * 根据学生id查询选课
           * @param sid 学生id
           * @return
           */
          @Select("select c.* from tb_course c,tb_student_course sc where c.c_id = sc.c_id and sc.s_id = #{id}")
          @Results(value = {
                  //给cid映射
                  @Result(property = "cid",column = "c_id",id = true)
          })
          List<Course> selectBySid(@Param("id") String sid);
      }
      

2.2.3、分页、条件查询前端实现

  • 步骤

    • 创建stuList.vue,并添加路由
    • 编写表单
    • 编写分页条
    • 编写条件查询表单
  • 创建页面,添加路由

在这里插入图片描述

  • 编写表格

    <template>
        <div>
    <!--      表格start  -->
            <el-table :data="pageInfo.list" border stripe style="width: 100%">
                <el-table-column type="selection" min-width="55"></el-table-column>
                <el-table-column prop="sid" label="学生编号" min-width="180"></el-table-column>
                <el-table-column prop="sname" label="姓名" min-width="180"></el-table-column>
                <el-table-column  label="班级" min-width="180">
                    <template slot-scope="scope">
                        {{scope.row.classes?scope.row.classes.cname:''}}
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="年龄" min-width="120"></el-table-column>
                <el-table-column prop="birthday" label="生日" min-width="180"></el-table-column>
                <el-table-column  label="性别" min-width="120">
                    <template slot-scope="scope">
                        {{scope.row.gender==1?'男':scope.row.gender==0?'女':''}}
                    </template>
                </el-table-column>
                <el-table-column label="选课" min-width="250">
                    <template slot-scope="scope">
                        <el-tag v-for="(item,index) in scope.row.courseList" :key="index">{{item.cname}}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="操作" min-width="180">
                    <template slot-scope="scope">
                        <el-button>修改</el-button>
                        <el-button type="danger">删除</el-button>
                    </template>
                </el-table-column>
    
    
            </el-table>
    <!--      表格end  -->
        </div>
    </template>
    
    <script>
        export default {
            name: "StuList",
            data(){
                return{
                    studentVo:{ //查询条件
                        pageNum:1, //默认页数和每页显示多少条
                        pageSize:3
                    },
                    pageInfo:{}, //分页对象
                }
            },
            methods:{
                async condition(num){
                    //给页数赋值
                    if (num){
                        this.studentVo.pageNum = num;
                    }
                    // 发送ajax获取分页对象
                    let {data} = await this.axios.post('http://localhost:8081/student/condition',this.studentVo);
                    if (data.code==20000){
                        this.pageInfo = data.data;
                    }
                }
            },
            mounted(){
                this.condition();
            }
        }
    </script>
    
    <style scoped>
        .el-tag {
            margin-right: 10px;
        }
    </style>
    

    效果

在这里插入图片描述

  • 编写分页条

    template部分

    <!--     分页条start   -->
            <el-pagination
                    background
                    @size-change="handleSizeChange"
                    @current-change="condition"
                    :current-page="pageInfo.pageNum"
                    :page-sizes="[1, 2, 3, 5,10]"
                    :page-size="pageInfo.pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="pageInfo.total">
            </el-pagination>
    <!--     分页条end   -->
    

    methods部分

    handleSizeChange(size){ // 改变一页显示多少条
        this.studentVo.pageSize = size;
        //改变页数并且跳转到第一页
        this.condition(1);
    }
    

    完整版

    <template>
        <div>
    <!--      表格start  -->
            <el-table :data="pageInfo.list" border stripe style="width: 100%">
                <el-table-column type="selection" min-width="55"></el-table-column>
                <el-table-column prop="sid" label="学生编号" min-width="180"></el-table-column>
                <el-table-column prop="sname" label="姓名" min-width="180"></el-table-column>
                <el-table-column  label="班级" min-width="180">
                    <template slot-scope="scope">
                        {{scope.row.classes?scope.row.classes.cname:''}}
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="年龄" min-width="120"></el-table-column>
                <el-table-column prop="birthday" label="生日" min-width="180"></el-table-column>
                <el-table-column  label="性别" min-width="120">
                    <template slot-scope="scope">
                        {{scope.row.gender==1?'男':scope.row.gender==0?'女':''}}
                    </template>
                </el-table-column>
                <el-table-column label="选课" min-width="250">
                    <template slot-scope="scope">
                        <el-tag v-for="(item,index) in scope.row.courseList" :key="index">{{item.cname}}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="操作" min-width="180">
                    <template slot-scope="scope">
                        <el-button>修改</el-button>
                        <el-button type="danger">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
    <!--      表格end  -->
    
    <!--     分页条start   -->
            <el-pagination
                    background
                    @size-change="handleSizeChange"
                    @current-change="condition"
                    :current-page="pageInfo.pageNum"
                    :page-sizes="[1, 2, 3, 5,10]"
                    :page-size="pageInfo.pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="pageInfo.total">
            </el-pagination>
    <!--     分页条end   -->
        </div>
    </template>
    
    <script>
        export default {
            name: "StuList",
            data(){
                return{
                    studentVo:{ //查询条件
                        pageNum:1, //默认页数和每页显示多少条
                        pageSize:3
                    },
                    pageInfo:{}, //分页对象
                }
            },
            methods:{
                async condition(num){
                    //给页数赋值
                    if (num){
                        this.studentVo.pageNum = num;
                    }
                    // 发送ajax获取分页对象
                    let {data} = await this.axios.post('http://localhost:8081/student/condition',this.studentVo);
                    if (data.code==20000){
                        this.pageInfo = data.data;
                    }
                },
                handleSizeChange(size){ // 改变一页显示多少条
                    this.studentVo.pageSize = size;
                    //改变页数并且跳转到第一页
                    this.condition(1);
                }
            },
            mounted(){
                this.condition();
            }
        }
    </script>
    
    <style scoped>
        .el-tag {
            margin-right: 10px;
        }
    </style>
    
  • 编写表单

    <!--     条件查询表单start   -->
            <el-form inline :model="studentVo" class="demo-form-inline">
                <el-form-item label="班级">
                    <el-select v-model="studentVo.cid" placeholder="请选择班级" clearable>
                        <el-option v-for="(item,index) in classList" :key="index" :label="item.cname" :value="item.cid" ></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="学生姓名">
                    <el-input v-model="studentVo.sname" placeholder="请输入姓名" clearable></el-input>
                </el-form-item>
                <el-form-item label="年龄">
                    <el-col :span="11">
                        <el-input type="number" placeholder="请输入开始年龄" v-model="studentVo.startAge"  clearable></el-input>
                    </el-col>
                    <el-col class="line" :span="2" style="text-align: center">-</el-col>
                    <el-col :span="11">
                        <el-input type="number" placeholder="请输入结束年龄" v-model="studentVo.endAge"  clearable></el-input>
                    </el-col>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="condition(1)">查询</el-button>
                </el-form-item>
            </el-form>
    <!--     条件查询表单end   -->
    

    完整版

    <template>
        <div>
    <!--     条件查询表单start   -->
            <el-form inline :model="studentVo" class="demo-form-inline">
                <el-form-item label="班级">
                    <el-select v-model="studentVo.cid" placeholder="请选择班级" clearable>
                        <el-option v-for="(item,index) in classList" :key="index" :label="item.cname" :value="item.cid" ></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="学生姓名">
                    <el-input v-model="studentVo.sname" placeholder="请输入姓名" clearable></el-input>
                </el-form-item>
                <el-form-item label="年龄">
                    <el-col :span="11">
                        <el-input type="number" placeholder="请输入开始年龄" v-model="studentVo.startAge"  clearable></el-input>
                    </el-col>
                    <el-col class="line" :span="2" style="text-align: center">-</el-col>
                    <el-col :span="11">
                        <el-input type="number" placeholder="请输入结束年龄" v-model="studentVo.endAge"  clearable></el-input>
                    </el-col>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="condition(1)">查询</el-button>
                </el-form-item>
            </el-form>
    <!--     条件查询表单end   -->
    
    
    <!--      表格start  -->
            <el-table :data="pageInfo.list" border stripe style="width: 100%">
                <el-table-column type="selection" min-width="55"></el-table-column>
                <el-table-column prop="sid" label="学生编号" min-width="180"></el-table-column>
                <el-table-column prop="sname" label="姓名" min-width="180"></el-table-column>
                <el-table-column  label="班级" min-width="180">
                    <template slot-scope="scope">
                        {{scope.row.classes?scope.row.classes.cname:''}}
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="年龄" min-width="120"></el-table-column>
                <el-table-column prop="birthday" label="生日" min-width="180"></el-table-column>
                <el-table-column  label="性别" min-width="120">
                    <template slot-scope="scope">
                        {{scope.row.gender==1?'男':scope.row.gender==0?'女':''}}
                    </template>
                </el-table-column>
                <el-table-column label="选课" min-width="250">
                    <template slot-scope="scope">
                        <el-tag v-for="(item,index) in scope.row.courseList" :key="index">{{item.cname}}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="操作" min-width="180">
                    <template slot-scope="scope">
                        <el-button>修改</el-button>
                        <el-button type="danger">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
    <!--      表格end  -->
    
    <!--     分页条start   -->
            <el-pagination
                    background
                    @size-change="handleSizeChange"
                    @current-change="condition"
                    :current-page="pageInfo.pageNum"
                    :page-sizes="[1, 2, 3, 5,10]"
                    :page-size="pageInfo.pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="pageInfo.total">
            </el-pagination>
    <!--     分页条end   -->
        </div>
    </template>
    
    <script>
        export default {
            name: "StuList",
            data(){
                return{
                    studentVo:{ //查询条件
                        pageNum:1, //默认页数和每页显示多少条
                        pageSize:3
                    },
                    pageInfo:{}, //分页对象
                    classList:[], // 班级列表
                }
            },
            methods:{
                async condition(num){
                    //给页数赋值
                    if (num){
                        this.studentVo.pageNum = num;
                    }
                    // 发送ajax获取分页对象
                    let {data} = await this.axios.post('http://localhost:8081/student/condition',this.studentVo);
                    if (data.code==20000){
                        this.pageInfo = data.data;
                    }
                },
                handleSizeChange(size){ // 改变一页显示多少条
                    this.studentVo.pageSize = size;
                    //改变页数并且跳转到第一页
                    this.condition(1);
                },
                async selectClassList(){ // 查询班级列表
                    let {data} = await this.axios.get(`http://localhost:8081/class`);
                    if (data.code==20000){
                        this.classList = data.data;
                    }
                }
            },
            mounted(){
                this.condition();
                this.selectClassList();
            }
        }
    </script>
    
    <style scoped>
        .el-tag {
            margin-right: 10px;
        }
    </style>
    

2.2.4、增删改后端实现

  • StudentCourse类

    添加学生和修改学生选课信息操作从sql表

    package com.czxy.domain;
    
    import lombok.Data;
    
    import javax.persistence.Column;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    @Data
    @Table(name = "tb_student_course")
    public class StudentCourse {
        @Id
        @Column(name = "s_id")
        private String sid;
    
        @Column(name = "c_id")
        private String cid;
    
        private Double score;
    }
    
  • StudentCourseMapper类

    package com.czxy.mapper;
    
    import com.czxy.domain.StudentCourse;
    import org.apache.ibatis.annotations.Mapper;
    
    @Mapper
    public interface StudentCourseMapper extends tk.mybatis.mapper.common.Mapper<StudentCourse> {
    }
    
  • StudentController类

    package com.czxy.controller;
    
    import com.czxy.domain.Student;
    import com.czxy.service.StudentService;
    import com.czxy.vo.BaseResult;
    import com.czxy.vo.StudentVo;
    import com.github.pagehelper.PageInfo;
    import org.springframework.web.bind.annotation.*;
    
    import javax.annotation.Resource;
    
    @RestController
    @RequestMapping("/student")
    @CrossOrigin
    public class StudentController {
        @Resource
        private StudentService service;
    
        /**
         * 分页、条件查询
         * @param vo 分页、条件参数
         * @return 分页对象
         */
        @PostMapping("/condition")
        public BaseResult<PageInfo<Student>> condition(@RequestBody StudentVo vo){
            try {
                PageInfo<Student> pageInfo = service.condition(vo);
                return BaseResult.ok("查询成功",pageInfo);
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("查询失败");
            }
        }
    
        /**
         * 根据学生id查询详情
         * @param id 学生id
         * @return
         */
        @GetMapping("/{id}")
        public BaseResult<Student> selectById(@PathVariable("id") String id){
            try {
                Student student = service.selectById(id);
                return BaseResult.ok("查询成功",student);
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("查询失败");
            }
        }
    
        /**
         * 添加或者更新
         * @param student 添加或者更新的学生对象
         * @return
         */
        @PostMapping("/insertOrUpdate")
        public BaseResult insertOrUpdate(@RequestBody Student student){
            try {
                boolean result = service.insertOrUpdate(student);
                if (result){
                    return BaseResult.ok("编辑成功");
                }else {
                    return BaseResult.error("编辑失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("编辑失败");
            }
        }
    
        /**
         * 根据id删除学生
         * @param id 学生id
         * @return
         */
        @DeleteMapping("/{id}")
        public BaseResult delById(@PathVariable("id") String id){
            try {
                boolean result = service.delById(id);
                if (result){
                    return BaseResult.ok("删除成功");
                }else {
                    return BaseResult.error("删除失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
                return BaseResult.error("删除失败");
            }
        }
    }
    
  • service

    • 接口

      package com.czxy.service;
      
      import com.czxy.domain.Student;
      import com.czxy.vo.StudentVo;
      import com.github.pagehelper.PageInfo;
      
      public interface StudentService {
          /**
           * 条件查询
           * @param vo 查询参数
           * @return
           */
          PageInfo<Student> condition(StudentVo vo);
      
          /**
           * 根据学生id查询详情
           * @param id 学生id
           * @return
           */
          Student selectById(String id);
      
          /**
           * 添加或者更新
           * @param student 添加或者更新的学生对象
           * @return
           */
          boolean insertOrUpdate(Student student);
      
          /**
           * 根据学生id删除
           * @param id 学生id
           * @return
           */
          boolean delById(String id);
      }
      

      实现类

      package com.czxy.service.impl;
      
      import com.czxy.domain.Classes;
      import com.czxy.domain.Course;
      import com.czxy.domain.Student;
      import com.czxy.domain.StudentCourse;
      import com.czxy.mapper.ClassesMapper;
      import com.czxy.mapper.CourseMapper;
      import com.czxy.mapper.StudentCourseMapper;
      import com.czxy.mapper.StudentMapper;
      import com.czxy.service.StudentService;
      import com.czxy.vo.StudentVo;
      import com.github.pagehelper.PageHelper;
      import com.github.pagehelper.PageInfo;
      import org.apache.commons.lang3.StringUtils;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      import tk.mybatis.mapper.entity.Example;
      
      import javax.annotation.Resource;
      import java.util.List;
      
      @Service
      @Transactional
      public class StudentServiceImpl implements StudentService {
      
          @Resource
          private StudentMapper studentMapper; //学生mapper
      
          @Resource
          private ClassesMapper classesMapper; //班级mapper
      
          @Resource
          private CourseMapper courseMapper; //选课mapper
      
          @Resource
          private StudentCourseMapper studentCourseMapper; // 学生和选课关联表
      
          @Override
          public PageInfo<Student> condition(StudentVo vo) {
              // 设置分页信息
              PageHelper.startPage(vo.getPageNum(),vo.getPageSize());
      
              // 拼接参数
              Example example = new Example(Student.class);
              Example.Criteria criteria = example.createCriteria();
      
              // 如果vo中的条件存在则添加条件
              // StringUtils.isNotBlank 参数不为null和空字符串 返回true
              if (StringUtils.isNotBlank(vo.getCid())){
                  criteria.andEqualTo("cid",vo.getCid());
              }
              if (StringUtils.isNotBlank(vo.getSname())){
                  //模糊查询
                  criteria.andLike("sname","%"+vo.getSname()+"%");
              }
              if (StringUtils.isNotBlank(vo.getStartAge())){
                  // 年龄大于startAge
                  criteria.andGreaterThanOrEqualTo("age",vo.getStartAge());
              }
              if (StringUtils.isNotBlank(vo.getEndAge())){
                  // 年龄大于endAge
                  criteria.andLessThanOrEqualTo("age",vo.getEndAge());
              }
      
              List<Student> list = studentMapper.selectByExample(example);
      
              // 添加班级 和 选课信息
              list.forEach(student -> {
                  // 根据id查询班级 给学生添加班级
                  Classes classes = classesMapper.selectByPrimaryKey(student.getCid());
                  student.setClasses(classes);
      
                  // 查询学生选课信息
                  List<Course> courseList = courseMapper.selectBySid(student.getSid());
                  student.setCourseList(courseList);
      
              });
      
              return new PageInfo<>(list);
      
          }
      
          @Override
          public Student selectById(String id) {
              Student student = studentMapper.selectByPrimaryKey(id);
              // 根据id查询班级 给学生添加班级
              Classes classes = classesMapper.selectByPrimaryKey(student.getCid());
              student.setClasses(classes);
      
              // 查询学生选课信息
              List<Course> courseList = courseMapper.selectBySid(student.getSid());
              student.setCourseList(courseList);
      
              return student;
          }
      
          @Override
          public boolean insertOrUpdate(Student student) {
              Student temp = studentMapper.selectByPrimaryKey(student.getSid());
              // temp不存在则添加,存在则修改
              int result = 0;
              if (temp == null){
                  result = studentMapper.insertSelective(student);
              }else {
                  result = studentMapper.updateByPrimaryKeySelective(student);
                  // 对学生选课进行修改 ,先删除所有的课程,然后在添加
                  studentCourseMapper.deleteByPrimaryKey(student.getSid());
              }
      
              student.getCourseIds().forEach(id->{
                  StudentCourse sc = new StudentCourse();
                  sc.setSid(student.getSid());
                  sc.setCid(id);
                  studentCourseMapper.insertSelective(sc);
              });
      
              return result == 1;
          }
      
          @Override
          public boolean delById(String id) {
              int i = studentMapper.deleteByPrimaryKey(id);
              return i==1;
          }
      }
      
      
查询所有课程
  • CourseController
package com.czxy.controller;

import com.czxy.domain.Course;
import com.czxy.service.CourseService;
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;

@RestController
@RequestMapping("/course")
@CrossOrigin
public class CourseController {

    @Resource
    private CourseService service;


    @GetMapping
    public BaseResult<List<Course>> selectAll(){
        try {
            List<Course> list = service.selectAll();
            return BaseResult.ok("查询成功",list);
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.error("查询失败");
        }
    }
}
  • service

    接口

    package com.czxy.service;
    
    import com.czxy.domain.Course;
    
    import java.util.List;
    
    public interface CourseService {
        /**
         * 查询所有课程
         * @return
         */
        List<Course> selectAll();
    }
    

    实现 类

    package com.czxy.service.impl;
    
    import com.czxy.domain.Course;
    import com.czxy.mapper.CourseMapper;
    import com.czxy.service.CourseService;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @Service
    @Transactional
    public class CourseServiceImpl implements CourseService {
    
        @Resource
        private CourseMapper courseMapper;
    
    
        @Override
        public List<Course> selectAll() {
            return courseMapper.selectAll();
        }
    }
    

2.2.5、增删改前端实现

  • 删除

    在表格的删除按钮绑定del方法

在这里插入图片描述

methods区域

async del(id){
    this.$confirm('您确定要删除吗', '删除操作', {
        type: 'warning'
    }).then(async () => {
        // 调用后端的删除方法
       let {data} = await this.axios.delete(`http://localhost:8081/student/${id}`);
       if (data.code==20000){
           // 成功提示 及重载表格
           this.$message.success(data.message);
           this.condition(1);
       } else {
           this.$message.error(data.message);
       }
    }).catch(() => {
        this.$message.info('取消删除成功')
    });
}
  • 修改和添加

    <template>
        <div>
    <!--     条件查询表单start   -->
            <el-form inline :model="studentVo" class="demo-form-inline">
                <el-form-item label="班级">
                    <el-select v-model="studentVo.cid" placeholder="请选择班级" clearable>
                        <el-option v-for="(item,index) in classList" :key="index" :label="item.cname" :value="item.cid" ></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="学生姓名">
                    <el-input v-model="studentVo.sname" placeholder="请输入姓名" clearable></el-input>
                </el-form-item>
                <el-form-item label="年龄">
                    <el-col :span="11">
                        <el-input type="number" placeholder="请输入开始年龄" v-model="studentVo.startAge"  clearable></el-input>
                    </el-col>
                    <el-col class="line" :span="2" style="text-align: center">-</el-col>
                    <el-col :span="11">
                        <el-input type="number" placeholder="请输入结束年龄" v-model="studentVo.endAge"  clearable></el-input>
                    </el-col>
                </el-form-item>
                <el-form-item>
                    <el-button type="primary" @click="condition(1)">查询</el-button>
                </el-form-item>
            </el-form>
    <!--     条件查询表单end   -->
    
    <!--    添加学生按钮    -->
            <el-button type="primary" @click="addView">添加学生</el-button>
    
    
    <!--    添加和更新的对话框 start   -->
            <el-dialog :title="dialogTitle==0?'添加班级':'修改班级'" width="600px" :visible.sync="studentDialogFormVisible">
                <el-form :model="student" :rules="dialogTitle==0?rules:{}" label-width="80px" ref="studentFrom">
    
                    <el-form-item label="学生编号" prop="sid" >
                        <el-input v-model="student.sid" placeholder="请输入学生编号" :disabled="dialogTitle==1"></el-input>
                    </el-form-item>
                    <el-form-item label="学生姓名">
                        <el-input v-model="student.sname" placeholder="请输入姓名"></el-input>
                    </el-form-item>
                    <el-form-item label="班级">
                        <el-select v-model="student.cid" placeholder="请选择班级" clearable>
                            <el-option v-for="(item,index) in classList" :key="index" :label="item.cname"  :value="item.cid"></el-option>
                        </el-select>
                    </el-form-item>
                    <el-form-item label="年龄">
                        <el-input v-model="student.age" placeholder="请输入年龄" type="number"></el-input>
                    </el-form-item>
                    <el-form-item label="生日">
                        <el-date-picker type="date" placeholder="选择生日" v-model="student.birthday"  value-format="yyyy-MM-dd"></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 :label="item.cid" v-for="(item,index) in courseList" :key="index">{{item.cname}}</el-checkbox>
                        </el-checkbox-group>
                    </el-form-item>
                </el-form>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="studentDialogFormVisible = false">取 消</el-button>
                    <el-button type="primary" @click="insertOrUpdate">确 定</el-button>
                </div>
            </el-dialog>
    <!--    添加和更新的对话框 end   -->
    
    <!--      表格start  -->
            <el-table :data="pageInfo.list" border stripe style="width: 100%">
                <el-table-column type="selection" min-width="55"></el-table-column>
                <el-table-column prop="sid" label="学生编号" min-width="180"></el-table-column>
                <el-table-column prop="sname" label="姓名" min-width="180"></el-table-column>
                <el-table-column  label="班级" min-width="180">
                    <template slot-scope="scope">
                        {{scope.row.classes?scope.row.classes.cname:''}}
                    </template>
                </el-table-column>
                <el-table-column prop="age" label="年龄" min-width="120"></el-table-column>
                <el-table-column prop="birthday" label="生日" min-width="180"></el-table-column>
                <el-table-column  label="性别" min-width="120">
                    <template slot-scope="scope">
                        {{scope.row.gender==1?'男':scope.row.gender==0?'女':''}}
                    </template>
                </el-table-column>
                <el-table-column label="选课" min-width="250">
                    <template slot-scope="scope">
                        <el-tag v-for="(item,index) in scope.row.courseList" :key="index">{{item.cname}}</el-tag>
                    </template>
                </el-table-column>
                <el-table-column label="操作" min-width="180">
                    <template slot-scope="scope">
                        <el-button @click="editView(scope.row.sid)">修改</el-button>
                        <el-button type="danger" @click="del(scope.row.sid)">删除</el-button>
                    </template>
                </el-table-column>
            </el-table>
    <!--      表格end  -->
    
    <!--     分页条start   -->
            <el-pagination
                    background
                    @size-change="handleSizeChange"
                    @current-change="condition"
                    :current-page="pageInfo.pageNum"
                    :page-sizes="[1, 2, 3, 5,10]"
                    :page-size="pageInfo.pageSize"
                    layout="total, sizes, prev, pager, next, jumper"
                    :total="pageInfo.total">
            </el-pagination>
    <!--     分页条end   -->
        </div>
    </template>
    
    <script>
        export default {
            name: "StuList",
            data(){
                var sidValidator = async (rule,value,callback)=>{
                    let {data} = await this.axios.get(`http://localhost:8081/student/${value}`);
                    if (data.code==20000&&data.data){
                        callback(new Error('学生编号以存在,请重新输入'))
                    }
                    callback()
                };
                return{
                    studentVo:{ //查询条件
                        pageNum:1, //默认页数和每页显示多少条
                        pageSize:3
                    },
                    pageInfo:{}, //分页对象
                    classList:[], // 班级列表
                    dialogTitle:0, // 对话框标题
                    studentDialogFormVisible:false, // 对话框是否显隐
                    student:{}, // 对话框表单绑定的对象
                    courseList:[], // 所有课程
                    rules:{ // 添加的校验规则
                        sid:[
                            {required:true,message:'请输入学生编号',trigger:"blur"},
                            {validator:sidValidator,trigger:"blur"}
                        ]
                    },
                }
            },
            methods:{
                async condition(num){
                    //给页数赋值
                    if (num){
                        this.studentVo.pageNum = num;
                    }
                    // 发送ajax获取分页对象
                    let {data} = await this.axios.post('http://localhost:8081/student/condition',this.studentVo);
                    if (data.code==20000){
                        this.pageInfo = data.data;
                    }
                },
                handleSizeChange(size){ // 改变一页显示多少条
                    this.studentVo.pageSize = size;
                    //改变页数并且跳转到第一页
                    this.condition(1);
                },
                async selectClassList(){ // 查询班级列表
                    let {data} = await this.axios.get(`http://localhost:8081/class`);
                    if (data.code==20000){
                        this.classList = data.data;
                    }
                },
                async del(id){
                    this.$confirm('您确定要删除吗', '删除操作', {
                        type: 'warning'
                    }).then(async () => {
                        // 调用后端的删除方法
                       let {data} = await this.axios.delete(`http://localhost:8081/student/${id}`);
                       if (data.code==20000){
                           // 成功提示 及重载表格
                           this.$message.success(data.message);
                           this.condition(1);
                       } else {
                           this.$message.error(data.message);
                       }
                    }).catch(() => {
                        this.$message.info('取消删除成功')
                    });
                },
                async editView(id){ //修改学生的页面
                    //清除提示错误的样式
                    if (this.$refs.studentFrom) {
                        this.$refs.studentFrom.resetFields();
                    }
                    //更新班级列表
                    this.selectClassList();
                    // 获取所有课程
                    this.selectCourseList();
                    let {data} = await this.axios.get(`http://localhost:8081/student/${id}`);
                    // 根据id查询 查询成功将对话框显示出来,并给student对象赋值
                    if (data.code==20000){
                        this.student = data.data;
                        this.studentDialogFormVisible = true;
                        //设置对话框的标题
                        this.dialogTitle = 1;
                    }
                },
                addView(){ //添加页面
                    //清空 student对象
                    this.student = {
                        courseIds:[]
                    };
                    this.studentDialogFormVisible = true;
                    //设置对话框的标题
                    this.dialogTitle = 0;
                    //更新班级列表
                    this.selectClassList();
                    // 获取所有课程
                    this.selectCourseList();
                    //清除提示错误的样式
                    if (this.$refs.studentFrom) {
                        this.$refs.studentFrom.resetFields();
                    }
    
                },
                async selectCourseList(){ // 获取所有选课信息
                    let {data} = await this.axios.get(`http://localhost:8081/course`);
                    if (data.code==20000){
                        this.courseList = data.data;
                    }
                },
                insertOrUpdate(){ // 添加或更新方法
                    this.$refs.studentFrom.validate(async (valid) => {
                        if (valid) {
                            // 校验通过调用后端
                            let {data} = await this.axios.post(`http://localhost:8081/student/insertOrUpdate`,this.student);
                            if (data.code==20000){
                                //成功提示,刷新表格
                                this.$message.success(data.message);
                                this.condition(1);
                                //关闭对话框
                                this.studentDialogFormVisible = false;
                            } else {
                                //失败提示
                                this.$message.error(data.message);
                            }
                        } else {
                            return false;
                        }
                    });
                }
            },
            mounted(){
                this.condition();
                this.selectClassList();
            }
        }
    </script>
    
    <style scoped>
        .el-tag {
            margin-right: 10px;
        }
    </style>
    

2.2.6、批量删除

  • 后端实现

    StudentController

    /**
     * 批量删除
     * @param ids 需要删除的学生id集合
     * @return
     */
    @PostMapping("/batch")
    public BaseResult batchDel(List<String> ids){
        try {
            boolean result = service.batchDel(ids);
            if (result){
                return BaseResult.ok("批量删除成功");
            }else {
                return BaseResult.error("批量删除失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.error("批量删除失败");
        }
    }
    

    service

    接口

    /**
     * 根据学生id批量删除
     * @param ids  学生id集合
     * @return
     */
    boolean batchDel(List<String> ids);
    

    实现类

    @Override
    public boolean batchDel(List<String> ids) {
        // 遍历删除学生选课信息
        ids.forEach(id->studentCourseMapper.deleteByPrimaryKey(id));
    
        // 删除学生
        Example example = new Example(Student.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andIn("sid",ids);
    
        // 批量删除
        int i = studentMapper.deleteByExample(example);
    
        return i >= 1;
    }
    
  • 前端实现

在这里插入图片描述

  • methods区域

    handleSelection(val){ // 处理全选数组到ids
        this.ids = this.val.map(item=>item.sid);
    },
    batchDel(){ //批量删除
        this.$confirm(`您确定要删除${this.ids.length}个吗`, '删除操作', {
            type: 'warning'
        }).then(async () => {
            // 调用后端的删除方法
            let {data} = await this.axios.post(`http://localhost:8081/student/batch`,this.ids);
            if (data.code==20000){
                // 成功提示 及重载表格
                this.$message.success(data.message);
                this.condition(1);
            } else {
                this.$message.error(data.message);
            }
        }).catch(() => {
            this.$message.info('取消批量删除成功')
        });
    }
    

在template区域添加一个批量删除按钮

<el-button type="primary" @click="batchDel">批量删除</el-button>

2.2.7、前端页面代码

<template>
    <div>
<!--     条件查询表单start   -->
        <el-form inline :model="studentVo" class="demo-form-inline">
            <el-form-item label="班级">
                <el-select v-model="studentVo.cid" placeholder="请选择班级" clearable>
                    <el-option v-for="(item,index) in classList" :key="index" :label="item.cname" :value="item.cid" ></el-option>
                </el-select>
            </el-form-item>
            <el-form-item label="学生姓名">
                <el-input v-model="studentVo.sname" placeholder="请输入姓名" clearable></el-input>
            </el-form-item>
            <el-form-item label="年龄">
                <el-col :span="11">
                    <el-input type="number" placeholder="请输入开始年龄" v-model="studentVo.startAge"  clearable></el-input>
                </el-col>
                <el-col class="line" :span="2" style="text-align: center">-</el-col>
                <el-col :span="11">
                    <el-input type="number" placeholder="请输入结束年龄" v-model="studentVo.endAge"  clearable></el-input>
                </el-col>
            </el-form-item>
            <el-form-item>
                <el-button type="primary" @click="condition(1)">查询</el-button>
            </el-form-item>
        </el-form>
<!--     条件查询表单end   -->

<!--    添加学生按钮    -->
        <el-button type="primary" @click="addView">添加学生</el-button>

<!--     批量删除按钮   -->
        <el-button type="primary" @click="batchDel">批量删除</el-button>



<!--    添加和更新的对话框 start   -->
        <el-dialog :title="dialogTitle==0?'添加班级':'修改班级'" width="600px" :visible.sync="studentDialogFormVisible">
            <el-form :model="student" :rules="dialogTitle==0?rules:{}" label-width="80px" ref="studentFrom">

                <el-form-item label="学生编号" prop="sid" >
                    <el-input v-model="student.sid" placeholder="请输入学生编号" :disabled="dialogTitle==1"></el-input>
                </el-form-item>
                <el-form-item label="学生姓名">
                    <el-input v-model="student.sname" placeholder="请输入姓名"></el-input>
                </el-form-item>
                <el-form-item label="班级">
                    <el-select v-model="student.cid" placeholder="请选择班级" clearable>
                        <el-option v-for="(item,index) in classList" :key="index" :label="item.cname"  :value="item.cid"></el-option>
                    </el-select>
                </el-form-item>
                <el-form-item label="年龄">
                    <el-input v-model="student.age" placeholder="请输入年龄" type="number"></el-input>
                </el-form-item>
                <el-form-item label="生日">
                    <el-date-picker type="date" placeholder="选择生日" v-model="student.birthday"  value-format="yyyy-MM-dd"></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 :label="item.cid" v-for="(item,index) in courseList" :key="index">{{item.cname}}</el-checkbox>
                    </el-checkbox-group>
                </el-form-item>
            </el-form>
            <div slot="footer" class="dialog-footer">
                <el-button @click="studentDialogFormVisible = false">取 消</el-button>
                <el-button type="primary" @click="insertOrUpdate">确 定</el-button>
            </div>
        </el-dialog>
<!--    添加和更新的对话框 end   -->

<!--      表格start  -->
        <el-table :data="pageInfo.list" border stripe style="width: 100%" @selection-change="handleSelection">
            <el-table-column type="selection" min-width="55"></el-table-column>
            <el-table-column prop="sid" label="学生编号" min-width="180"></el-table-column>
            <el-table-column prop="sname" label="姓名" min-width="180"></el-table-column>
            <el-table-column  label="班级" min-width="180">
                <template slot-scope="scope">
                    {{scope.row.classes?scope.row.classes.cname:''}}
                </template>
            </el-table-column>
            <el-table-column prop="age" label="年龄" min-width="120"></el-table-column>
            <el-table-column prop="birthday" label="生日" min-width="180"></el-table-column>
            <el-table-column  label="性别" min-width="120">
                <template slot-scope="scope">
                    {{scope.row.gender==1?'男':scope.row.gender==0?'女':''}}
                </template>
            </el-table-column>
            <el-table-column label="选课" min-width="250">
                <template slot-scope="scope">
                    <el-tag v-for="(item,index) in scope.row.courseList" :key="index">{{item.cname}}</el-tag>
                </template>
            </el-table-column>
            <el-table-column label="操作" min-width="180">
                <template slot-scope="scope">
                    <el-button @click="editView(scope.row.sid)">修改</el-button>
                    <el-button type="danger" @click="del(scope.row.sid)">删除</el-button>
                </template>
            </el-table-column>
        </el-table>
<!--      表格end  -->

<!--     分页条start   -->
        <el-pagination
                background
                @size-change="handleSizeChange"
                @current-change="condition"
                :current-page="pageInfo.pageNum"
                :page-sizes="[1, 2, 3, 5,10]"
                :page-size="pageInfo.pageSize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="pageInfo.total">
        </el-pagination>
<!--     分页条end   -->
    </div>
</template>

<script>
    export default {
        name: "StuList",
        data(){
            var sidValidator = async (rule,value,callback)=>{
                let {data} = await this.axios.get(`http://localhost:8081/student/${value}`);
                if (data.code==20000&&data.data){
                    callback(new Error('学生编号以存在,请重新输入'))
                }
                callback()
            };
            return{
                studentVo:{ //查询条件
                    pageNum:1, //默认页数和每页显示多少条
                    pageSize:3
                },
                pageInfo:{}, //分页对象
                classList:[], // 班级列表
                dialogTitle:0, // 对话框标题
                studentDialogFormVisible:false, // 对话框是否显隐
                student:{}, // 对话框表单绑定的对象
                courseList:[], // 所有课程
                rules:{ // 添加的校验规则
                    sid:[
                        {required:true,message:'请输入学生编号',trigger:"blur"},
                        {validator:sidValidator,trigger:"blur"}
                    ]
                },
                ids:[], //批量删除的数组
            }
        },
        methods:{
            async condition(num){
                //给页数赋值
                if (num){
                    this.studentVo.pageNum = num;
                }
                // 发送ajax获取分页对象
                let {data} = await this.axios.post('http://localhost:8081/student/condition',this.studentVo);
                if (data.code==20000){
                    this.pageInfo = data.data;
                }
            },
            handleSizeChange(size){ // 改变一页显示多少条
                this.studentVo.pageSize = size;
                //改变页数并且跳转到第一页
                this.condition(1);
            },
            async selectClassList(){ // 查询班级列表
                let {data} = await this.axios.get(`http://localhost:8081/class`);
                if (data.code==20000){
                    this.classList = data.data;
                }
            },
            async del(id){ // 根据id删除学生
                this.$confirm('您确定要删除吗', '删除操作', {
                    type: 'warning'
                }).then(async () => {
                    // 调用后端的删除方法
                   let {data} = await this.axios.delete(`http://localhost:8081/student/${id}`);
                   if (data.code==20000){
                       // 成功提示 及重载表格
                       this.$message.success(data.message);
                       this.condition(1);
                   } else {
                       this.$message.error(data.message);
                   }
                }).catch(() => {
                    this.$message.info('取消删除成功')
                });
            },
            async editView(id){ //修改学生的页面
                //清除提示错误的样式
                if (this.$refs.studentFrom) {
                    this.$refs.studentFrom.resetFields();
                }
                //更新班级列表
                this.selectClassList();
                // 获取所有课程
                this.selectCourseList();
                let {data} = await this.axios.get(`http://localhost:8081/student/${id}`);
                // 根据id查询 查询成功将对话框显示出来,并给student对象赋值
                if (data.code==20000){
                    this.student = data.data;
                    this.studentDialogFormVisible = true;
                    //设置对话框的标题
                    this.dialogTitle = 1;
                }
            },
            addView(){ //添加页面
                //清空 student对象
                this.student = {
                    courseIds:[]
                };
                this.studentDialogFormVisible = true;
                //设置对话框的标题
                this.dialogTitle = 0;
                //更新班级列表
                this.selectClassList();
                // 获取所有课程
                this.selectCourseList();
                //清除提示错误的样式
                if (this.$refs.studentFrom) {
                    this.$refs.studentFrom.resetFields();
                }

            },
            async selectCourseList(){ // 获取所有选课信息
                let {data} = await this.axios.get(`http://localhost:8081/course`);
                if (data.code==20000){
                    this.courseList = data.data;
                }
            },
            insertOrUpdate(){ // 添加或更新方法
                this.$refs.studentFrom.validate(async (valid) => {
                    if (valid) {
                        // 校验通过调用后端
                        let {data} = await this.axios.post(`http://localhost:8081/student/insertOrUpdate`,this.student);
                        if (data.code==20000){
                            //成功提示,刷新表格
                            this.$message.success(data.message);
                            this.condition(1);
                            //关闭对话框
                            this.studentDialogFormVisible = false;
                        } else {
                            //失败提示
                            this.$message.error(data.message);
                        }
                    } else {
                        return false;
                    }
                });
            },
            handleSelection(val){ // 处理全选数组到ids
                this.ids = this.val.map(item=>item.sid);
            },
            batchDel(){ //批量删除
                this.$confirm(`您确定要删除${this.ids.length}个吗`, '删除操作', {
                    type: 'warning'
                }).then(async () => {
                    // 调用后端的删除方法
                    let {data} = await this.axios.post(`http://localhost:8081/student/batch`,this.ids);
                    if (data.code==20000){
                        // 成功提示 及重载表格
                        this.$message.success(data.message);
                        this.condition(1);
                    } else {
                        this.$message.error(data.message);
                    }
                }).catch(() => {
                    this.$message.info('取消批量删除成功')
                });
            }
        },
        mounted(){
            this.condition();
            this.selectClassList();
        }
    }
</script>

<style scoped>
    .el-tag {
        margin-right: 10px;
    }
</style>

2.3、优化

2.3.1、删除班级时,提示信息

  • 后端实现

    ClassController

    /**
     * 根据班级编号查询是否存在学生
     * @param id 班级编号
     * @return
     */
    @GetMapping("/isExist/{id}")
    public BaseResult isExistStudent(@PathVariable("id") String id){
        try {
            boolean result = service.isExistStudent(id);
            System.out.println(result);
            if (!result){
                return BaseResult.ok("查询成功");
            }else {
                return BaseResult.error("该班级存在学生,并删除");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return BaseResult.error("查询失败");
        }
    }
    

    service接口

    /**
     * 根据id查询班级是否存在学生
     * @param id 班级编号
     * @return
     */
    boolean isExistStudent(String id);
    

    service实现类

    @Override
    public boolean isExistStudent(String id) {
        List<Student> list = classesMapper.selectByCid(id);
        if (list!=null && list.size()>0){
            return true;
        }else {
            return false;
        }
    }
    

    mapper

        /**
         * 根据班级编号查询所属学生
         * @param cid 班级编号
         * @return
         */
        @Select("select * from tb_student where c_id = #{id}")
        List<Student> selectByCid(@Param("id") String cid);
    
  • 前端实现

    async del(id){ //删除
        let res = await this.axios.get(`http://localhost:8081/class/isExist/${id}`);
        let tempInfo = '是否删除该班级?';
        if (res.data.code == 0){
            tempInfo = `是否删除该班级,${res.data.message}`
        }
    
        this.$confirm(tempInfo, '删除操作', {
            type: 'warning'
        }).then( () => {
            //ajax删除操作
        }).catch(() => {
            this.$message.info('取消成功')
        });
    }
    

2.3.2、删除班级时,同时删除班级里面存在的学生

  • 后端修改

    CalssesServiceImpl类

    @Override
    public boolean del(String id) {
        // 优化 先删除该班级的学生
        List<Student> list = classesMapper.selectByCid(id);
    
        list.forEach(student -> {
            //遍历删除学生 及学生的课程
            studentService.delById(student.getSid());
        });
    
        int i = classesMapper.deleteByPrimaryKey(id);
        return i==1;
    }
    
  • 前端实现

    async del(id){ //删除
        let res = await this.axios.get(`http://localhost:8081/class/isExist/${id}`);
        let tempInfo = '是否删除该班级?';
        if (res.data.code == 0){
            tempInfo = `是否删除该班级,${res.data.message}`
        }
    
        this.$confirm(tempInfo, '删除操作', {
            type: 'warning'
        }).then(async () => {
            let {data} = await this.axios.delete(`http://localhost:8081/class/${id}`);
            if (data.code==20000){
                // 成功提示及重新查询班级列表
                this.$message.success(data.message);
                this.selectClassList();
            } else {
                this.$message.error(data.message)
            }
        }).catch(() => {
            this.$message.info('取消成功')
        });
    },
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值