前端使用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、判断用户名是否存在的方法
-
分析
- 获取前端发送的用户名
- 与数据库进行交互判断用户名是否存在
- 返回结果
-
实现
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、省市县的查询方法
- 分析
-
步骤
- 编写City类
- 编写CityMapper类 编写查询方法
- 编写CityService接口及实现类
- 编写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('取消成功') }); },