SpringCloud微服务之学生管理

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 RDS MySQL Serverless,价值2615元额度,1个月
简介: SpringCloud微服务之学生管理

1.环境搭建

1.1 架构分析

  • 注册中心:Nacos
  • 网关:Gateway
  • 后端基础框架:ssm
  • 前端:Vue + SPA
  • Axios(request.js)

1.2 数据库环境

1.2.1 学生数据库

#学生数据库
CREATE DATABASE nacos_ssm_student;
USE nacos_ssm_student;
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');
CREATE TABLE `tb_student` (
  `s_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT 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` INT DEFAULT NULL,
  `city_ids` VARCHAR(32) DEFAULT NULL COMMENT '城市:320000,321300,321322'
);
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (1,'赵三33',21,'2001-01-17 00:00:00','1',1,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (2,'钱四444',1900,'2001-05-16 00:00:00','1',2,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (3,'孙五56',189,'2022-03-15 00:00:00','0',1,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (4,'张三',20,'2020-12-21 00:00:00','0',2,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (5,'xxx',18,'2020-12-21 00:00:00','0',2,'140000,140800,140823');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (6,'123',18,'2020-11-01 00:00:00','0',3,'130000,130100,130127');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (7,'xx',18,'2020-11-02 00:00:00','0',1,'130000,131000,131003');

1.2.2 用户数据库

# 用户数据库
CREATE DATABASE nacos_ssm_user;
USE nacos_ssm_user;
CREATE TABLE `tb_user` (
  `u_id` VARCHAR(32) PRIMARY KEY NOT NULL COMMENT '用户编号',
  `user_name` VARCHAR(50) UNIQUE DEFAULT NULL COMMENT '用户名',
  `password` VARCHAR(32) DEFAULT NULL COMMENT '密码',
  `gender` BIT(1) DEFAULT NULL COMMENT '性别,1表示男,0表示女',
  `image` VARCHAR(50) UNIQUE DEFAULT NULL COMMENT '头像图片'
);
INSERT  INTO `tb_user`(`u_id`,`user_name`,`password`,`gender`,`image`) VALUES ('u001','jack','1234',1,'1.jpg');
INSERT  INTO `tb_user`(`u_id`,`user_name`,`password`,`gender`,`image`) VALUES ('u002','rose','1234',0,'2.jpg');
INSERT  INTO `tb_user`(`u_id`,`user_name`,`password`,`gender`,`image`) VALUES ('u003','tom','1234',1,'3.jpg');

1.2.3 班级数据库

# 班级数据库
CREATE DATABASE nacos_ssm_classes;
USE nacos_ssm_classes;
CREATE TABLE `tb_teacher` (
  `tid` INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `tname` VARCHAR(50) DEFAULT NULL COMMENT '老师姓名',
  `type` INT(11) DEFAULT NULL COMMENT '老师类型:1.授课老师、2.助理老师、3.辅导员老师'
);
INSERT  INTO `tb_teacher`(`tid`,`tname`,`type`) VALUES (1,'梁桐老师',1);
INSERT  INTO `tb_teacher`(`tid`,`tname`,`type`) VALUES (2,'马坤老师',2);
INSERT  INTO `tb_teacher`(`tid`,`tname`,`type`) VALUES (3,'仲燕老师',3);
INSERT  INTO `tb_teacher`(`tid`,`tname`,`type`) VALUES (4,'袁新奇老师',1);
INSERT  INTO `tb_teacher`(`tid`,`tname`,`type`) VALUES (5,'任林达老师',2);
INSERT  INTO `tb_teacher`(`tid`,`tname`,`type`) VALUES (6,'王珊珊老师',3);
CREATE TABLE `tb_class` (
  `cid` INT(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
  `cname` VARCHAR(50) DEFAULT NULL COMMENT '班级名称',
  `teacher1_id` INT(11) DEFAULT NULL COMMENT '授课老师',
  `teacher2_id` INT(11) DEFAULT NULL COMMENT '助理老师',
  `teacher3_id` INT(11) DEFAULT NULL COMMENT '辅导员老师'
);
INSERT  INTO `tb_class`(`cid`,`cname`,`teacher1_id`,`teacher2_id`,`teacher3_id`) VALUES (1,'Java56',1,2,3);
INSERT  INTO `tb_class`(`cid`,`cname`,`teacher1_id`,`teacher2_id`,`teacher3_id`) VALUES (2,'Java78',1,2,3);
INSERT  INTO `tb_class`(`cid`,`cname`,`teacher1_id`,`teacher2_id`,`teacher3_id`) VALUES (3,'Java12',4,5,6);
INSERT  INTO `tb_class`(`cid`,`cname`,`teacher1_id`,`teacher2_id`,`teacher3_id`) VALUES (4,'Java34',4,5,6);

1.2.4 学生数据库

#学生数据库
CREATE DATABASE nacos_ssm_student;
USE nacos_ssm_student;
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');
CREATE TABLE `tb_student` (
  `s_id` INT NOT NULL PRIMARY KEY AUTO_INCREMENT 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` INT DEFAULT NULL,
  `city_ids` VARCHAR(32) DEFAULT NULL COMMENT '城市:320000,321300,321322'
);
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (1,'赵三33',21,'2001-01-17 00:00:00','1',1,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (2,'钱四444',1900,'2001-05-16 00:00:00','1',2,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (3,'孙五56',189,'2022-03-15 00:00:00','0',1,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (4,'张三',20,'2020-12-21 00:00:00','0',2,'320000,321300,321322');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (5,'xxx',18,'2020-12-21 00:00:00','0',2,'140000,140800,140823');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (6,'123',18,'2020-11-01 00:00:00','0',3,'130000,130100,130127');
INSERT  INTO `tb_student`(`s_id`,`sname`,`age`,`birthday`,`gender`,`c_id`,`city_ids`) VALUES (7,'xx',18,'2020-11-02 00:00:00','0',1,'130000,131000,131003');

1.3 后端环境

1.3.1 父项目

  • 步骤:
  • 步骤1:创建项目 nacos-ssm-student
  • 步骤2:添加坐标
  • 步骤1:创建项目

  • 步骤2:添加坐标:
<!-- 1 确定spring boot的版本-->
    <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>
        <mysql.version>5.1.32</mysql.version>
        <pageHelper.starter.version>1.2.5</pageHelper.starter.version>
        <durid.starter.version>1.1.10</durid.starter.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>
        <student.version>1.0-SNAPSHOT</student.version>
    </properties>
    <!-- 3 锁定版本-->
    <dependencyManagement>
        <dependencies>
            <!-- sprig cloud-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud-release.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--nacos -->
            <dependency>
                <groupId>com.alibaba.nacos</groupId>
                <artifactId>nacos-client</artifactId>
                <version>${nacos.version}</version>
            </dependency>
            <!--nacos cloud 发现 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>
            <!--nacos cloud 配置 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
                <version>${alibaba.cloud.version}</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-sentinel -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                <version>${alibaba.cloud.version}</version>
            </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>
            <!--swagger2-->
            <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>
            <!--jwt-->
            <!--JavaBean工具类,用于JavaBean数据封装-->
            <dependency>
                <groupId>commons-beanutils</groupId>
                <artifactId>commons-beanutils</artifactId>
                <version>${beanutils.version}</version>
            </dependency>
            <!--jwt工具-->
            <dependency>
                <groupId>io.jsonwebtoken</groupId>
                <artifactId>jjwt</artifactId>
                <version>${jwt.jjwt.version}</version>
            </dependency>
            <!--joda 时间工具类 -->
            <dependency>
                <groupId>joda-time</groupId>
                <artifactId>joda-time</artifactId>
                <version>${jwt.joda.version}</version>
            </dependency>
            <!-- 自定义项目 -->
            <dependency>
                <groupId>com.czxy</groupId>
                <artifactId>nacos-ssm-student-domain</artifactId>
                <version>${student.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

1.3.2 domain项目

  • 步骤:
  • 步骤1:创建项目:nacos-ssm-student-domain
  • 步骤2:添加pom
  • 步骤3:拷贝vo(BaseResult)
  • 步骤4:拷贝JavaBean
  • 步骤1:创建项目:nacos-ssm-student-domain

  • 步骤2:添加pom
<dependencies>
        <!--jpa-->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>javax.persistence-api</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!--jackson-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-json</artifactId>
        </dependency>
    </dependencies>
  • 步骤3:拷贝vo
package com.czxy.vo;
import lombok.Getter;
import java.util.HashMap;
import java.util.Map;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Getter
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;
    }
}
  • 步骤4:拷贝JavaBean
  • City
package com.czxy.domain;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
/**
 * (TbCity)实体类
 *
 * @author 桐叔
 */
@Table(name = "tb_city")
@Data
public class City implements Serializable {
    private static final long serialVersionUID = 660498290955870873L;
    /**
     * 城市ID
     */
    @Id
    @Column(name = "c_id")
    private String cid;
    /**
     * 城市名称
     */
    @Column(name = "city_name")
    private String cityName;
    /**
     * 父ID
     */
    @Column(name = "parent_id")
    private String parentId;
}
  • Classes
package com.czxy.domain;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Table(name = "tb_class")
@Data
public class Classes {
    @Id
    @Column(name = "cid")
    private Integer cid;
    @Column(name = "cname")
    private String cname;       //班级名称
    @Column(name = "teacher1_id")
    private Integer teacher1Id;       //授课老师
    @Column(name = "teacher2_id")
    private Integer teacher2Id;       //助理老师
    @Column(name = "teacher3_id")
    private Integer teacher3Id;       //辅导员老师
}
  • Course
package com.czxy.domain;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Table(name = "tb_course")
@Data
public class Course {
    @Id
    @Column(name = "c_id")
    private Integer cid;
    @Column(name = "cname")
    private String cname;
    @Column(name = "`desc`")
    private String desc;
}
  • Student
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;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Table(name = "tb_student")
@Data
public class Student {
    @Id
    @Column(name = "s_id")
    private Integer sid;         //学生ID
    @Column(name = "sname")
    private String sname;         //姓名
    @Column(name = "age")
    private Integer age;         //年龄
    @Column(name = "birthday")
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private Date birthday;         //生日
    @Column(name = "gender")
    private String gender;      //性别
    @Column(name = "c_id")
    private Integer cid;         //班级外键
    @Column(name = "city_ids")
    private String cityIds;    //城市
    private List<City> cityList;    //所选城市
    @Transient
    private Classes classes;    //班级对象
    @Transient
    private Integer courseCount;        //选课数
    @Transient
    private List<Course> courseList = new ArrayList<>();    //选课详情
    @Transient
    private List<Integer> courseIds = new ArrayList();      //选课id
}
  • Teacher
package com.czxy.domain;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Table(name = "tb_teacher")
@Data
public class Teacher {
    @Id
    @Column(name = "tid")
    private Integer tid;
    @Column(name = "tname")
    private String tname;       //老师姓名
    @Column(name = "type")
    private Integer type;       //老师类型:1.授课老师、2.助理老师、3.辅导员老师
}
  • User
package com.czxy.domain;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Table(name = "tb_user")
@Data
public class User {
    @Id
    @Column(name = "u_id")
    private String uid;
    @Column(name = "user_name")
    private String userName;
    private String password;
    private Integer gender;
    private String image;
}
/*
CREATE TABLE `tb_user` (
  `u_id` VARCHAR(32) PRIMARY KEY NOT NULL COMMENT '用户编号',
  `user_name` VARCHAR(50) UNIQUE DEFAULT NULL COMMENT '用户名',
  `password` VARCHAR(32) DEFAULT NULL COMMENT '密码',
  `gender` BIT(1) DEFAULT NULL COMMENT '性别,1表示男,0表示女',
  `image` VARCHAR(50) UNIQUE DEFAULT NULL COMMENT '头像图片'
);
 */

1.3.3 网关:10010

  • 步骤:
  • 步骤1:创建项目,nacos-ssm-student-gateway
  • 步骤2:添加坐标
  • 步骤3:配置文件 application.yml
  • 步骤4:拷贝全局跨域配置类 GlobalGatewayCorsConfig
  • 步骤5:启动类 GatewayApplication
  • 步骤1:创建项目,nacos-ssm-student-gateway


  • 步骤2:添加坐标
<dependencies>
        <!-- 网关 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!-- nacos 服务发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--JavaBean工具类,用于JavaBean数据封装-->
        <dependency>
            <groupId>commons-beanutils</groupId>
            <artifactId>commons-beanutils</artifactId>
        </dependency>
        <!--jwt工具-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
        <!--joda 时间工具类 -->
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
    </dependencies>
  • 步骤3:配置文件
#端口号
server:
  port: 10010
spring:
  application:
    name: student-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848   #nacos服务地址
    gateway:
      discovery:
        locator:
          enabled: true               #开启服务注册和发现的功能,自动创建router以服务名开头的请求路径转发到对应的服务
          lowerCaseServiceId: true    #将请求路径上的服务名配置为小写
  • 步骤4:拷贝全局跨域配置类
package com.czxy.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Configuration
public class GlobalGatewayCorsConfig {
    @Bean
    public WebFilter corsFilter2() {
        return (ServerWebExchange ctx, WebFilterChain chain) -> {
            ServerHttpRequest request = ctx.getRequest();
            if (CorsUtils.isCorsRequest(request)) {
                HttpHeaders requestHeaders = request.getHeaders();
                ServerHttpResponse response = ctx.getResponse();
                HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
                HttpHeaders headers = response.getHeaders();
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
                headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
                        requestHeaders.getAccessControlRequestHeaders());
                if (requestMethod != null) {
                    headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
                }
                headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
                headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
                if (request.getMethod() == HttpMethod.OPTIONS) {
                    response.setStatusCode(HttpStatus.OK);
                    return Mono.empty();
                }
            }
            return chain.filter(ctx);
        };
    }
}
  • 步骤5:启动类
package com.czxy;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

1.3.4 学生服务:9000

  • 步骤:
  • 步骤1:创建项目:nacos-ssm-student-service-student
  • 步骤2:添加pom
  • 步骤3:编写yml
  • 步骤4:编写启动类,StudentServiceApplication
  • 步骤5:拷贝 Swagger 配置类 ,Swagger2ConfigurationV3
  • 步骤1:创建项目:nacos-ssm-student-service-student


  • 步骤2:添加pom
<dependencies>
        <!--web起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- nacos 客户端 -->
        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
        </dependency>
        <!-- nacos 服务发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- mybatis启动器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!-- 通用Mapper启动器 -->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
        </dependency>
        <!-- 分页助手启动器 -->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper-spring-boot-starter</artifactId>
        </dependency>
        <!-- mysql驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- Druid连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!--swagger2-->
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
        </dependency>
        <!-- feign 远程调用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- 自定义项目 -->
        <dependency>
            <groupId>com.czxy</groupId>
            <artifactId>nacos-ssm-student-domain</artifactId>
        </dependency>
    </dependencies>
  • 步骤3:编写yml
#端口号
server:
  port: 9000
spring:
  application:
    name: student-service          #服务名
  datasource:
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/nacos_ssm_student?useUnicode=true&characterEncoding=utf8
    username: root
    password: 1234
    druid:    #druid 连接池配置
      initial-size: 1       #初始化连接池大小
      min-idle: 1           #最小连接数
      max-active: 20        #最大连接数
      test-on-borrow: true  #获取连接时候验证,会影响性能
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848   #nacos服务地址
    sentinel:
      transport:
        dashboard: 127.0.0.1:8080
  • 步骤4:编写启动类
package com.czxy.student;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@SpringBootApplication
@EnableDiscoveryClient
public class StudentServiceApplication {
    public static void main(String[] args) {
        SpringApplication.run(StudentServiceApplication.class, args );
    }
}
  • 步骤5:拷贝 Swagger2ConfigurationV3 配置类
package com.czxy.student.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;
    }
}

1.4 前端环境

1.4.1 创建项目

vue create nacos-student-spa

1.4.2 安装axios

cnpm install axios --save

1.4.3 抽取axios

  • 安装依赖
npm i element-ui --save
  • 创建工具src/utils/request.js

import axios from 'axios'
import { MessageBox, Message } from 'element-ui'
// 方式1:设置基本路径
// axios.defaults.baseURL='http://localhost:10010/api'
// 方式2:create an axios instance,并设置基本路径
const service = axios.create({
  baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
  // withCredentials: true, // send cookies when cross-domain requests
  timeout: 5000 // request timeout
})
// request interceptor
service.interceptors.request.use(
  config => {
    // 请求头中追加token
    let token = localStorage.getItem('token')
    if (token) {
      config.headers.Authorization = token
    }
    return config
  },
  error => {
    // do something with request error
    console.log(error) // for debug
    return Promise.reject(error)
  }
)
// response interceptor
service.interceptors.response.use(
  response => {
    const res = response.data
    // if the custom code is not 20000, it is judged as an error.
    if (res.code !== 20000) {
      Message({
        message: res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })
      // ajax异常提示信息 (路径信息,数据)
      console.info(response.config, response.data )
      return Promise.reject(new Error(res.message || 'Error'))
    } else {
      return res
    }
  },
  error => {
    console.log('err' + error) // for debug
    if(error.response.status == 401) {
      MessageBox.confirm(error.response.data, '重新登录确认框', {
        confirmButtonText: '重新登录',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        // 删除token
        localStorage.removeItem('token')
        location.reload()
      })
    } else {
      Message({
        message: error.message,
        type: 'error',
        duration: 5 * 1000
      })
    }
    return Promise.reject(error)
  }
)
export default service
  • 使用工具,创建 src/api/student.js

// 导入工具 request.js
import axios from '@/utils/request.js'
// 编写功能方法
export function condition(studentPage, studentVo) {
    return axios.post(`/student-service/student/condition/${studentPage.pageSize}/${studentPage.pageNum}`, studentVo)
}

1.4.4 启动

npm run serve

1.4.5 访问

http://localhost:8080/

1.4.6 修改入口页面

<template>
  <div>
    <router-link to="/classes_list">班级管理</router-link> | 
    <router-link to="/student_list">学生管理</router-link> | 
    <router-link to="/user_register">注册</router-link> | 
    <router-link to="/user_login">登录</router-link> | 
    <hr>
    <!-- 视图显示区域 -->
    <router-view/>
  </div>
</template>
<script>
export default {
}
</script>
<style>
</style>

1.4.7 优化:拷贝编辑器配置文件

  • 创建文件 .editorconfig
# editorconfig.org
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false

2. 学生管理

2.1 查询所有:后端

2.1.1 需求

  • 查询所有的学生,含条件查询、分页查询

2.1.2 接口

POST http://localhost:10010/student-service/student/condition/3/1
{
  "code": 20000,
  "message": "查询成功",
  "data": {
    "records": [
      {
        "sid": 1,
        "sname": "赵三33",
        "age": 21,
        "birthday": "2001-01-17",
        "gender": "1",
        "cid": 1,
        "cityIds": "320000,321300,321322",
        "cityList": null,
        "classes": null,
        "courseCount": null,
        "courseList": [],
        "courseIds": []
      },
      ...
   ]
}

2.1.3 后端实现

  • 步骤1:拷贝配置类(Swagger配置类)
  • 步骤2:创建条件查询封装类:StudentVo
  • 步骤3:编写Mapper
  • 步骤4:编写service接口、实现类
  • 步骤5:编写controller
  • 步骤6:测试
  • 步骤1:拷贝配置类(Swagger配置类)

  • 步骤2:创建条件查询封装类:StudentVo
package com.czxy.student.vo;
import lombok.Data;
/**
 * @author 桐叔
 * @email liangtong@itcast.cn
 */
@Data
public class StudentVo {
    private String cid;     //班级
    private String sname;       //姓名
    private String startAge;    //开始年龄
    private String endAge;      //结束年龄
}
  • 步骤3:编写Mapper

         
  • 步骤4:编写service
  • 接口

         
  • 实现类

  • 步骤5:编写controller

  • 步骤6:测试
http://localhost:9000/student/condition/3/1
http://localhost:10010/student-service/student/condition/3/1

2.2 查询所欲:前端

2.2.1 查询所有

  • 需求:显示学生列表

  • 步骤:
  • 步骤1:确定访问路径
  • 步骤2:编写路由
  • 步骤3:查询所有
  • 步骤1:确定访问路径

  • 步骤2:编写路由
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
  {
    path: '/student_list',
    name: '学生列表',
    component: () => import('../views/StudentList.vue')
  }
]
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})
export default router
  • 步骤3:查询所有
<template>
  <div>
    <router-link to="/student_add">添加学生</router-link>
    <!-- 查询列表 -->
    <table id="tid" border="1" width="800">
      <tr>
        <td>学生ID</td>
        <td>班级ID</td>
        <td>学生姓名</td>
        <td>年龄</td>
        <td>生日</td>
        <td>性别</td>
        <td>操作</td>
      </tr>
      <tr v-for="(student,index) in pageInfo.list" :key="index">
        <td>{{student.sid}}</td>
        <td>{{student.cid}}</td>
        <td>{{student.sname}}</td>
        <td>{{student.age}}</td>
        <td>{{student.birthday}}</td>
        <td>{{student.gender == 1 ? "男" : "女"}}</td>
        <td>
          <a>修改</a>
          <a>删除</a>
        </td>
      </tr>
    </table>
  </div>
</template>
<script>
import {condition} from '@/api/student.js'
export default {
  data() {
    return {
      pageInfo: {       //分页对象
        pageSize: 2,
        pageNum: 1
      },
      studentVo: {          //条件表单对象
        cid: ''
      },
    }
  },
  mounted() {
    // 查询所有
    this.conditionFn()
  },
  methods: {
    async conditionFn() {
        let { data } = await condition(this.pageInfo,this.studentVo)
        console.info(data)
        this.pageInfo = data
    },
  },
}
</script>
<style>
</style>

2.2.2 条件所有

  • 需求:

  • 步骤
  • 步骤1:添加条件查询表单
  • 步骤2:完善 conditionFn 函数
  • 步骤1:添加条件查询表单
<!-- 查询条件 -->
    <table>
      <tr>
        <td>班级</td>
        <td>
          <select v-model="studentVo.cid">
            <option value="">--选择班级--</option>
            <option value="1">Java12班</option>
            <option value="2">Java34班</option>
            <option value="3">Java56班</option>
          </select>
        </td>
        <td>姓名:</td>
        <td>
          <input type="text" placeholder="请输入姓名" v-model="studentVo.sname" size="10">
        </td>
        <td>年龄:</td>
        <td>
          <input type="text" placeholder="请输入开始年龄" v-model="studentVo.startAge" size="10">
          --
          <input type="text" placeholder="请输入结束年龄" v-model="studentVo.endAge" size="10">
        </td>
        <td><input type="button" value="查询" @click="conditionFn(1)"></td>
      </tr>
    </table>
  • 步骤2:完善 conditionFn 函数
async conditionFn(pageNum) {
        if(pageNum) {
            this.pageInfo.pageNum = pageNum
        }
        let { data } = await condition(this.pageInfo,this.studentVo)
        console.info(data)
        this.pageInfo = data
    },

2.2.3 分页所有

  • 需求:

  • 步骤
  • 步骤1:添加分页信息
  • 步骤2:编写跳转函数
  • 步骤1:添加分页信息
<!-- 分页条 -->
    <div id="pageId">
      每页
      <select v-model="pageInfo.pageSize" @change="conditionFn(1)">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="5">5</option>
        <option value="10">10</option>
      </select>条,
      <a href="#" v-for="index in pageInfo.pages" :key="index" @click.prevent="conditionFn(index)" >{{index}}</a>
      ,跳转到第 <input type="text" v-model="pageInfo.pageNum" size="5" @keydown.enter="go" />页
    </div>
  • 步骤2:编写跳转函数
go() {
      if(parseInt(this.pageInfo.pageNum) == this.pageInfo.pageNum) {
        this.conditionFn()
      }
    },


相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4天前
|
消息中间件 Java RocketMQ
Spring Cloud RocketMQ:构建可靠消息驱动的微服务架构
【4月更文挑战第28天】消息队列在微服务架构中扮演着至关重要的角色,能够实现服务之间的解耦、异步通信以及数据分发。Spring Cloud RocketMQ作为Apache RocketMQ的Spring Cloud集成,为微服务架构提供了可靠的消息传输机制。
16 1
|
7天前
|
Java 数据安全/隐私保护 Sentinel
微服务学习 | Spring Cloud 中使用 Sentinel 实现服务限流
微服务学习 | Spring Cloud 中使用 Sentinel 实现服务限流
|
7天前
|
运维 监控 Java
SpringCloud&认识微服务
SpringCloud&认识微服务
11 0
|
14天前
|
人工智能 监控 安全
Java+Spring Cloud +Vue+UniApp微服务智慧工地云平台源码
视频监控系统、人员实名制与分账制管理系统、车辆管理系统、环境监测系统、大型设备监测(龙门吊、塔吊、升降机、卸料平台等)、用电监测系统、基坑监测系统、AI算法分析(安全帽佩戴、火焰识别、周界报警、人员聚众报警、升降机超载报警)、安全培训、设备监测。
20 4
|
15天前
|
负载均衡 Java 开发者
细解微服务架构实践:如何使用Spring Cloud进行Java微服务治理
【4月更文挑战第17天】Spring Cloud是Java微服务治理的首选框架,整合了Eureka(服务发现)、Ribbon(客户端负载均衡)、Hystrix(熔断器)、Zuul(API网关)和Config Server(配置中心)。通过Eureka实现服务注册与发现,Ribbon提供负载均衡,Hystrix实现熔断保护,Zuul作为API网关,Config Server集中管理配置。理解并运用Spring Cloud进行微服务治理是现代Java开发者的关键技能。
|
18天前
|
人工智能 监控 安全
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
Springcloud数字化物联网智慧工地综合平台源码 劳务管理、设备管理、绿色施工
31 3
|
24天前
|
SpringCloudAlibaba Java 数据库
SpringCloud Alibaba微服务 -- Seata的原理和使用
SpringCloud Alibaba微服务 -- Seata的原理和使用
|
24天前
|
SpringCloudAlibaba 监控 Java
SpringCloud Alibaba微服务-- Sentinel的使用(保姆级)
SpringCloud Alibaba微服务-- Sentinel的使用(保姆级)
|
24天前
|
SpringCloudAlibaba Java API
SpringCloud Alibaba微服务工程搭建(保姆级)
SpringCloud Alibaba微服务工程搭建(保姆级)
|
24天前
|
SpringCloudAlibaba Java Nacos
SpringCloud Alibaba微服务 -- Nacos使用以及注册中心和配置中心的应用(保姆级)
SpringCloud Alibaba微服务 -- Nacos使用以及注册中心和配置中心的应用(保姆级)